diff options
author | jstebbins <[email protected]> | 2012-11-12 08:22:07 +0000 |
---|---|---|
committer | jstebbins <[email protected]> | 2012-11-12 08:22:07 +0000 |
commit | ab5445d6f279a3477c08f069ff3329b696cb9ac8 (patch) | |
tree | 28b1f1aa52db4f2f0d35a35950f6486955703426 /libhb | |
parent | cf1f034f914348d0f0bfcd5f8902f0a3fb519273 (diff) |
Improve management of titles and jobs
Cleans up several several unavoidable memory leaks caused by old api.
Clearly separates titles from jobs. Titles are set during scan and
never modified now.
Since titles are immutable, this lead to API some changes. For example,
We were setting chapter names in the title from the front ends. Now
these get set in the job.
These new APIs allow us to start moving away from our use of title->job.
Eventually, I would like to eliminate title->job completely, but the
mac ui is too tightly tied to using this field to allow removing it
at this time. So there is temporarily a convenience function used
only by the mac ui that allows it to continue using title->job and also
use the new APIs.
New APIs:
typedef struct hb_title_set_s hb_title_set_t;
struct hb_title_set_s
{
hb_list_t * list_title;
int feature; // Detected DVD feature title
};
hb_title_set_t * hb_get_title_set( hb_handle_t * );
This is just something I added to clean up how "feature title" info
is passed.
hb_job_t * hb_job_init( hb_title_t * title );
Initializes a new job with default settings from the title.
hb_job_t * hb_job_init_by_index( hb_handle_t *h, int title_index );
Same as hb_job_init(). For use by win Interop lib.
void hb_job_reset( hb_job_t * job );
Convenience function for the MacUi.
Clears audio, subtitle, and filter lists. The macui still uses
title->job because it is so intricately tied to it. So I created
this convenience function that it can call after adding a job.
void hb_job_close( hb_job_t ** job );
Releases the job an all resources it contains.
void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts );
Makes a copy of "advanced_opts" and stores in job.
Freed by hb_job_close().
void hb_job_set_file( hb_job_t *job, const char *file );
Makes a copy of "file" and stores in job.
Freed by hb_job_close().
void hb_chapter_set_title(hb_chapter_t *chapter, const char *title);
Makes a copy of "title" and stores in chapter.
Freed by hb_chapter_close().
Recommended usage (cli and lingui are updated to do this):
job = hb_job_init( title );
// set job settings ...
hb_add(h, job);
hb_job_close( &job );
I have also added new APIs for managing metadata. These are
used to add metadata to a job.
void hb_metadata_set_name( hb_metadata_t *metadata, const char *name );
void hb_metadata_set_artist( hb_metadata_t *metadata, const char *artist );
void hb_metadata_set_composer( hb_metadata_t *metadata, const char *composer );
void hb_metadata_set_release_date( hb_metadata_t *metadata, const char *release_date );
void hb_metadata_set_comment( hb_metadata_t *metadata, const char *comment );
void hb_metadata_set_genre( hb_metadata_t *metadata, const char *genre );
void hb_metadata_set_album( hb_metadata_t *metadata, const char *album );
void hb_metadata_set_coverart( hb_metadata_t *metadata, const uint8_t *coverart, int size );
Example:
job = hb_job_init( &job );
// set job settings ...
hb_metadata_set_artist( job->metadata, "Danny Elfman" );
hb_add(h, job);
hb_job_close( &job );
Some APIs have changed in order to avoid using title incorrectly and
use the new hb_title_set_t.
-void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title );
+void hb_autopassthru_apply_settings( hb_job_t * job );
-void hb_get_preview( hb_handle_t *, hb_title_t *, int, uint8_t * );
+void hb_get_preview( hb_handle_t *, hb_job_t *, int, uint8_t * );
hb_thread_t * hb_scan_init( hb_handle_t *, volatile int * die,
const char * path, int title_index,
- hb_list_t * list_title, int preview_count,
+ hb_title_set_t * title_set, int preview_count,
int store_previews, uint64_t min_duration );
These APIs have been removed. Win Interop will need some changes.
I think what I've provided will be suffecient, but let me know if it's not.
-void hb_get_preview_by_index( hb_handle_t *, int, int, uint8_t * );
-void hb_set_anamorphic_size_by_index( hb_handle_t *, int,
- int *output_width, int *output_height,
- int *output_par_width, int *output_par_height );
git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@5058 b64f7644-9d1e-0410-96f1-a4d463321fa5
Diffstat (limited to 'libhb')
-rw-r--r-- | libhb/bd.c | 4 | ||||
-rw-r--r-- | libhb/common.c | 742 | ||||
-rw-r--r-- | libhb/common.h | 101 | ||||
-rw-r--r-- | libhb/decavcodec.c | 2 | ||||
-rw-r--r-- | libhb/decmetadata.c | 114 | ||||
-rw-r--r-- | libhb/decmpeg2.c | 8 | ||||
-rw-r--r-- | libhb/decsrtsub.c | 5 | ||||
-rw-r--r-- | libhb/dvd.c | 4 | ||||
-rw-r--r-- | libhb/dvdnav.c | 4 | ||||
-rw-r--r-- | libhb/hb.c | 326 | ||||
-rw-r--r-- | libhb/hb.h | 18 | ||||
-rw-r--r-- | libhb/internal.h | 4 | ||||
-rw-r--r-- | libhb/muxcommon.c | 9 | ||||
-rw-r--r-- | libhb/muxmkv.c | 72 | ||||
-rw-r--r-- | libhb/muxmp4.c | 73 | ||||
-rw-r--r-- | libhb/reader.c | 20 | ||||
-rw-r--r-- | libhb/rendersub.c | 6 | ||||
-rw-r--r-- | libhb/scan.c | 104 | ||||
-rw-r--r-- | libhb/stream.c | 100 | ||||
-rw-r--r-- | libhb/sync.c | 7 | ||||
-rw-r--r-- | libhb/work.c | 113 |
21 files changed, 1253 insertions, 583 deletions
diff --git a/libhb/bd.c b/libhb/bd.c index 208782674..268cdaab0 100644 --- a/libhb/bd.c +++ b/libhb/bd.c @@ -491,10 +491,12 @@ hb_title_t * hb_bd_title_scan( hb_bd_t * d, int tt, uint64_t min_duration ) /* Chapters */ for ( ii = 0; ii < ti->chapter_count; ii++ ) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); chapter->index = ii + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); chapter->duration = ti->chapters[ii].duration; chapter->block_start = ti->chapters[ii].offset; diff --git a/libhb/common.c b/libhb/common.c index 821f17e76..80b526c2a 100644 --- a/libhb/common.c +++ b/libhb/common.c @@ -306,13 +306,13 @@ const char* hb_mixdown_get_short_name_from_mixdown(int amixdown) return ""; } -void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ) +void hb_autopassthru_apply_settings( hb_job_t * job ) { int i, j, already_printed; hb_audio_t * audio; - for( i = 0, already_printed = 0; i < hb_list_count( title->list_audio ); ) + for( i = 0, already_printed = 0; i < hb_list_count( job->list_audio ); ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( audio->config.out.codec == HB_ACODEC_AUTO_PASS ) { if( !already_printed ) @@ -327,8 +327,8 @@ void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ) { hb_log( "Auto Passthru: passthru not possible and no valid fallback specified, dropping track %d", audio->config.out.track ); - hb_list_rem( title->list_audio, audio ); - free( audio ); + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); continue; } audio->config.out.samplerate = audio->config.in.samplerate; @@ -1157,7 +1157,7 @@ hb_list_t * hb_list_init() ********************************************************************** * Returns the number of items currently in the list *********************************************************************/ -int hb_list_count( hb_list_t * l ) +int hb_list_count( const hb_list_t * l ) { return l->items_count; } @@ -1252,7 +1252,7 @@ void hb_list_rem( hb_list_t * l, void * p ) * Returns item at position i, or NULL if there are not that many * items in the list *********************************************************************/ -void * hb_list_item( hb_list_t * l, int i ) +void * hb_list_item( const hb_list_t * l, int i ) { if( i < 0 || i >= l->items_count ) { @@ -1575,6 +1575,19 @@ void hb_register_error_handler( hb_error_handler_t * handler ) error_handler = handler; } +static void hb_update_str( char **dst, const char *src ) +{ + if ( dst ) + { + free( *dst ); + *dst = NULL; + if ( src ) + { + *dst = strdup( src ); + } + } +} + /********************************************************************** * hb_title_init ********************************************************************** @@ -1592,6 +1605,7 @@ hb_title_t * hb_title_init( char * path, int index ) t->list_chapter = hb_list_init(); t->list_subtitle = hb_list_init(); t->list_attachment = hb_list_init(); + t->metadata = hb_metadata_init(); strcat( t->path, path ); // default to decoding mpeg2 t->video_id = 0xE0; @@ -1616,65 +1630,252 @@ void hb_title_close( hb_title_t ** _t ) hb_subtitle_t * subtitle; hb_attachment_t * attachment; - while( ( audio = hb_list_item( t->list_audio, 0 ) ) ) - { - hb_list_rem( t->list_audio, audio ); - free( audio ); - } - hb_list_close( &t->list_audio ); - while( ( chapter = hb_list_item( t->list_chapter, 0 ) ) ) { hb_list_rem( t->list_chapter, chapter ); - free( chapter ); + hb_chapter_close( &chapter ); } hb_list_close( &t->list_chapter ); + while( ( audio = hb_list_item( t->list_audio, 0 ) ) ) + { + hb_list_rem( t->list_audio, audio ); + hb_audio_close( &audio ); + } + hb_list_close( &t->list_audio ); + while( ( subtitle = hb_list_item( t->list_subtitle, 0 ) ) ) { hb_list_rem( t->list_subtitle, subtitle ); - if ( subtitle->extradata ) - { - free( subtitle->extradata ); - subtitle->extradata = NULL; - } - free( subtitle ); + hb_subtitle_close( &subtitle ); } hb_list_close( &t->list_subtitle ); while( ( attachment = hb_list_item( t->list_attachment, 0 ) ) ) { hb_list_rem( t->list_attachment, attachment ); - if ( attachment->name ) + hb_attachment_close( &attachment ); + } + hb_list_close( &t->list_attachment ); + + hb_metadata_close( &t->metadata ); + + free( t->video_codec_name ); + free(t->container_name); + +#if defined(HB_TITLE_JOBS) + hb_job_close( &t->job ); +#endif + + free( t ); + *_t = NULL; +} + +/* + * Create a pristine job structure from a title + * title_index is 1 based + */ +hb_job_t * hb_job_init_by_index( hb_handle_t * h, int title_index ) +{ + hb_title_set_t *title_set = hb_get_title_set( h ); + hb_title_t * title = hb_list_item( title_set->list_title, + title_index - 1 ); + return hb_job_init( title ); +} + +hb_job_t * hb_job_init( hb_title_t * title ) +{ + hb_job_t * job; + + if ( title == NULL ) + return NULL; + + job = calloc( sizeof( hb_job_t ), 1 ); + + job->title = title; + + /* Set defaults settings */ + job->chapter_start = 1; + job->chapter_end = hb_list_count( title->list_chapter ); + job->list_chapter = hb_chapter_list_copy( title->list_chapter ); + + /* Autocrop by default. Gnark gnark */ + memcpy( job->crop, title->crop, 4 * sizeof( int ) ); + + /* Preserve a source's pixel aspect, if it's available. */ + if( title->pixel_aspect_width && title->pixel_aspect_height ) + { + job->anamorphic.par_width = title->pixel_aspect_width; + job->anamorphic.par_height = title->pixel_aspect_height; + } + + if( title->aspect != 0 && title->aspect != 1. && + !job->anamorphic.par_width && !job->anamorphic.par_height) + { + hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height, + (int)(title->aspect * title->height + 0.5), title->width ); + } + + job->width = title->width - job->crop[2] - job->crop[3]; + hb_fix_aspect( job, HB_KEEP_WIDTH ); + if( job->height > title->height - job->crop[0] - job->crop[1] ) + { + job->height = title->height - job->crop[0] - job->crop[1]; + hb_fix_aspect( job, HB_KEEP_HEIGHT ); + } + + job->keep_ratio = 1; + + job->vcodec = HB_VCODEC_FFMPEG_MPEG4; + job->vquality = -1.0; + job->vbitrate = 1000; + job->pass = 0; + job->vrate = title->rate; + job->vrate_base = title->rate_base; + + job->mux = HB_MUX_MP4; + + job->list_audio = hb_list_init(); + job->list_subtitle = hb_list_init(); + job->list_filter = hb_list_init(); + + job->list_attachment = hb_attachment_list_copy( title->list_attachment ); + job->metadata = hb_metadata_copy( title->metadata ); + + return job; +} + +/** + * Clean up the job structure so that is is ready for setting up a new job. + * Should be called by front-ends after hb_add(). + */ +/********************************************************************** + * hb_job_reset + ********************************************************************** + * + *********************************************************************/ +void hb_job_reset( hb_job_t * job ) +{ + if ( job ) + { + hb_audio_t *audio; + hb_subtitle_t *subtitle; + hb_filter_object_t *filter; + hb_title_t * title = job->title; + + // clean up audio list + while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) + { + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); + } + + // clean up subtitle list + while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) { - free( attachment->name ); - attachment->name = NULL; + hb_list_rem( job->list_subtitle, subtitle ); + hb_subtitle_close( &subtitle ); } - if ( attachment->data ) + + // clean up filter list + while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) { - free( attachment->data ); - attachment->data = NULL; + hb_list_rem( job->list_filter, filter ); + hb_filter_close( &filter ); } - free( attachment ); + + hb_metadata_close( &job->metadata ); + job->metadata = hb_metadata_copy( title->metadata ); } - hb_list_close( &t->list_attachment ); +} - if( t->metadata ) +/********************************************************************** + * hb_job_close + ********************************************************************** + * + *********************************************************************/ +void hb_job_close( hb_job_t ** _j ) +{ + if (_j) { - if( t->metadata->coverart ) + hb_job_t * job = *_j; + + if (job) { - free( t->metadata->coverart ); + hb_chapter_t *chapter; + hb_audio_t *audio; + hb_subtitle_t *subtitle; + hb_filter_object_t *filter; + hb_attachment_t *attachment; + + free(job->file); + free(job->advanced_opts); + + // clean up chapter list + while( ( chapter = hb_list_item( job->list_chapter, 0 ) ) ) + { + hb_list_rem( job->list_chapter, chapter ); + hb_chapter_close( &chapter ); + } + hb_list_close( &job->list_chapter ); + + // clean up audio list + while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) + { + hb_list_rem( job->list_audio, audio ); + hb_audio_close( &audio ); + } + hb_list_close( &job->list_audio ); + + // clean up subtitle list + while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) + { + hb_list_rem( job->list_subtitle, subtitle ); + hb_subtitle_close( &subtitle ); + } + hb_list_close( &job->list_subtitle ); + + // clean up filter list + while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) + { + hb_list_rem( job->list_filter, filter ); + hb_filter_close( &filter ); + } + hb_list_close( &job->list_filter ); + + // clean up attachment list + while( ( attachment = hb_list_item( job->list_attachment, 0 ) ) ) + { + hb_list_rem( job->list_attachment, attachment ); + hb_attachment_close( &attachment ); + } + hb_list_close( &job->list_attachment ); + + // clean up metadata + if ( job->metadata ) + { + hb_metadata_close( &job->metadata ); + } + free( job ); } - free( t->metadata ); + _j = NULL; } +} - if ( t->video_codec_name ) +void hb_job_set_file( hb_job_t *job, const char *file ) +{ + if ( job ) { - free( t->video_codec_name ); + hb_update_str( &job->file, file ); } +} - free( t ); - *_t = NULL; +void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts ) +{ + if ( job ) + { + hb_update_str( &job->advanced_opts, advanced_opts ); + } } hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ) @@ -1689,6 +1890,30 @@ hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ) return filter_copy; } +/********************************************************************** + * hb_filter_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_filter_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_filter_object_t *filter = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( filter = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_filter_copy(filter) ); + } + } + } + return list; +} + /** * Gets a filter object with the given type * @param filter_id The type of filter to get. @@ -1759,6 +1984,93 @@ void hb_filter_close( hb_filter_object_t ** _f ) } /********************************************************************** + * hb_chapter_copy + ********************************************************************** + * + *********************************************************************/ +hb_chapter_t *hb_chapter_copy(const hb_chapter_t *src) +{ + hb_chapter_t *chap = NULL; + + if ( src ) + { + chap = calloc( 1, sizeof(*chap) ); + memcpy( chap, src, sizeof(*chap) ); + if ( src->title ) + { + chap->title = strdup( src->title ); + } + } + return chap; +} + +/********************************************************************** + * hb_chapter_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_chapter_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_chapter_t *chapter = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( chapter = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_chapter_copy(chapter) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_chapter_close + ********************************************************************** + * + *********************************************************************/ +void hb_chapter_close(hb_chapter_t **chap) +{ + if ( chap && *chap ) + { + free((*chap)->title); + free(*chap); + *chap = NULL; + } +} + +/********************************************************************** + * hb_chapter_set_title + ********************************************************************** + * + *********************************************************************/ +void hb_chapter_set_title( hb_chapter_t *chapter, const char *title ) +{ + if ( chapter ) + { + hb_update_str( &chapter->title, title ); + } +} + +/********************************************************************** + * hb_chapter_set_title_by_index + ********************************************************************** + * Applies information from the given job to the official job instance. + * @param job Handle to hb_job_t. + * @param chapter The chapter to apply the name to (1-based). + * @param titel to apply. + *********************************************************************/ +void hb_chapter_set_title_by_index( hb_job_t * job, int chapter_index, const char * title ) +{ + hb_chapter_t * chapter = hb_list_item( job->list_chapter, chapter_index - 1 ); + hb_chapter_set_title( chapter, title ); +} + +/********************************************************************** * hb_audio_copy ********************************************************************** * @@ -1771,11 +2083,54 @@ hb_audio_t *hb_audio_copy(const hb_audio_t *src) { audio = calloc(1, sizeof(*audio)); memcpy(audio, src, sizeof(*audio)); + if ( src->config.out.name ) + { + audio->config.out.name = strdup(src->config.out.name); + } } return audio; } /********************************************************************** + * hb_audio_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_audio_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_audio_t *audio = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( audio = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_audio_copy(audio) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_audio_close + ********************************************************************** + * + *********************************************************************/ +void hb_audio_close( hb_audio_t **audio ) +{ + if ( audio && *audio ) + { + free((*audio)->config.out.name); + free(*audio); + *audio = NULL; + } +} + +/********************************************************************** * hb_audio_new ********************************************************************** * @@ -1878,7 +2233,7 @@ int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg) } if (audiocfg->out.name && *audiocfg->out.name) { - audio->config.out.name = audiocfg->out.name; + audio->config.out.name = strdup(audiocfg->out.name); } hb_list_add(job->list_audio, audio); @@ -1918,6 +2273,45 @@ hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src) } /********************************************************************** + * hb_subtitle_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_subtitle_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_subtitle_t *subtitle = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( subtitle = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_subtitle_copy(subtitle) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_subtitle_close + ********************************************************************** + * + *********************************************************************/ +void hb_subtitle_close( hb_subtitle_t **sub ) +{ + if ( sub && *sub ) + { + free ((*sub)->extradata); + free(*sub); + *sub = NULL; + } +} + +/********************************************************************** * hb_subtitle_add ********************************************************************** * @@ -2026,6 +2420,238 @@ int hb_subtitle_can_pass( int source, int mux ) } } +/********************************************************************** + * hb_metadata_init + ********************************************************************** + * + *********************************************************************/ +hb_metadata_t *hb_metadata_init() +{ + hb_metadata_t *metadata = calloc( 1, sizeof(*metadata) ); + return metadata; +} + +/********************************************************************** + * hb_metadata_copy + ********************************************************************** + * + *********************************************************************/ +hb_metadata_t *hb_metadata_copy( const hb_metadata_t *src ) +{ + hb_metadata_t *metadata = NULL; + + if ( src ) + { + metadata = calloc( 1, sizeof(*metadata) ); + if ( src->name ) + { + metadata->name = strdup(src->name); + } + if ( src->artist ) + { + metadata->artist = strdup(src->artist); + } + if ( src->album_artist ) + { + metadata->album_artist = strdup(src->album_artist); + } + if ( src->composer ) + { + metadata->composer = strdup(src->composer); + } + if ( src->release_date ) + { + metadata->release_date = strdup(src->release_date); + } + if ( src->comment ) + { + metadata->comment = strdup(src->comment); + } + if ( src->album ) + { + metadata->album = strdup(src->album); + } + if ( src->genre ) + { + metadata->genre = strdup(src->genre); + } + if ( src->description ) + { + metadata->description = strdup(src->description); + } + if ( src->long_description ) + { + metadata->long_description = strdup(src->long_description); + } + if ( src->list_coverart ) + { + int ii; + for ( ii = 0; ii < hb_list_count( src->list_coverart ); ii++ ) + { + hb_coverart_t *art = hb_list_item( src->list_coverart, ii ); + hb_metadata_add_coverart( + metadata, art->data, art->size, art->type ); + } + } + } + return metadata; +} + +/********************************************************************** + * hb_metadata_close + ********************************************************************** + * + *********************************************************************/ +void hb_metadata_close( hb_metadata_t **_m ) +{ + if ( _m && *_m ) + { + hb_metadata_t *m = *_m; + hb_coverart_t *art; + + free( m->name ); + free( m->artist ); + free( m->composer ); + free( m->release_date ); + free( m->comment ); + free( m->album ); + free( m->album_artist ); + free( m->genre ); + free( m->description ); + free( m->long_description ); + + if ( m->list_coverart ) + { + while( ( art = hb_list_item( m->list_coverart, 0 ) ) ) + { + hb_list_rem( m->list_coverart, art ); + free( art->data ); + free( art ); + } + hb_list_close( &m->list_coverart ); + } + + free( m ); + *_m = NULL; + } +} + +/********************************************************************** + * hb_metadata_set_* + ********************************************************************** + * + *********************************************************************/ +void hb_metadata_set_name( hb_metadata_t *metadata, const char *name ) +{ + if ( metadata ) + { + hb_update_str( &metadata->name, name ); + } +} + +void hb_metadata_set_artist( hb_metadata_t *metadata, const char *artist ) +{ + if ( metadata ) + { + hb_update_str( &metadata->artist, artist ); + } +} + +void hb_metadata_set_composer( hb_metadata_t *metadata, const char *composer ) +{ + if ( metadata ) + { + hb_update_str( &metadata->composer, composer ); + } +} + +void hb_metadata_set_release_date( hb_metadata_t *metadata, const char *release_date ) +{ + if ( metadata ) + { + hb_update_str( &metadata->release_date, release_date ); + } +} + +void hb_metadata_set_comment( hb_metadata_t *metadata, const char *comment ) +{ + if ( metadata ) + { + hb_update_str( &metadata->comment, comment ); + } +} + +void hb_metadata_set_genre( hb_metadata_t *metadata, const char *genre ) +{ + if ( metadata ) + { + hb_update_str( &metadata->genre, genre ); + } +} + +void hb_metadata_set_album( hb_metadata_t *metadata, const char *album ) +{ + if ( metadata ) + { + hb_update_str( &metadata->album, album ); + } +} + +void hb_metadata_set_album_artist( hb_metadata_t *metadata, const char *album_artist ) +{ + if ( metadata ) + { + hb_update_str( &metadata->album_artist, album_artist ); + } +} + +void hb_metadata_set_description( hb_metadata_t *metadata, const char *description ) +{ + if ( metadata ) + { + hb_update_str( &metadata->description, description ); + } +} + +void hb_metadata_set_long_description( hb_metadata_t *metadata, const char *long_description ) +{ + if ( metadata ) + { + hb_update_str( &metadata->long_description, long_description ); + } +} + +void hb_metadata_add_coverart( hb_metadata_t *metadata, const uint8_t *data, int size, int type ) +{ + if ( metadata ) + { + if ( metadata->list_coverart == NULL ) + { + metadata->list_coverart = hb_list_init(); + } + hb_coverart_t *art = calloc( 1, sizeof(hb_coverart_t) ); + art->data = malloc( size ); + memcpy( art->data, data, size ); + art->size = size; + art->type = type; + hb_list_add( metadata->list_coverart, art ); + } +} + +void hb_metadata_rem_coverart( hb_metadata_t *metadata, int idx ) +{ + if ( metadata ) + { + hb_coverart_t *art = hb_list_item( metadata->list_coverart, idx ); + if ( art ) + { + hb_list_rem( metadata->list_coverart, art ); + free( art->data ); + free( art ); + } + } +} + char * hb_strdup_printf( const char * fmt, ... ) { int len; @@ -2119,6 +2745,46 @@ hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src) } /********************************************************************** + * hb_attachment_list_copy + ********************************************************************** + * + *********************************************************************/ +hb_list_t *hb_attachment_list_copy(const hb_list_t *src) +{ + hb_list_t *list = hb_list_init(); + hb_attachment_t *attachment = NULL; + int i; + + if( src ) + { + for( i = 0; i < hb_list_count(src); i++ ) + { + if( ( attachment = hb_list_item( src, i ) ) ) + { + hb_list_add( list, hb_attachment_copy(attachment) ); + } + } + } + return list; +} + +/********************************************************************** + * hb_attachment_close + ********************************************************************** + * + *********************************************************************/ +void hb_attachment_close( hb_attachment_t **attachment ) +{ + if ( attachment && *attachment ) + { + free((*attachment)->data); + free((*attachment)->name); + free(*attachment); + *attachment = NULL; + } +} + +/********************************************************************** * hb_yuv2rgb ********************************************************************** * Converts a YCrCb pixel to an RGB pixel. diff --git a/libhb/common.h b/libhb/common.h index f7cc6dfef..41711e954 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -73,6 +73,7 @@ typedef struct hb_rate_s hb_rate_t; typedef struct hb_mixdown_s hb_mixdown_t; typedef struct hb_encoder_s hb_encoder_t; typedef struct hb_job_s hb_job_t; +typedef struct hb_title_set_s hb_title_set_t; typedef struct hb_title_s hb_title_t; typedef struct hb_chapter_s hb_chapter_t; typedef struct hb_audio_s hb_audio_t; @@ -81,6 +82,7 @@ typedef struct hb_subtitle_s hb_subtitle_t; typedef struct hb_subtitle_config_s hb_subtitle_config_t; typedef struct hb_attachment_s hb_attachment_t; typedef struct hb_metadata_s hb_metadata_t; +typedef struct hb_coverart_s hb_coverart_t; typedef struct hb_state_s hb_state_t; typedef union hb_esconfig_u hb_esconfig_t; typedef struct hb_work_private_s hb_work_private_t; @@ -102,11 +104,11 @@ typedef struct hb_lock_s hb_lock_t; #include "libavutil/audioconvert.h" hb_list_t * hb_list_init(); -int hb_list_count( hb_list_t * ); +int hb_list_count( const hb_list_t * ); void hb_list_add( hb_list_t *, void * ); void hb_list_insert( hb_list_t * l, int pos, void * p ); void hb_list_rem( hb_list_t *, void * ); -void * hb_list_item( hb_list_t *, int ); +void * hb_list_item( const hb_list_t *, int ); void hb_list_close( hb_list_t ** ); void hb_reduce( int *x, int *y, int num, int den ); @@ -117,12 +119,19 @@ void hb_limit_rational64( int64_t *x, int64_t *y, int64_t num, int64_t den, int6 #define HB_KEEP_HEIGHT 1 void hb_fix_aspect( hb_job_t * job, int keep ); +void hb_job_set_advanced_opts( hb_job_t *job, const char *advanced_opts ); +void hb_job_set_file( hb_job_t *job, const char *file ); + hb_audio_t *hb_audio_copy(const hb_audio_t *src); +hb_list_t *hb_audio_list_copy(const hb_list_t *src); +void hb_audio_close(hb_audio_t **audio); void hb_audio_config_init(hb_audio_config_t * audiocfg); int hb_audio_add(const hb_job_t * job, const hb_audio_config_t * audiocfg); hb_audio_config_t * hb_list_audio_config_item(hb_list_t * list, int i); hb_subtitle_t *hb_subtitle_copy(const hb_subtitle_t *src); +hb_list_t *hb_subtitle_list_copy(const hb_list_t *src); +void hb_subtitle_close( hb_subtitle_t **sub ); int hb_subtitle_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg, int track); int hb_srt_add(const hb_job_t * job, const hb_subtitle_config_t * subtitlecfg, const char *lang); @@ -131,6 +140,29 @@ int hb_subtitle_can_burn( int source ); int hb_subtitle_can_pass( int source, int mux ); hb_attachment_t *hb_attachment_copy(const hb_attachment_t *src); +hb_list_t *hb_attachment_list_copy(const hb_list_t *src); +void hb_attachment_close(hb_attachment_t **attachment); + +hb_metadata_t * hb_metadata_init(); +hb_metadata_t * hb_metadata_copy(const hb_metadata_t *src); +void hb_metadata_close(hb_metadata_t **metadata); +void hb_metadata_set_name( hb_metadata_t *metadata, const char *name ); +void hb_metadata_set_artist( hb_metadata_t *metadata, const char *artist ); +void hb_metadata_set_composer( hb_metadata_t *metadata, const char *composer ); +void hb_metadata_set_release_date( hb_metadata_t *metadata, const char *release_date ); +void hb_metadata_set_comment( hb_metadata_t *metadata, const char *comment ); +void hb_metadata_set_genre( hb_metadata_t *metadata, const char *genre ); +void hb_metadata_set_album( hb_metadata_t *metadata, const char *album ); +void hb_metadata_set_album_artist( hb_metadata_t *metadata, const char *album_artist ); +void hb_metadata_set_description( hb_metadata_t *metadata, const char *description ); +void hb_metadata_set_long_description( hb_metadata_t *metadata, const char *long_description ); +void hb_metadata_add_coverart( hb_metadata_t *metadata, const uint8_t *data, int size, int type ); +void hb_metadata_rem_coverart( hb_metadata_t *metadata, int ii ); + +hb_chapter_t *hb_chapter_copy(const hb_chapter_t *src); +hb_list_t *hb_chapter_list_copy(const hb_list_t *src); +void hb_chapter_close(hb_chapter_t **chapter); +void hb_chapter_set_title(hb_chapter_t *chapter, const char *title); struct hb_rate_s { @@ -205,7 +237,9 @@ int hb_mixdown_get_low_freq_channel_count(int amixdown); int hb_mixdown_get_mixdown_from_short_name(const char *short_name); const char* hb_mixdown_get_short_name_from_mixdown(int amixdown); -void hb_autopassthru_apply_settings( hb_job_t * job, hb_title_t * title ); +int hb_mixdown_get_mixdown_from_short_name( const char * short_name ); +const char * hb_mixdown_get_short_name_from_mixdown( int amixdown ); +void hb_autopassthru_apply_settings( hb_job_t * job ); void hb_autopassthru_print_settings( hb_job_t * job ); int hb_autopassthru_get_encoder( int in_codec, int copy_mask, int fallback, int muxer ); int hb_get_best_mixdown(uint32_t codec, uint64_t layout, int mixdown); @@ -222,6 +256,12 @@ void hb_get_audio_compression_limits(uint32_t codec, float *low, float *high, fl float hb_get_best_audio_compression( uint32_t codec, float compression); float hb_get_default_audio_compression( uint32_t codec ); +struct hb_title_set_s +{ + hb_list_t * list_title; + int feature; // Detected DVD feature title +}; + /****************************************************************************** * hb_job_t: settings to be filled by the UI *****************************************************************************/ @@ -333,6 +373,8 @@ struct hb_job_s #define HB_COLR_MAT_SMPTE240M 7 // 0, 3-5, 8-65535: reserved + hb_list_t * list_chapter; + /* List of audio settings. */ hb_list_t * list_audio; int acodec_copy_mask; // Auto Passthru allowed codecs @@ -341,6 +383,10 @@ struct hb_job_s /* Subtitles */ hb_list_t * list_subtitle; + hb_list_t * list_attachment; + + hb_metadata_t * metadata; + /* Muxer settings mux: output file format file: file path */ @@ -349,7 +395,7 @@ struct hb_job_s #define HB_MUX_MKV 0x200000 int mux; - const char * file; + char * file; /* Allow MP4 files > 4 gigs */ int largeFileSize; @@ -534,7 +580,7 @@ struct hb_chapter_s uint64_t duration; /* Optional chapter title */ - char title[1024]; + char *title; }; /* @@ -615,23 +661,38 @@ struct hb_subtitle_s */ struct hb_attachment_s { - enum attachtype { FONT_TTF_ATTACH } type; + enum attachtype { FONT_TTF_ATTACH, HB_ART_ATTACH } type; char * name; char * data; int size; }; +struct hb_coverart_s +{ + uint8_t *data; + uint32_t size; + enum arttype { + HB_ART_UNDEFINED, + HB_ART_BMP, + HB_ART_GIF, + HB_ART_PNG, + HB_ART_JPEG + } type; +}; + struct hb_metadata_s { - char name[255]; - char artist[255]; - char composer[255]; - char release_date[255]; - char comment[1024]; - char album[255]; - char genre[255]; - uint32_t coverart_size; - uint8_t *coverart; + char *name; + char *artist; // Actors + char *composer; + char *release_date; + char *comment; + char *album; // DVD + char *album_artist; // Director + char *genre; + char *description; + char *long_description; + hb_list_t * list_coverart; }; struct hb_title_s @@ -682,7 +743,7 @@ struct hb_title_s int video_codec_param; /* codec specific config */ char *video_codec_name; int video_bitrate; - const char *container_name; + char *container_name; int data_rate; hb_metadata_t *metadata; @@ -692,12 +753,15 @@ struct hb_title_s hb_list_t * list_subtitle; hb_list_t * list_attachment; - /* Job template for this title */ +#define HB_TITLE_JOBS +#if defined(HB_TITLE_JOBS) hb_job_t * job; +#endif uint32_t flags; // set if video stream doesn't have IDR frames #define HBTF_NO_IDR (1 << 0) +#define HBTF_SCAN_COMPLETE (1 << 0) }; @@ -941,7 +1005,8 @@ enum hb_filter_object_t * hb_filter_init( int filter_id ); hb_filter_object_t * hb_filter_copy( hb_filter_object_t * filter ); -void hb_filter_close( hb_filter_object_t ** ); +hb_list_t *hb_filter_list_copy(const hb_list_t *src); +void hb_filter_close( hb_filter_object_t ** ); typedef void hb_error_handler_t( const char *errmsg ); diff --git a/libhb/decavcodec.c b/libhb/decavcodec.c index 4fd22c833..dd3c8879d 100644 --- a/libhb/decavcodec.c +++ b/libhb/decavcodec.c @@ -565,7 +565,7 @@ static void log_chapter( hb_work_private_t *pv, int chap_num, int64_t pts ) if ( !pv->job ) return; - c = hb_list_item( pv->job->title->list_chapter, chap_num - 1 ); + c = hb_list_item( pv->job->list_chapter, chap_num - 1 ); if ( c && c->title ) { hb_log( "%s: \"%s\" (%d) at frame %u time %"PRId64, diff --git a/libhb/decmetadata.c b/libhb/decmetadata.c index e3829de09..513e64fbe 100644 --- a/libhb/decmetadata.c +++ b/libhb/decmetadata.c @@ -11,9 +11,10 @@ #include "common.h" -static void decmp4metadata( hb_title_t *title ) +static int decmp4metadata( hb_title_t *title ) { MP4FileHandle input_file; + int result = 0; hb_deep_log( 2, "Got an MP4 input, read the metadata"); input_file = MP4Read( title->path, 0 ); @@ -31,35 +32,93 @@ static void decmp4metadata( hb_title_t *title ) if( tags->name ) { hb_deep_log( 2, "Metadata Name in input file is '%s'", tags->name ); - strncpy( title->metadata->name, tags->name, sizeof(title->metadata->name) ); + hb_metadata_set_name(title->metadata, tags->name); + result = 1; } if( tags->artist ) - strncpy( title->metadata->artist, tags->artist, sizeof(title->metadata->artist) ); + { + hb_metadata_set_artist(title->metadata, tags->artist); + result = 1; + } if( tags->composer ) - strncpy( title->metadata->composer, tags->composer, sizeof(title->metadata->composer) ); + { + hb_metadata_set_composer(title->metadata, tags->composer); + result = 1; + } if( tags->comments ) - strncpy( title->metadata->comment, tags->comments, sizeof(title->metadata->comment) ); + { + hb_metadata_set_comment(title->metadata, tags->comments); + result = 1; + } if( tags->releaseDate ) - strncpy( title->metadata->release_date, tags->releaseDate, sizeof(title->metadata->release_date) ); + { + hb_metadata_set_release_date(title->metadata, tags->releaseDate); + result = 1; + } if( tags->album ) - strncpy( title->metadata->album, tags->album, sizeof(title->metadata->album) ); + { + hb_metadata_set_album(title->metadata, tags->album); + result = 1; + } + + if( tags->albumArtist ) + { + hb_metadata_set_album_artist(title->metadata, tags->albumArtist); + result = 1; + } if( tags->genre ) - strncpy( title->metadata->genre, tags->genre, sizeof(title->metadata->genre) ); + { + hb_metadata_set_genre(title->metadata, tags->genre); + result = 1; + } + + if( tags->description ) + { + hb_metadata_set_description(title->metadata, tags->description); + result = 1; + } + + if( tags->longDescription ) + { + hb_metadata_set_long_description(title->metadata, tags->longDescription); + result = 1; + } - if( tags->artworkCount > 0 ) { - const MP4TagArtwork* art = tags->artwork + 0; // first element - title->metadata->coverart = (uint8_t*)malloc( art->size ); - title->metadata->coverart_size = art->size; - memcpy( title->metadata->coverart, art->data, art->size ); + int ii; + for ( ii = 0; ii < tags->artworkCount; ii++ ) + { + const MP4TagArtwork* art = tags->artwork + ii; + int type; + switch ( art->type ) + { + case MP4_ART_BMP: + type = HB_ART_BMP; + break; + case MP4_ART_GIF: + type = HB_ART_GIF; + break; + case MP4_ART_JPEG: + type = HB_ART_JPEG; + break; + case MP4_ART_PNG: + type = HB_ART_PNG; + break; + default: + type = HB_ART_UNDEFINED; + break; + } + hb_metadata_add_coverart( + title->metadata, art->data, art->size, type); hb_deep_log( 2, "Got some cover art of type %d, size %d", art->type, - title->metadata->coverart_size ); + art->size ); + result = 1; } /* store,free tags */ @@ -91,11 +150,13 @@ static void decmp4metadata( hb_title_t *title ) if( chapter_list[i-1].title ) { - strcpy( chapter->title, chapter_list[i-1].title ); + hb_chapter_set_title( chapter, chapter_list[i-1].title ); } else { - sprintf( chapter->title, "Chapter %d", chapter->index ); + char chapter_title[80]; + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); } hb_deep_log( 2, "Added chapter %i, name='%s', dur=%"PRId64", (%02i:%02i:%02i)", @@ -109,6 +170,7 @@ static void decmp4metadata( hb_title_t *title ) MP4Close( input_file ); } + return result; } /* @@ -116,24 +178,16 @@ static void decmp4metadata( hb_title_t *title ) * * Look at the title and extract whatever metadata we can from that title. */ -void decmetadata( hb_title_t *title ) +int decmetadata( hb_title_t *title ) { if( !title ) { - return; + return 0; } - if( title->metadata ) - { - free( title->metadata ); - title->metadata = NULL; - } - - title->metadata = calloc( sizeof(hb_metadata_t), 1); - if( !title->metadata ) { - return; + return 0; } /* @@ -141,9 +195,7 @@ void decmetadata( hb_title_t *title ) */ if( title->container_name && strcmp(title->container_name, "mov,mp4,m4a,3gp,3g2,mj2") == 0 ) { - decmp4metadata( title ); - } else { - free( title->metadata ); - title->metadata = NULL; + return decmp4metadata( title ); } + return 0; } diff --git a/libhb/decmpeg2.c b/libhb/decmpeg2.c index 311fc93c8..991feb8e9 100644 --- a/libhb/decmpeg2.c +++ b/libhb/decmpeg2.c @@ -498,11 +498,11 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, m->look_for_iframe = 0; const char *chap_name = ""; if ( m->job && new_chap > 0 && - hb_list_item( m->job->title->list_chapter, + hb_list_item( m->job->list_chapter, new_chap - 1 ) ) { hb_chapter_t * c = hb_list_item( - m->job->title->list_chapter, + m->job->list_chapter, new_chap - 1 ); chap_name = c->title; } @@ -514,10 +514,10 @@ static int hb_libmpeg2_decode( hb_libmpeg2_t * m, hb_buffer_t * buf_es, { // this is the first frame returned by the decoder m->first_pts = buf->s.start; - if ( m->job && hb_list_item( m->job->title->list_chapter, + if ( m->job && hb_list_item( m->job->list_chapter, m->job->chapter_start - 1 ) ) { - hb_chapter_t * c = hb_list_item( m->job->title->list_chapter, + hb_chapter_t * c = hb_list_item( m->job->list_chapter, m->job->chapter_start - 1 ); hb_log( "mpeg2: \"%s\" (%d) at frame %u time %"PRId64, c->title, m->job->chapter_start, m->nframes, buf->s.start ); diff --git a/libhb/decsrtsub.c b/libhb/decsrtsub.c index 55004c05f..6d1754068 100644 --- a/libhb/decsrtsub.c +++ b/libhb/decsrtsub.c @@ -464,7 +464,6 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) hb_buffer_t *buffer; int i; hb_chapter_t * chapter; - hb_title_t *title = job->title; pv = calloc( 1, sizeof( hb_work_private_t ) ); if( pv ) @@ -489,7 +488,7 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) pv->start_time = 0; for( i = 1; i < job->chapter_start; ++i ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); if( chapter ) { pv->start_time += chapter->duration; @@ -501,7 +500,7 @@ static int decsrtInit( hb_work_object_t * w, hb_job_t * job ) pv->stop_time = pv->start_time; for( i = job->chapter_start; i <= job->chapter_end; ++i ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); if( chapter ) { pv->stop_time += chapter->duration; diff --git a/libhb/dvd.c b/libhb/dvd.c index 1a273f977..f342b5474 100644 --- a/libhb/dvd.c +++ b/libhb/dvd.c @@ -561,11 +561,13 @@ static hb_title_t * hb_dvdread_title_scan( hb_dvd_t * e, int t, uint64_t min_dur for( i = 0; i < vts->vts_ptt_srpt->title[title->ttn-1].nr_of_ptts; i++ ) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); /* remember the on-disc chapter number */ chapter->index = i + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); pgc_id = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgcn; pgn = vts->vts_ptt_srpt->title[title->ttn-1].ptt[i].pgn; diff --git a/libhb/dvdnav.c b/libhb/dvdnav.c index 638b6e5af..c1f152efd 100644 --- a/libhb/dvdnav.c +++ b/libhb/dvdnav.c @@ -740,12 +740,14 @@ static hb_title_t * hb_dvdnav_title_scan( hb_dvd_t * e, int t, uint64_t min_dura for (i = pgn; i <= pgc->nr_of_programs; i++) { + char chapter_title[80]; chapter = calloc( sizeof( hb_chapter_t ), 1 ); chapter->pgcn = pgcn; chapter->pgn = i; chapter->index = c + 1; - sprintf( chapter->title, "Chapter %d", chapter->index ); + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); hb_list_add( title->list_chapter, chapter ); c++; diff --git a/libhb/hb.c b/libhb/hb.c index 52ddc206b..8a1ec3b1e 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -36,7 +36,7 @@ struct hb_handle_s int pid; /* DVD/file scan thread */ - hb_list_t * list_title; + hb_title_set_t title_set; hb_thread_t * scan_thread; /* The thread which processes the jobs. Others threads are launched @@ -71,7 +71,6 @@ int hb_instance_counter = 0; int hb_process_initialized = 0; static void thread_func( void * ); -hb_title_t * hb_get_title_by_index( hb_handle_t *, int ); static int ff_lockmgr_cb(void **mutex, enum AVLockOp op) { @@ -432,7 +431,7 @@ hb_handle_t * hb_init( int verbose, int update_check ) */ hb_buffer_pool_init(); - h->list_title = hb_list_init(); + h->title_set.list_title = hb_list_init(); h->jobs = hb_list_init(); h->state_lock = hb_lock_init(); @@ -531,7 +530,7 @@ hb_handle_t * hb_init_dl( int verbose, int update_check ) } } - h->list_title = hb_list_init(); + h->title_set.list_title = hb_list_init(); h->jobs = hb_list_init(); h->current_job = NULL; @@ -631,7 +630,7 @@ void hb_remove_previews( hb_handle_t * h ) dir = opendir( dirname ); if (dir == NULL) return; - count = hb_list_count( h->list_title ); + count = hb_list_count( h->title_set.list_title ); while( ( entry = readdir( dir ) ) ) { if( entry->d_name[0] == '.' ) @@ -640,7 +639,7 @@ void hb_remove_previews( hb_handle_t * h ) } for( i = 0; i < count; i++ ) { - title = hb_list_item( h->list_title, i ); + title = hb_list_item( h->title_set.list_title, i ); len = snprintf( filename, 1024, "%d_%d", h->id, title->index ); if (strncmp(entry->d_name, filename, len) == 0) { @@ -670,15 +669,15 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index, /* Clean up from previous scan */ hb_remove_previews( h ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } hb_log( "hb_scan: path=%s, title_index=%d", path, title_index ); h->scan_thread = hb_scan_init( h, &h->scan_die, path, title_index, - h->list_title, preview_count, + &h->title_set, preview_count, store_previews, min_duration ); } @@ -689,25 +688,12 @@ void hb_scan( hb_handle_t * h, const char * path, int title_index, */ hb_list_t * hb_get_titles( hb_handle_t * h ) { - return h->list_title; + return h->title_set.list_title; } -/** - * Create preview image of desired title a index of picture. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to get the preview for (1-based). - * @param picture Index in title. - * @param buffer Handle to buffer were image will be drawn. - */ -void hb_get_preview_by_index( hb_handle_t * h, int title_index, int picture, uint8_t * buffer ) +hb_title_set_t * hb_get_title_set( hb_handle_t * h ) { - hb_title_t * title; - - title = hb_get_title_by_index( h, title_index ); - if ( title != NULL ) - { - hb_get_preview( h, title, picture, buffer ); - } + return &h->title_set; } int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf ) @@ -747,12 +733,16 @@ hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ) { FILE * file; char filename[1024]; + hb_title_set_t *title_set; + hb_title_t * title = NULL; + title_set = hb_get_title_set(h); + int ii; - for (ii = 0; ii < hb_list_count(h->list_title); ii++) + for (ii = 0; ii < hb_list_count(title_set->list_title); ii++) { - title = hb_list_item( h->list_title, ii); + title = hb_list_item( title_set->list_title, ii); if (title != NULL && title->index == title_idx) { break; @@ -804,10 +794,10 @@ hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ) * @param picture Index in title. * @param buffer Handle to buffer were image will be drawn. */ -void hb_get_preview( hb_handle_t * h, hb_title_t * title, int picture, +void hb_get_preview( hb_handle_t * h, hb_job_t * job, int picture, uint8_t * buffer ) { - hb_job_t * job = title->job; + hb_title_t * title = job->title; char filename[1024]; hb_buffer_t * in_buf, * deint_buf = NULL, * preview_buf; uint8_t * pen; @@ -991,26 +981,6 @@ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int thre /** * Calculates job width and height for anamorphic content, * - * @param h Instance handle - * @param title_index Index of the title/job to inspect (1-based). - * @param output_width Pointer to returned storage width - * @param output_height Pointer to returned storage height - * @param output_par_width Pointer to returned pixel width - * @param output_par_height Pointer to returned pixel height - */ -void hb_set_anamorphic_size_by_index( hb_handle_t * h, int title_index, - int *output_width, int *output_height, - int *output_par_width, int *output_par_height ) -{ - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_set_anamorphic_size( title->job, output_width, output_height, output_par_width, output_par_height ); -} - -/** - * Calculates job width and height for anamorphic content, - * * @param job Handle to hb_job_t * @param output_width Pointer to returned storage width * @param output_height Pointer to returned storage height @@ -1423,53 +1393,6 @@ hb_job_t * hb_current_job( hb_handle_t * h ) } /** - * Applies information from the given job to the official job instance. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to apply the chapter name to (1-based). - * @param chapter The chapter to apply the name to (1-based). - * @param job Job information to apply. - */ -void hb_set_chapter_name( hb_handle_t * h, int title_index, int chapter_index, const char * chapter_name ) -{ - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_chapter_t * chapter = hb_list_item( title->list_chapter, chapter_index - 1 ); - - strncpy(chapter->title, chapter_name, 1023); - chapter->title[1023] = '\0'; -} - -/** - * Applies information from the given job to the official job instance. - * Currently only applies information needed for anamorphic size calculation and previews. - * @param h Handle to hb_handle_t. - * @param title_index Index of the title to apply the job information to (1-based). - * @param job Job information to apply. - */ -void hb_set_job( hb_handle_t * h, int title_index, hb_job_t * job ) -{ - int i; - - hb_title_t * title; - title = hb_get_title_by_index( h, title_index ); - - hb_job_t * job_target = title->job; - - job_target->deinterlace = job->deinterlace; - job_target->width = job->width; - job_target->height = job->height; - job_target->maxWidth = job->maxWidth; - job_target->maxHeight = job->maxHeight; - for (i = 0; i < 4; i++) - { - job_target->crop[i] = job->crop[i]; - } - - job_target->anamorphic = job->anamorphic; -} - -/** * Adds a job to the job list. * @param h Handle to hb_handle_t. * @param job Handle to hb_job_t. @@ -1477,85 +1400,21 @@ void hb_set_job( hb_handle_t * h, int title_index, hb_job_t * job ) void hb_add( hb_handle_t * h, hb_job_t * job ) { hb_job_t * job_copy; - hb_title_t * title, * title_copy; - hb_chapter_t * chapter, * chapter_copy; hb_audio_t * audio; hb_subtitle_t * subtitle; - hb_attachment_t * attachment; int i; char audio_lang[4]; - /* Copy the title */ - title = job->title; - title_copy = malloc( sizeof( hb_title_t ) ); - memcpy( title_copy, title, sizeof( hb_title_t ) ); - - title_copy->list_chapter = hb_list_init(); - for( i = 0; i < hb_list_count( title->list_chapter ); i++ ) - { - chapter = hb_list_item( title->list_chapter, i ); - chapter_copy = malloc( sizeof( hb_chapter_t ) ); - memcpy( chapter_copy, chapter, sizeof( hb_chapter_t ) ); - hb_list_add( title_copy->list_chapter, chapter_copy ); - } - - /* - * Copy the metadata - */ - if( title->metadata ) - { - title_copy->metadata = malloc( sizeof( hb_metadata_t ) ); - - if( title_copy->metadata ) - { - memcpy( title_copy->metadata, title->metadata, sizeof( hb_metadata_t ) ); - - /* - * Need to copy the artwork seperatly (TODO). - */ - if( title->metadata->coverart ) - { - title_copy->metadata->coverart = malloc( title->metadata->coverart_size ); - if( title_copy->metadata->coverart ) - { - memcpy( title_copy->metadata->coverart, title->metadata->coverart, - title->metadata->coverart_size ); - } else { - title_copy->metadata->coverart_size = 0; - } - } - } - } - - /* Copy the audio track(s) we want */ - title_copy->list_audio = hb_list_init(); - for( i = 0; i < hb_list_count(job->list_audio); i++ ) - { - if( ( audio = hb_list_item( job->list_audio, i ) ) ) - { - hb_list_add( title_copy->list_audio, hb_audio_copy(audio) ); - } - } - - /* Initialize subtitle list - filled out further below */ - title_copy->list_subtitle = hb_list_init(); - - /* Copy all the attachments */ - title_copy->list_attachment = hb_list_init(); - for( i = 0; i < hb_list_count(title->list_attachment); i++ ) - { - if( ( attachment = hb_list_item( title->list_attachment, i ) ) ) - { - hb_list_add( title_copy->list_attachment, hb_attachment_copy(attachment) ); - } - } - title_copy->video_codec_name = strdup( title->video_codec_name ); + /* Copy the job */ + job_copy = calloc( sizeof( hb_job_t ), 1 ); + memcpy( job_copy, job, sizeof( hb_job_t ) ); - /* If we're doing Foreign Audio Search, copy all subtitles matching the first - * audio track language we find in the audio list. + /* If we're doing Foreign Audio Search, copy all subtitles matching the + * first audio track language we find in the audio list. * - * Otherwise, copy all subtitles found in the input job (which can be manually - * selected by the user, or added after the Foreign Audio Search pass). */ + * Otherwise, copy all subtitles found in the input job (which can be + * manually selected by the user, or added after the Foreign Audio + * Search pass). */ memset( audio_lang, 0, sizeof( audio_lang ) ); if( job->indepth_scan ) @@ -1571,9 +1430,16 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) break; } } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + + /* + * If doing a subtitle scan then add all the matching subtitles for this + * language. + */ + job_copy->list_subtitle = hb_list_init(); + + for( i = 0; i < hb_list_count( job->title->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->title->list_subtitle, i ); if( strcmp( subtitle->iso639_2, audio_lang ) == 0 && hb_subtitle_can_force( subtitle->source ) ) { @@ -1582,54 +1448,31 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) * * We will update the subtitle list on the next pass later, after * the subtitle scan pass has completed. */ - hb_list_add( title_copy->list_subtitle, hb_subtitle_copy( subtitle ) ); + hb_list_add( job_copy->list_subtitle, + hb_subtitle_copy( subtitle ) ); } } } else { /* Copy all subtitles from the input job to title_copy/job_copy. */ - for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) - { - if( ( subtitle = hb_list_item( job->list_subtitle, i ) ) ) - { - hb_list_add( title_copy->list_subtitle, hb_subtitle_copy( subtitle ) ); - } - } + job_copy->list_subtitle = hb_subtitle_list_copy( job->list_subtitle ); } - /* Copy the job */ - job_copy = calloc( sizeof( hb_job_t ), 1 ); - memcpy( job_copy, job, sizeof( hb_job_t ) ); - title_copy->job = job_copy; - job_copy->title = title_copy; - job_copy->list_audio = title_copy->list_audio; - job_copy->list_subtitle = title_copy->list_subtitle; // sharing list between title and job - job_copy->file = strdup( job->file ); + job_copy->list_chapter = hb_chapter_list_copy( job->list_chapter ); + job_copy->list_audio = hb_audio_list_copy( job->list_audio ); + job_copy->list_attachment = hb_attachment_list_copy( job->list_attachment ); + job_copy->metadata = hb_metadata_copy( job->metadata ); + + if ( job->file ) + job_copy->file = strdup( job->file ); + if ( job->advanced_opts ) + job_copy->advanced_opts = strdup( job->advanced_opts ); job_copy->h = h; job_copy->pause = h->pause_lock; /* Copy the job filter list */ - if( job->list_filter ) - { - int i; - int filter_count = hb_list_count( job->list_filter ); - job_copy->list_filter = hb_list_init(); - for( i = 0; i < filter_count; i++ ) - { - /* - * Copy the filters, since the MacGui reuses the global filter objects - * meaning that queued up jobs overwrite the previous filter settings. - * In reality, settings is probably the only field that needs duplicating - * since it's the only value that is ever changed. But name is duplicated - * as well for completeness. Not copying private_data since it gets - * created for each job in renderInit. - */ - hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - hb_filter_object_t * filter_copy = hb_filter_copy( filter ); - hb_list_add( job_copy->list_filter, filter_copy ); - } - } + job_copy->list_filter = hb_filter_list_copy( job->list_filter ); /* Add the job to the list */ hb_list_add( h->jobs, job_copy ); @@ -1638,37 +1481,6 @@ void hb_add( hb_handle_t * h, hb_job_t * job ) } /** - * Clean up the job structure so that is is ready for setting up a new job. - * Should be called by front-ends after hb_add(). - */ -void hb_reset_job( hb_job_t * job ) -{ - hb_audio_t *audio; - hb_subtitle_t *subtitle; - hb_filter_object_t *filter; - - // clean up audio list - while( ( audio = hb_list_item( job->list_audio, 0 ) ) ) - { - hb_list_rem( job->list_audio, audio ); - free( audio ); - } - // clean up subtitle list - while( ( subtitle = hb_list_item( job->list_subtitle, 0 ) ) ) - { - hb_list_rem( job->list_subtitle, subtitle ); - free( subtitle ); - } - // clean up filter list - while( ( filter = hb_list_item( job->list_filter, 0 ) ) ) - { - hb_list_rem( job->list_filter, filter ); - free( filter->settings ); - free( filter ); - } -} - -/** * Removes a job from the job list. * @param h Handle to hb_handle_t. * @param job Handle to hb_job_t. @@ -1831,17 +1643,12 @@ void hb_close( hb_handle_t ** _h ) hb_thread_close( &h->main_thread ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); - if( title->job ) - { - hb_reset_job( title->job ); - } - free( title->job ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } - hb_list_close( &h->list_title ); + hb_list_close( &h->title_set.list_title ); hb_list_close( &h->jobs ); hb_lock_close( &h->state_lock ); @@ -1925,9 +1732,9 @@ static void thread_func( void * _h ) hb_title_t * title; hb_remove_previews( h ); - while( ( title = hb_list_item( h->list_title, 0 ) ) ) + while( ( title = hb_list_item( h->title_set.list_title, 0 ) ) ) { - hb_list_rem( h->list_title, title ); + hb_list_rem( h->title_set.list_title, title ); hb_title_close( &title ); } @@ -1936,7 +1743,7 @@ static void thread_func( void * _h ) else { hb_log( "libhb: scan thread found %d valid title(s)", - hb_list_count( h->list_title ) ); + hb_list_count( h->title_set.list_title ) ); } hb_lock( h->state_lock ); h->state.state = HB_STATE_SCANDONE; //originally state.state @@ -2024,29 +1831,6 @@ int hb_get_instance_id( hb_handle_t * h ) } /** - * Returns the title with the given title index. - * @param h Handle to hb_handle_t - * @param title_index the index of the title to get - * @returns The requested title - */ -hb_title_t * hb_get_title_by_index( hb_handle_t * h, int title_index ) -{ - hb_title_t * title; - int i; - int count = hb_list_count( h->list_title ); - for (i = 0; i < count; i++) - { - title = hb_list_item( h->list_title, i ); - if (title->index == title_index) - { - return title; - } - } - - return NULL; -} - -/** * Sets the current state. * @param h Handle to hb_handle_t * @param s Handle to new hb_state_t diff --git a/libhb/hb.h b/libhb/hb.h index da2311834..825032cfb 100644 --- a/libhb/hb.h +++ b/libhb/hb.h @@ -54,21 +54,23 @@ uint64_t hb_first_duration( hb_handle_t * ); Returns the list of valid titles detected by the latest scan. */ hb_list_t * hb_get_titles( hb_handle_t * ); +/* hb_get_title_set() + Returns the title set which contains a list of valid titles detected + by the latest scan and title set data. */ +hb_title_set_t * hb_get_title_set( hb_handle_t * ); + /* hb_detect_comb() Analyze a frame for interlacing artifacts, returns true if they're found. Taken from Thomas Oestreich's 32detect filter in the Transcode project. */ int hb_detect_comb( hb_buffer_t * buf, int color_equal, int color_diff, int threshold, int prog_equal, int prog_diff, int prog_threshold ); +// JJJ: title->job? int hb_save_preview( hb_handle_t * h, int title, int preview, hb_buffer_t *buf ); hb_buffer_t * hb_read_preview( hb_handle_t * h, int title_idx, int preview ); -void hb_get_preview_by_index( hb_handle_t *, int, int, uint8_t * ); -void hb_get_preview( hb_handle_t *, hb_title_t *, int, +void hb_get_preview( hb_handle_t *, hb_job_t *, int, uint8_t * ); void hb_set_size( hb_job_t *, double ratio, int pixels ); -void hb_set_anamorphic_size_by_index( hb_handle_t *, int, - int *output_width, int *output_height, - int *output_par_width, int *output_par_height ); void hb_set_anamorphic_size( hb_job_t *, int *output_width, int *output_height, int *output_par_width, int *output_par_height ); @@ -83,7 +85,11 @@ void hb_set_chapter_name( hb_handle_t *, int, int, const char * ); void hb_set_job( hb_handle_t *, int, hb_job_t * ); void hb_add( hb_handle_t *, hb_job_t * ); void hb_rem( hb_handle_t *, hb_job_t * ); -void hb_reset_job( hb_job_t * job ); + +hb_job_t * hb_job_init_by_index( hb_handle_t *h, int title_index ); +hb_job_t * hb_job_init( hb_title_t * title ); +void hb_job_reset( hb_job_t * job ); +void hb_job_close( hb_job_t ** job ); void hb_start( hb_handle_t * ); void hb_pause( hb_handle_t * ); diff --git a/libhb/internal.h b/libhb/internal.h index caa2e7189..1c02ffe85 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -228,7 +228,7 @@ static inline hb_buffer_t * hb_video_buffer_init( int width, int height ) hb_thread_t * hb_update_init( int * build, char * version ); hb_thread_t * hb_scan_init( hb_handle_t *, volatile int * die, const char * path, int title_index, - hb_list_t * list_title, int preview_count, + hb_title_set_t * title_set, int preview_count, int store_previews, uint64_t min_duration ); hb_thread_t * hb_work_init( hb_list_t * jobs, volatile int * die, int * error, hb_job_t ** job ); @@ -266,7 +266,7 @@ extern const hb_muxer_t hb_demux[]; /*********************************************************************** * decmetadata.c **********************************************************************/ -extern void decmetadata( hb_title_t *title ); +extern int decmetadata( hb_title_t *title ); /*********************************************************************** * batch.c diff --git a/libhb/muxcommon.c b/libhb/muxcommon.c index 6587a4dac..d5d9c7a92 100644 --- a/libhb/muxcommon.c +++ b/libhb/muxcommon.c @@ -441,7 +441,6 @@ static void mux_loop( void * _w ) hb_work_object_t * hb_muxer_init( hb_job_t * job ) { - hb_title_t * title = job->title; int i; hb_mux_t * mux = calloc( sizeof( hb_mux_t ), 1 ); hb_work_object_t * w; @@ -490,9 +489,9 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) add_mux_track( mux, job->mux_data, 1 ); muxer->done = &muxer->private_data->mux->done; - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - hb_audio_t *audio = hb_list_item( title->list_audio, i ); + hb_audio_t *audio = hb_list_item( job->list_audio, i ); w = hb_get_work( WORK_MUX ); w->private_data = calloc( sizeof( hb_work_private_t ), 1 ); @@ -507,9 +506,9 @@ hb_work_object_t * hb_muxer_init( hb_job_t * job ) w->thread = hb_thread_init( w->name, mux_loop, w, HB_NORMAL_PRIORITY ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - hb_subtitle_t *subtitle = hb_list_item( title->list_subtitle, i ); + hb_subtitle_t *subtitle = hb_list_item( job->list_subtitle, i ); if (subtitle->config.dest != PASSTHRUSUB) continue; diff --git a/libhb/muxmkv.c b/libhb/muxmkv.c index addd800de..2b629bc49 100644 --- a/libhb/muxmkv.c +++ b/libhb/muxmkv.c @@ -59,7 +59,6 @@ static uint8_t * create_flac_header( uint8_t *data, int size ) static int MKVInit( hb_mux_object_t * m ) { hb_job_t * job = m->job; - hb_title_t * title = job->title; hb_audio_t * audio; hb_mux_data_t * mux_data; @@ -197,9 +196,9 @@ static int MKVInit( hb_mux_object_t * m ) mux_data->track = mk_createTrack(m->file, track); /* add the audio tracks */ - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; @@ -328,14 +327,14 @@ static int MKVInit( hb_mux_object_t * m ) "custom colors: OFF, tridx: 0000, " "colors: 000000, 000000, 000000, 000000\n"; - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { hb_subtitle_t * subtitle; uint32_t rgb[16]; char subidx[2048]; int len; - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if (subtitle->config.dest != PASSTHRUSUB) continue; @@ -400,7 +399,7 @@ static int MKVInit( hb_mux_object_t * m ) if (need_fonts) { - hb_list_t * list_attachment = job->title->list_attachment; + hb_list_t * list_attachment = job->list_attachment; int i; for ( i = 0; i < hb_list_count(list_attachment); i++ ) { @@ -437,7 +436,6 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, { ogg_packet *op = NULL; hb_job_t * job = m->job; - hb_title_t * title = job->title; uint64_t timecode = 0; hb_chapter_t *chapter_data; char tmp_buffer[1024]; @@ -457,7 +455,7 @@ static int MKVMux( hb_mux_object_t * m, hb_mux_data_t * mux_data, { mux_data->current_chapter = buf->s.new_chap - 2; } - chapter_data = hb_list_item( title->list_chapter, + chapter_data = hb_list_item( job->list_chapter, mux_data->current_chapter++ ); tmp_buffer[0] = '\0'; @@ -556,7 +554,6 @@ static int MKVEnd( hb_mux_object_t * m ) { hb_job_t *job = m->job; hb_mux_data_t *mux_data = job->mux_data; - hb_title_t *title = job->title; hb_chapter_t *chapter_data; char tmp_buffer[1024]; char *string = tmp_buffer; @@ -569,7 +566,7 @@ static int MKVEnd( hb_mux_object_t * m ) return 0; } - chapter_data = hb_list_item( title->list_chapter, mux_data->current_chapter++ ); + chapter_data = hb_list_item( job->list_chapter, mux_data->current_chapter++ ); if(job->chapter_markers) { @@ -588,29 +585,62 @@ static int MKVEnd( hb_mux_object_t * m ) mk_createChapterSimple(m->file, mux_data->prev_chapter_tc, mux_data->prev_chapter_tc, string); } - if( title->metadata ) + if( job->metadata ) { - hb_metadata_t *md = title->metadata; + hb_metadata_t *md = job->metadata; hb_deep_log( 2, "Writing Metadata to output file..."); - mk_createTagSimple( m->file, MK_TAG_TITLE, md->name ); - mk_createTagSimple( m->file, "ARTIST", md->artist ); - mk_createTagSimple( m->file, "COMPOSER", md->composer ); - mk_createTagSimple( m->file, MK_TAG_SYNOPSIS, md->comment ); - mk_createTagSimple( m->file, "DATE_RELEASED", md->release_date ); - // mk_createTagSimple( m->file, "", md->album ); - mk_createTagSimple( m->file, MK_TAG_GENRE, md->genre ); + if ( md->name ) + { + mk_createTagSimple( m->file, MK_TAG_TITLE, md->name ); + } + if ( md->artist ) + { + mk_createTagSimple( m->file, "ARTIST", md->artist ); + } + if ( md->album_artist ) + { + mk_createTagSimple( m->file, "DIRECTOR", md->album_artist ); + } + if ( md->composer ) + { + mk_createTagSimple( m->file, "COMPOSER", md->composer ); + } + if ( md->release_date ) + { + mk_createTagSimple( m->file, "DATE_RELEASED", md->release_date ); + } + if ( md->comment ) + { + mk_createTagSimple( m->file, "SUMMARY", md->comment ); + } + if ( !md->name && md->album ) + { + mk_createTagSimple( m->file, MK_TAG_TITLE, md->album ); + } + if ( md->genre ) + { + mk_createTagSimple( m->file, MK_TAG_GENRE, md->genre ); + } + if ( md->description ) + { + mk_createTagSimple( m->file, "DESCRIPTION", md->description ); + } + if ( md->long_description ) + { + mk_createTagSimple( m->file, "SYNOPSIS", md->long_description ); + } } // Update and track private data that can change during // encode. int i; - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { mk_Track * track; hb_audio_t * audio; - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); track = audio->priv.mux_data->track; switch (audio->config.out.codec & HB_ACODEC_MASK) diff --git a/libhb/muxmp4.c b/libhb/muxmp4.c index d21e4b767..f1380dc18 100644 --- a/libhb/muxmp4.c +++ b/libhb/muxmp4.c @@ -262,9 +262,9 @@ static int MP4Init( hb_mux_object_t * m ) } /* add the audio tracks */ - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); mux_data = calloc(1, sizeof( hb_mux_data_t ) ); audio->priv.mux_data = mux_data; @@ -464,7 +464,7 @@ static int MP4Init( hb_mux_object_t * m ) /* Set the language for this track */ MP4SetTrackLanguage(m->file, mux_data->track, audio->config.lang.iso639_2); - if( hb_list_count( title->list_audio ) > 1 ) + if( hb_list_count( job->list_audio ) > 1 ) { /* Set the audio track alternate group */ MP4SetTrackIntegerProperty(m->file, mux_data->track, "tkhd.alternate_group", 1); @@ -944,7 +944,7 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, duration = m->sum_dur - m->chapter_duration + offset; if ( duration >= (90000*3)/2 ) { - chapter = hb_list_item( m->job->title->list_chapter, + chapter = hb_list_item( m->job->list_chapter, buf->s.new_chap - 2 ); MP4AddChapter( m->file, @@ -1248,7 +1248,6 @@ static int MP4Mux( hb_mux_object_t * m, hb_mux_data_t * mux_data, static int MP4End( hb_mux_object_t * m ) { hb_job_t * job = m->job; - hb_title_t * title = job->title; // Flush the delayed frame if ( m->delay_buf ) @@ -1264,7 +1263,7 @@ static int MP4End( hb_mux_object_t * m ) if ( duration >= (90000*3)/2 ) { - chapter = hb_list_item( m->job->title->list_chapter, + chapter = hb_list_item( m->job->list_chapter, m->current_chapter - 1 ); MP4AddChapter( m->file, @@ -1293,9 +1292,9 @@ static int MP4End( hb_mux_object_t * m ) /* * Write the MP4 iTunes metadata if we have any metadata */ - if( title->metadata ) + if( job->metadata ) { - hb_metadata_t *md = title->metadata; + hb_metadata_t *md = job->metadata; const MP4Tags* tags; hb_deep_log( 2, "Writing Metadata to output file..."); @@ -1306,28 +1305,60 @@ static int MP4End( hb_mux_object_t * m ) MP4TagsFetch( tags, m->file ); /* populate */ - if( strlen( md->name )) + if( md->name ) MP4TagsSetName( tags, md->name ); - if( strlen( md->artist )) + if( md->artist ) MP4TagsSetArtist( tags, md->artist ); - if( strlen( md->composer )) + if( md->composer ) MP4TagsSetComposer( tags, md->composer ); - if( strlen( md->comment )) + if( md->comment ) MP4TagsSetComments( tags, md->comment ); - if( strlen( md->release_date )) + if( md->release_date ) MP4TagsSetReleaseDate( tags, md->release_date ); - if( strlen( md->album )) + if( md->album ) MP4TagsSetAlbum( tags, md->album ); - if( strlen( md->genre )) + if( md->album_artist ) + MP4TagsSetAlbumArtist( tags, md->album_artist ); + if( md->genre ) MP4TagsSetGenre( tags, md->genre ); + if( md->description ) + MP4TagsSetDescription( tags, md->description ); + if( md->long_description ) + MP4TagsSetLongDescription( tags, md->long_description ); - if( md->coverart ) + if( md->list_coverart ) { - MP4TagArtwork art; - art.data = md->coverart; - art.size = md->coverart_size; - art.type = MP4_ART_UNDEFINED; // delegate typing to libmp4v2 - MP4TagsAddArtwork( tags, &art ); + hb_coverart_t * coverart; + int ii; + + for ( ii = 0; ii < hb_list_count( md->list_coverart ); ii++ ) + { + coverart = hb_list_item( md->list_coverart, ii ); + MP4TagArtwork art; + int type; + switch ( coverart->type ) + { + case HB_ART_BMP: + type = MP4_ART_BMP; + break; + case HB_ART_GIF: + type = MP4_ART_GIF; + break; + case HB_ART_JPEG: + type = MP4_ART_JPEG; + break; + case HB_ART_PNG: + type = MP4_ART_PNG; + break; + default: + type = MP4_ART_UNDEFINED; + break; + } + art.data = coverart->data; + art.size = coverart->size; + art.type = type; + MP4TagsAddArtwork( tags, &art ); + } } /* push data to MP4 file */ diff --git a/libhb/reader.c b/libhb/reader.c index 8148e6590..d5c937422 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -386,12 +386,12 @@ void ReadLoop( void * _w ) * a media chapter that got merged, we'll stop ripping too early. */ int start = r->job->chapter_start; - hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 ); + hb_chapter_t *chap = hb_list_item( r->job->list_chapter, chapter_end - 1 ); chapter_end = chap->index; if (start > 1) { - chap = hb_list_item( r->title->list_chapter, start - 1 ); + chap = hb_list_item( r->job->list_chapter, start - 1 ); start = chap->index; } /* end chapter mapping XXX */ @@ -453,12 +453,12 @@ void ReadLoop( void * _w ) * end chapter so that we end at the right time. */ int start = r->job->chapter_start; - hb_chapter_t *chap = hb_list_item( r->title->list_chapter, chapter_end - 1 ); + hb_chapter_t *chap = hb_list_item( r->job->list_chapter, chapter_end - 1 ); chapter_end = chap->index; if (start > 1) { - chap = hb_list_item( r->title->list_chapter, start - 1 ); + chap = hb_list_item( r->job->list_chapter, start - 1 ); start = chap->index; } @@ -670,14 +670,14 @@ void ReadLoop( void * _w ) push_buf( r, r->job->fifo_mpeg2, hb_buffer_init(0) ); hb_audio_t *audio; - for( n = 0; (audio = hb_list_item( r->job->title->list_audio, n)); ++n ) + for( n = 0; (audio = hb_list_item( r->job->list_audio, n)); ++n ) { if ( audio->priv.fifo_in ) push_buf( r, audio->priv.fifo_in, hb_buffer_init(0) ); } hb_subtitle_t *subtitle; - for( n = 0; (subtitle = hb_list_item( r->job->title->list_subtitle, n)); ++n ) + for( n = 0; (subtitle = hb_list_item( r->job->list_subtitle, n)); ++n ) { if ( subtitle->fifo_in && subtitle->source == VOBSUB) push_buf( r, subtitle->fifo_in, hb_buffer_init(0) ); @@ -780,11 +780,11 @@ static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id ) } } - count = hb_list_count( title->list_subtitle ); + count = hb_list_count( job->list_subtitle ); count = count > 99 ? 99 : count; for( i = n = 0; i < count; i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if (id == subtitle->id) { /* pass the subtitles to be processed */ @@ -798,9 +798,9 @@ static hb_fifo_t ** GetFifoForId( hb_work_private_t * r, int id ) if( !job->indepth_scan ) { - for( i = n = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = n = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( id == audio->id ) { r->fifos[n++] = audio->priv.fifo_in; diff --git a/libhb/rendersub.c b/libhb/rendersub.c index 568b7d1b0..c9e9f02cf 100644 --- a/libhb/rendersub.c +++ b/libhb/rendersub.c @@ -441,7 +441,7 @@ static int ssa_init( hb_filter_object_t * filter, ass_set_message_cb( pv->ssa, ssa_log, NULL ); // Load embedded fonts - hb_list_t * list_attachment = init->job->title->list_attachment; + hb_list_t * list_attachment = init->job->list_attachment; int i; for ( i = 0; i < hb_list_count(list_attachment); i++ ) { @@ -678,9 +678,9 @@ static int hb_rendersub_init( hb_filter_object_t * filter, } // Find the subtitle we need - for( ii = 0; ii < hb_list_count(init->job->title->list_subtitle); ii++ ) + for( ii = 0; ii < hb_list_count(init->job->list_subtitle); ii++ ) { - subtitle = hb_list_item( init->job->title->list_subtitle, ii ); + subtitle = hb_list_item( init->job->list_subtitle, ii ); if( subtitle && subtitle->config.dest == RENDERSUB ) { // Found it diff --git a/libhb/scan.c b/libhb/scan.c index 10ed35391..0163af406 100644 --- a/libhb/scan.c +++ b/libhb/scan.c @@ -18,7 +18,7 @@ typedef struct char * path; int title_index; - hb_list_t * list_title; + hb_title_set_t * title_set; hb_bd_t * bd; hb_dvd_t * dvd; @@ -51,7 +51,7 @@ static const char *aspect_to_string( double aspect ) hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die, const char * path, int title_index, - hb_list_t * list_title, int preview_count, + hb_title_set_t * title_set, int preview_count, int store_previews, uint64_t min_duration ) { hb_scan_t * data = calloc( sizeof( hb_scan_t ), 1 ); @@ -60,7 +60,7 @@ hb_thread_t * hb_scan_init( hb_handle_t * handle, volatile int * die, data->die = die; data->path = strdup( path ); data->title_index = title_index; - data->list_title = list_title; + data->title_set = title_set; data->preview_count = preview_count; data->store_previews = store_previews; @@ -88,7 +88,8 @@ static void ScanFunc( void * _data ) if( data->title_index ) { /* Scan this title only */ - hb_list_add( data->list_title, hb_bd_title_scan( data->bd, + hb_list_add( data->title_set->list_title, + hb_bd_title_scan( data->bd, data->title_index, 0 ) ); } else @@ -96,10 +97,12 @@ static void ScanFunc( void * _data ) /* Scan all titles */ for( i = 0; i < hb_bd_title_count( data->bd ); i++ ) { - hb_list_add( data->list_title, hb_bd_title_scan( data->bd, + hb_list_add( data->title_set->list_title, + hb_bd_title_scan( data->bd, i + 1, data->min_title_duration ) ); } - feature = hb_bd_main_feature( data->bd, data->list_title ); + feature = hb_bd_main_feature( data->bd, + data->title_set->list_title ); } } else if( ( data->dvd = hb_dvd_init( data->path ) ) ) @@ -109,7 +112,8 @@ static void ScanFunc( void * _data ) if( data->title_index ) { /* Scan this title only */ - hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + hb_list_add( data->title_set->list_title, + hb_dvd_title_scan( data->dvd, data->title_index, 0 ) ); } else @@ -117,10 +121,12 @@ static void ScanFunc( void * _data ) /* Scan all titles */ for( i = 0; i < hb_dvd_title_count( data->dvd ); i++ ) { - hb_list_add( data->list_title, hb_dvd_title_scan( data->dvd, + hb_list_add( data->title_set->list_title, + hb_dvd_title_scan( data->dvd, i + 1, data->min_title_duration ) ); } - feature = hb_dvd_main_feature( data->dvd, data->list_title ); + feature = hb_dvd_main_feature( data->dvd, + data->title_set->list_title ); } } else if ( ( data->batch = hb_batch_init( data->path ) ) ) @@ -131,7 +137,7 @@ static void ScanFunc( void * _data ) title = hb_batch_title_scan( data->batch, data->title_index ); if ( title ) { - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } } else @@ -144,7 +150,7 @@ static void ScanFunc( void * _data ) title = hb_batch_title_scan( data->batch, i + 1 ); if ( title != NULL ) { - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } } } @@ -156,7 +162,7 @@ static void ScanFunc( void * _data ) { title = hb_stream_title_scan( data->stream, title ); if ( title ) - hb_list_add( data->list_title, title ); + hb_list_add( data->title_set->list_title, title ); } else { @@ -166,7 +172,7 @@ static void ScanFunc( void * _data ) } } - for( i = 0; i < hb_list_count( data->list_title ); ) + for( i = 0; i < hb_list_count( data->title_set->list_title ); ) { int j; hb_state_t state; @@ -176,7 +182,7 @@ static void ScanFunc( void * _data ) { goto finish; } - title = hb_list_item( data->list_title, i ); + title = hb_list_item( data->title_set->list_title, i ); #define p state.param.scanning /* Update the UI */ @@ -185,7 +191,7 @@ static void ScanFunc( void * _data ) p.title_count = data->dvd ? hb_dvd_title_count( data->dvd ) : data->bd ? hb_bd_title_count( data->bd ) : data->batch ? hb_batch_title_count( data->batch ) : - hb_list_count(data->list_title); + hb_list_count(data->title_set->list_title); hb_set_state( data->h, &state ); #undef p @@ -194,7 +200,7 @@ static void ScanFunc( void * _data ) if( !DecodePreviews( data, title ) ) { /* TODO: free things */ - hb_list_rem( data->list_title, title ); + hb_list_rem( data->title_set->list_title, title ); for( j = 0; j < hb_list_count( title->list_audio ); j++) { audio = hb_list_item( title->list_audio, j ); @@ -247,64 +253,16 @@ static void ScanFunc( void * _data ) i++; } - /* Init jobs templates */ - for( i = 0; i < hb_list_count( data->list_title ); i++ ) - { - hb_job_t * job; - - title = hb_list_item( data->list_title, i ); - job = calloc( sizeof( hb_job_t ), 1 ); - title->job = job; - - job->title = title; - job->feature = feature; + data->title_set->feature = feature; - /* Set defaults settings */ - job->chapter_start = 1; - job->chapter_end = hb_list_count( title->list_chapter ); - - /* Autocrop by default. Gnark gnark */ - memcpy( job->crop, title->crop, 4 * sizeof( int ) ); - - /* Preserve a source's pixel aspect, if it's available. */ - if( title->pixel_aspect_width && title->pixel_aspect_height ) - { - job->anamorphic.par_width = title->pixel_aspect_width; - job->anamorphic.par_height = title->pixel_aspect_height; - } - - if( title->aspect != 0 && title->aspect != 1. && - !job->anamorphic.par_width && !job->anamorphic.par_height) - { - hb_reduce( &job->anamorphic.par_width, &job->anamorphic.par_height, - (int)(title->aspect * title->height + 0.5), title->width ); - } - - job->width = title->width - job->crop[2] - job->crop[3]; - hb_fix_aspect( job, HB_KEEP_WIDTH ); - if( job->height > title->height - job->crop[0] - job->crop[1] ) - { - job->height = title->height - job->crop[0] - job->crop[1]; - hb_fix_aspect( job, HB_KEEP_HEIGHT ); - } - - hb_log( "scan: title (%d) job->width:%d, job->height:%d", - i, job->width, job->height ); - - job->keep_ratio = 1; - - job->vcodec = HB_VCODEC_FFMPEG_MPEG4; - job->vquality = -1.0; - job->vbitrate = 1000; - job->pass = 0; - job->vrate = title->rate; - job->vrate_base = title->rate_base; - - job->list_audio = hb_list_init(); - job->list_subtitle = hb_list_init(); - job->list_filter = hb_list_init(); - - job->mux = HB_MUX_MP4; + /* Mark title scan complete and init jobs */ + for( i = 0; i < hb_list_count( data->title_set->list_title ); i++ ) + { + title = hb_list_item( data->title_set->list_title, i ); + title->flags |= HBTF_SCAN_COMPLETE; +#if defined(HB_TITLE_JOBS) + title->job = hb_job_init( title ); +#endif } finish: diff --git a/libhb/stream.c b/libhb/stream.c index ede9f33d3..503e296dc 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -960,11 +960,10 @@ hb_stream_t * hb_bd_stream_open( hb_title_t *title ) update_ts_streams( d, pid, 0, stream_type, S, NULL ); } - // When scanning, title->job == NULL. We don't need to wait for - // a PCR when scanning. In fact, it trips us up on the first - // preview of every title since we would have to read quite a - // lot of data before finding the PCR. - if ( title->job ) + // We don't need to wait for a PCR when scanning. In fact, it + // trips us up on the first preview of every title since we would + // have to read quite a lot of data before finding the PCR. + if ( !(title->flags & HBTF_SCAN_COMPLETE) ) { /* BD has PCRs, but the BD index always points to a packet * after a PCR packet, so we will not see the initial PCR @@ -2774,7 +2773,6 @@ int decode_program_map(hb_stream_t* stream) stream->pmt_info.PCR_PID = bits_get(&bb, 13); bits_get(&bb, 4); int program_info_length = bits_get(&bb, 12); - int i; for (i = 0; i < program_info_length - 2; ) { @@ -5371,6 +5369,7 @@ static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id static char *get_ffmpeg_metadata_value( AVDictionary *m, char *key ) { AVDictionaryEntry *tag = NULL; + while ( (tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)) ) { if ( !strcmp( key, tag->key ) ) @@ -5425,6 +5424,64 @@ static void add_ffmpeg_attachment( hb_title_t *title, hb_stream_t *stream, int i hb_list_add(title->list_attachment, attachment); } +static int ffmpeg_decmetadata( AVDictionary *m, hb_title_t *title ) +{ + int result = 0; + AVDictionaryEntry *tag = NULL; + while ( (tag = av_dict_get(m, "", tag, AV_DICT_IGNORE_SUFFIX)) ) + { + if ( !strcasecmp( "TITLE", tag->key ) ) + { + hb_metadata_set_name(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "ARTIST", tag->key ) ) + { + hb_metadata_set_artist(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DIRECTOR", tag->key ) || + !strcasecmp( "album_artist", tag->key ) ) + { + hb_metadata_set_album_artist(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "COMPOSER", tag->key ) ) + { + hb_metadata_set_composer(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DATE_RELEASED", tag->key ) || + !strcasecmp( "date", tag->key ) ) + { + hb_metadata_set_release_date(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "SUMMARY", tag->key ) || + !strcasecmp( "comment", tag->key ) ) + { + hb_metadata_set_comment(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "GENRE", tag->key ) ) + { + hb_metadata_set_genre(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "DESCRIPTION", tag->key ) ) + { + hb_metadata_set_description(title->metadata, tag->value); + result = 1; + } + else if ( !strcasecmp( "SYNOPSIS", tag->key ) ) + { + hb_metadata_set_long_description(title->metadata, tag->value); + result = 1; + } + } + return result; +} + static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) { AVFormatContext *ic = stream->ffmpeg_ic; @@ -5520,16 +5577,20 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) chapter->seconds = ( seconds % 60 ); tag = av_dict_get( m->metadata, "title", NULL, 0 ); - /* Ignore generic chapter names set by MakeMKV ("Chapter 00" etc.). + /* Ignore generic chapter names set by MakeMKV + * ("Chapter 00" etc.). * Our default chapter names are better. */ if( tag && tag->value && - ( strncmp( "Chapter ", tag->value, 8 ) || strlen( tag->value ) > 11 ) ) + ( strncmp( "Chapter ", tag->value, 8 ) || + strlen( tag->value ) > 11 ) ) { - strcpy( chapter->title, tag->value ); + hb_chapter_set_title( chapter, tag->value ); } else { - sprintf( chapter->title, "Chapter %d", chapter->index ); + char chapter_title[80]; + sprintf( chapter_title, "Chapter %d", chapter->index ); + hb_chapter_set_title( chapter, chapter_title ); } hb_deep_log( 2, "Added chapter %i, name='%s', dur=%"PRIu64", (%02i:%02i:%02i)", @@ -5543,7 +5604,11 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) /* * Fill the metadata. */ - decmetadata( title ); + // JJJ: is this necessary? can we just get this metadata from libav api's? + if (!decmetadata( title )) + { + ffmpeg_decmetadata( ic->metadata, title ); + } if( hb_list_count( title->list_chapter ) == 0 ) { @@ -5787,16 +5852,25 @@ hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream ) static int ffmpeg_seek( hb_stream_t *stream, float frac ) { AVFormatContext *ic = stream->ffmpeg_ic; + int res; if ( frac > 0. ) { int64_t pos = (double)stream->ffmpeg_ic->duration * (double)frac + ffmpeg_initial_timestamp( stream ); - avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + res = avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + if (res < 0) + { + hb_error("avformat_seek_file failed"); + } } else { int64_t pos = ffmpeg_initial_timestamp( stream ); - avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + res = avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); + if (res < 0) + { + hb_error("avformat_seek_file failed"); + } } stream->need_keyframe = 1; return 1; diff --git a/libhb/sync.c b/libhb/sync.c index c3e4c37a1..f416d1664 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -167,7 +167,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job ) duration = 0; for( i = job->chapter_start; i <= job->chapter_end; i++ ) { - chapter = hb_list_item( title->list_chapter, i - 1 ); + chapter = hb_list_item( job->list_chapter, i - 1 ); duration += chapter->duration; } } @@ -179,7 +179,7 @@ hb_work_object_t * hb_sync_init( hb_job_t * job ) /* Initialize libsamplerate for every audio track we have */ if ( ! job->indepth_scan ) { - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { InitAudio( job, pv->common, i ); } @@ -892,7 +892,6 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) { hb_work_object_t * w; hb_work_private_t * pv; - hb_title_t * title = job->title; hb_sync_audio_t * sync; pv = calloc( 1, sizeof( hb_work_private_t ) ); @@ -905,7 +904,7 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) w = hb_get_work( WORK_SYNC_AUDIO ); w->private_data = pv; - w->audio = hb_list_item( title->list_audio, i ); + w->audio = hb_list_item( job->list_audio, i ); w->fifo_in = w->audio->priv.fifo_raw; if ( w->audio->config.out.codec & HB_ACODEC_PASS_FLAG ) diff --git a/libhb/work.c b/libhb/work.c index 277ebf033..030920c59 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -389,9 +389,9 @@ void hb_display_job_info( hb_job_t * job ) job->select_subtitle_config.default_track ? ", Default" : "" ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { @@ -425,9 +425,9 @@ void hb_display_job_info( hb_job_t * job ) if( !job->indepth_scan ) { - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); hb_log( " * audio track %d", audio->config.out.track ); @@ -529,6 +529,7 @@ static void do_job( hb_job_t * job ) hb_work_object_t * w; hb_work_object_t * sync; hb_work_object_t * muxer; + hb_work_object_t *reader = hb_get_work(WORK_READER); hb_interjob_t * interjob; hb_audio_t * audio; @@ -563,21 +564,25 @@ static void do_job( hb_job_t * job ) { interjob->select_subtitle->config.force = 0; } - for( i = 0; i < hb_list_count(title->list_subtitle); ) + for( i = 0; i < hb_list_count( job->list_subtitle ); ) { - if( ( subtitle = hb_list_item( title->list_subtitle, i ) ) ) + subtitle = hb_list_item( job->list_subtitle, i ); + if( subtitle ) { - /* Remove the scanned subtitle from the list if it would result in: + /* Remove the scanned subtitle from the list if + * it would result in: * - an emty track (forced and no forced hits) * - an identical, duplicate subtitle track: * -> both (or neither) are forced * -> subtitle is not forced but all its hits are forced */ if( ( interjob->select_subtitle->id == subtitle->id ) && - ( ( subtitle->config.force && interjob->select_subtitle->forced_hits == 0 ) || + ( ( subtitle->config.force && + interjob->select_subtitle->forced_hits == 0 ) || ( subtitle->config.force == interjob->select_subtitle->config.force ) || - ( subtitle->config.force == 0 && interjob->select_subtitle->hits == interjob->select_subtitle->forced_hits ) ) ) + ( !subtitle->config.force && + interjob->select_subtitle->hits == interjob->select_subtitle->forced_hits ) ) ) { - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -602,13 +607,13 @@ static void do_job( hb_job_t * job ) if (job->pass == 0 || job->pass == 2) { // final pass, interjob->select_subtitle is no longer needed - hb_list_insert(title->list_subtitle, 0, interjob->select_subtitle); + hb_list_insert(job->list_subtitle, 0, interjob->select_subtitle); interjob->select_subtitle = NULL; } else { // this is not the final pass, so we need to copy it instead - hb_list_insert(title->list_subtitle, 0, hb_subtitle_copy(interjob->select_subtitle)); + hb_list_insert(job->list_subtitle, 0, hb_subtitle_copy(interjob->select_subtitle)); } } @@ -616,10 +621,9 @@ static void do_job( hb_job_t * job ) { // Sanitize subtitles uint8_t one_burned = 0; - for( i = 0; i < hb_list_count( title->list_subtitle ); ) + for( i = 0; i < hb_list_count( job->list_subtitle ); ) { - subtitle = hb_list_item( title->list_subtitle, i ); - + subtitle = hb_list_item( job->list_subtitle, i ); if ( subtitle->config.dest == RENDERSUB ) { if ( one_burned ) @@ -627,7 +631,7 @@ static void do_job( hb_job_t * job ) if ( !hb_subtitle_can_pass(subtitle->source, job->mux) ) { hb_log( "More than one subtitle burn-in requested, dropping track %d.", i ); - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -661,7 +665,7 @@ static void do_job( hb_job_t * job ) else { hb_log( "Subtitle pass-thru requested and input track is not compatible with container. One track already burned, dropping track %d.", i ); - hb_list_rem( title->list_subtitle, subtitle ); + hb_list_rem( job->list_subtitle, subtitle ); free( subtitle ); continue; } @@ -697,9 +701,9 @@ static void do_job( hb_job_t * job ) init.height = title->height; init.par_width = job->anamorphic.par_width; init.par_height = job->anamorphic.par_height; - memcpy(init.crop, title->crop, sizeof(int[4])); - init.vrate_base = title->rate_base; - init.vrate = title->rate; + memcpy(init.crop, job->crop, sizeof(int[4])); + init.vrate_base = job->vrate_base; + init.vrate = job->vrate; init.pfr_vrate_base = job->pfr_vrate_base; init.pfr_vrate = job->pfr_vrate; init.cfr = 0; @@ -720,7 +724,7 @@ static void do_job( hb_job_t * job ) job->height = init.height; job->anamorphic.par_width = init.par_width; job->anamorphic.par_height = init.par_height; - memcpy(title->crop, init.crop, sizeof(int[4])); + memcpy(job->crop, init.crop, sizeof(int[4])); job->vrate_base = init.vrate_base; job->vrate = init.vrate; job->pfr_vrate_base = init.pfr_vrate_base; @@ -761,18 +765,18 @@ static void do_job( hb_job_t * job ) if (!job->indepth_scan) { // apply Auto Passthru settings - hb_autopassthru_apply_settings(job, title); + hb_autopassthru_apply_settings(job); // sanitize audio settings - for (i = 0; i < hb_list_count(title->list_audio);) + for (i = 0; i < hb_list_count(job->list_audio);) { - audio = hb_list_item(title->list_audio, i); + audio = hb_list_item(job->list_audio, i); if (audio->config.out.codec == HB_ACODEC_AUTO_PASS) { // Auto Passthru should have been handled above // remove track to avoid a crash hb_log("Auto Passthru error, dropping track %d", audio->config.out.track); - hb_list_rem(title->list_audio, audio); + hb_list_rem(job->list_audio, audio); free(audio); continue; } @@ -782,7 +786,7 @@ static void do_job( hb_job_t * job ) { hb_log("Passthru requested and input codec is not the same as output codec for track %d, dropping track", audio->config.out.track); - hb_list_rem(title->list_audio, audio); + hb_list_rem(job->list_audio, audio); free(audio); continue; } @@ -796,9 +800,9 @@ static void do_job( hb_job_t * job ) int best_bitrate = 0; int best_samplerate = 0; - for (i = 0; i < hb_list_count(title->list_audio); i++) + for (i = 0; i < hb_list_count(job->list_audio); i++) { - audio = hb_list_item(title->list_audio, i); + audio = hb_list_item(job->list_audio, i); /* set up the audio work structures */ audio->priv.fifo_raw = hb_fifo_init(FIFO_SMALL, FIFO_SMALL_WAKE); @@ -999,9 +1003,9 @@ static void do_job( hb_job_t * job ) w->fifo_in = job->fifo_mpeg2; w->fifo_out = job->fifo_raw; - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { @@ -1081,9 +1085,9 @@ static void do_job( hb_job_t * job ) hb_list_add( job->list_work, w ); - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); /* * Audio Decoder Thread @@ -1140,7 +1144,6 @@ static void do_job( hb_job_t * job ) hb_display_job_info( job ); /* Init read & write threads */ - hb_work_object_t *reader = hb_get_work(WORK_READER); if ( reader->init( reader, job ) ) { hb_error( "Failure to initialise thread '%s'", reader->name ); @@ -1330,9 +1333,9 @@ cleanup: hb_fifo_close( &job->fifo_sync ); hb_fifo_close( &job->fifo_mpeg4 ); - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle ) { hb_fifo_close( &subtitle->fifo_in ); @@ -1341,9 +1344,9 @@ cleanup: hb_fifo_close( &subtitle->fifo_out ); } } - for( i = 0; i < hb_list_count( title->list_audio ); i++ ) + for( i = 0; i < hb_list_count( job->list_audio ); i++ ) { - audio = hb_list_item( title->list_audio, i ); + audio = hb_list_item( job->list_audio, i ); if( audio->priv.fifo_in != NULL ) hb_fifo_close( &audio->priv.fifo_in ); if( audio->priv.fifo_raw != NULL ) @@ -1354,13 +1357,22 @@ cleanup: hb_fifo_close( &audio->priv.fifo_out ); } + if( job->list_filter ) + { + for( i = 0; i < hb_list_count( job->list_filter ); i++ ) + { + hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); + hb_fifo_close( &filter->fifo_out ); + } + } + if( job->indepth_scan ) { /* Before closing the title print out our subtitle stats if we need to * find the highest and lowest. */ - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); hb_log( "Subtitle track %d (id 0x%x) '%s': %d hits (%d forced)", subtitle->track, subtitle->id, subtitle->lang, @@ -1415,34 +1427,23 @@ cleanup: hb_log( "No candidate detected during subtitle scan" ); } - for( i = 0; i < hb_list_count( title->list_subtitle ); i++ ) + for( i = 0; i < hb_list_count( job->list_subtitle ); i++ ) { - subtitle = hb_list_item( title->list_subtitle, i ); + subtitle = hb_list_item( job->list_subtitle, i ); if( subtitle->id == subtitle_hit ) { subtitle->config = job->select_subtitle_config; - hb_list_rem( title->list_subtitle, subtitle ); + // Remove from list since we are taking ownership + // of the subtitle. + hb_list_rem( job->list_subtitle, subtitle ); interjob->select_subtitle = subtitle; break; } } } - if( job->list_filter ) - { - for( i = 0; i < hb_list_count( job->list_filter ); i++ ) - { - hb_filter_object_t * filter = hb_list_item( job->list_filter, i ); - hb_fifo_close( &filter->fifo_out ); - hb_filter_close( &filter ); - } - hb_list_close( &job->list_filter ); - } - hb_buffer_pool_free(); - - hb_title_close( &job->title ); - free( job ); + hb_job_close( &job ); } static inline void copy_chapter( hb_buffer_t * dst, hb_buffer_t * src ) |