X-Git-Url: http://git.osdn.jp/view?a=blobdiff_plain;f=libhb%2Fwork.c;h=752839bce0b7259dee24817f7462cb51ff60e630;hb=1c9c75d452c8d15ee972b4c4612763f9b95b1790;hp=c283f22a13deec08f52b099439fb15d2ef859e82;hpb=eb1c445d2a317c8beeaa3573cd8e6031b97b3fae;p=handbrake-jp%2Fhandbrake-jp-git.git diff --git a/libhb/work.c b/libhb/work.c index c283f22a..752839bc 100644 --- a/libhb/work.c +++ b/libhb/work.c @@ -7,6 +7,7 @@ #include "hb.h" #include "a52dec/a52.h" #include "dca.h" +#include "libavformat/avformat.h" typedef struct { @@ -105,6 +106,7 @@ hb_work_object_t * hb_codec_encoder( int codec ) case HB_ACODEC_FAAC: return hb_get_work( WORK_ENCFAAC ); case HB_ACODEC_LAME: return hb_get_work( WORK_ENCLAME ); case HB_ACODEC_VORBIS: return hb_get_work( WORK_ENCVORBIS ); + case HB_ACODEC_CA_AAC: return hb_get_work( WORK_ENC_CA_AAC ); } return NULL; } @@ -113,7 +115,7 @@ hb_work_object_t * hb_codec_encoder( int codec ) * Displays job parameters in the debug log. * @param job Handle work hb_job_t. */ -hb_display_job_info( hb_job_t * job ) +void hb_display_job_info( hb_job_t * job ) { hb_title_t * title = job->title; hb_audio_t * audio; @@ -153,6 +155,9 @@ hb_display_job_info( hb_job_t * job ) if( job->mp4_optimize ) hb_log( " + optimized for progressive web downloads"); + + if( job->color_matrix ) + hb_log( " + custom color matrix: %s", job->color_matrix == 1 ? "ITU Bt.601 (SD)" : "ITU Bt.709 (HD)"); break; case HB_MUX_AVI: @@ -182,31 +187,42 @@ hb_display_job_info( hb_job_t * job ) hb_log( " + bitrate %d kbps", title->video_bitrate / 1000 ); } - if( job->vfr) - { - hb_log( " + frame rate: %.3f fps -> variable fps", - (float) title->rate / (float) title->rate_base ); - } - else if( !job->cfr ) + if( !job->cfr ) { hb_log( " + frame rate: same as source (around %.3f fps)", (float) title->rate / (float) title->rate_base ); } else { - hb_log( " + frame rate: %.3f fps -> constant %.3f fps", - (float) title->rate / (float) title->rate_base, (float) job->vrate / (float) job->vrate_base ); + static const char *frtypes[] = { + "", "constant", "peak rate limited to" + }; + hb_log( " + frame rate: %.3f fps -> %s %.3f fps", + (float) title->rate / (float) title->rate_base, frtypes[job->cfr], + (float) job->vrate / (float) job->vrate_base ); } - if( job->pixel_ratio ) + if( job->anamorphic.mode ) { - hb_log( " + %s anamorphic", job->pixel_ratio == 1 ? "strict" : "loose" ); + hb_log( " + %s anamorphic", job->anamorphic.mode == 1 ? "strict" : job->anamorphic.mode == 2? "loose" : "custom" ); + if( job->anamorphic.mode == 3 && job->anamorphic.keep_display_aspect ) + { + hb_log( " + keeping source display aspect ratio"); + } + if( job->anamorphic.modulus != 16 ) + { + hb_log( " + modulus: %i", job->anamorphic.modulus ); + } hb_log( " + storage dimensions: %d * %d -> %d * %d, crop %d/%d/%d/%d", title->width, title->height, job->width, job->height, job->crop[0], job->crop[1], job->crop[2], job->crop[3] ); - hb_log( " + pixel aspect ratio: %i / %i", job->pixel_aspect_width, job->pixel_aspect_height ); + if( job->anamorphic.itu_par ) + { + hb_log( " + using ITU pixel aspect ratio values"); + } + hb_log( " + pixel aspect ratio: %i / %i", job->anamorphic.par_width, job->anamorphic.par_height ); hb_log( " + display dimensions: %.0f * %i", - (float)( job->width * job->pixel_aspect_width / job->pixel_aspect_height ), job->height ); + (float)( job->width * job->anamorphic.par_width / job->anamorphic.par_height ), job->height ); } else { @@ -240,10 +256,6 @@ hb_display_job_info( hb_job_t * job ) hb_log( " + encoder: FFmpeg" ); break; - case HB_VCODEC_XVID: - hb_log( " + encoder: XviD" ); - break; - case HB_VCODEC_X264: hb_log( " + encoder: x264" ); if( job->x264opts != NULL && *job->x264opts != '\0' ) @@ -261,7 +273,7 @@ hb_display_job_info( hb_job_t * job ) } else if( job->vquality > 1 ) { - hb_log( " + quality: %.0f %s", job->vquality, job->crf && job->vcodec == HB_VCODEC_X264 ? "(RF)" : "(QP)" ); + hb_log( " + quality: %.2f %s", job->vquality, job->crf && job->vcodec == HB_VCODEC_X264 ? "(RF)" : "(QP)" ); } else { @@ -269,13 +281,18 @@ hb_display_job_info( hb_job_t * job ) } } - for( i=0; i < hb_list_count(title->list_subtitle); i++ ) + for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) { subtitle = hb_list_item( title->list_subtitle, i ); if( subtitle ) { - hb_log( " * subtitle track %i, %s (id %x)", job->subtitle+1, subtitle->lang, subtitle->id); + hb_log( " * subtitle track %i, %s (id %x) %s [%s] -> %s ", subtitle->track, subtitle->lang, subtitle->id, + subtitle->format == PICTURESUB ? "Picture" : "Text", + subtitle->source == VOBSUB ? "VOBSUB" : + ((subtitle->source == CC608SUB || + subtitle->source == CC708SUB) ? "CC" : "SRT"), + subtitle->config.dest == RENDERSUB ? "Render/Burn in" : "Pass-Through"); } } @@ -286,23 +303,29 @@ hb_display_job_info( hb_job_t * job ) audio = hb_list_item( title->list_audio, i ); hb_log( " * audio track %d", audio->config.out.track ); + + if( audio->config.out.name ) + hb_log( " + name: %s", audio->config.out.name ); - hb_log( " + decoder: %s (track %d, id %x)", audio->config.lang.description, audio->config.in.track, audio->id ); + hb_log( " + decoder: %s (track %d, id %x)", audio->config.lang.description, audio->config.in.track + 1, audio->id ); if( ( audio->config.in.codec == HB_ACODEC_AC3 ) || ( audio->config.in.codec == HB_ACODEC_DCA) ) { hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.in.bitrate / 1000, audio->config.in.samplerate ); } - for (j = 0; j < hb_audio_mixdowns_count; j++) + if( (audio->config.out.codec != HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_DCA) ) { - if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown) { - hb_log( " + mixdown: %s", hb_audio_mixdowns[j].human_readable_name ); - break; + for (j = 0; j < hb_audio_mixdowns_count; j++) + { + if (hb_audio_mixdowns[j].amixdown == audio->config.out.mixdown) { + hb_log( " + mixdown: %s", hb_audio_mixdowns[j].human_readable_name ); + break; + } } } - if ( audio->config.out.dynamic_range_compression > 1 && (audio->config.out.codec != HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_DCA)) + if ( audio->config.out.dynamic_range_compression && (audio->config.out.codec != HB_ACODEC_AC3) && (audio->config.out.codec != HB_ACODEC_DCA)) { hb_log(" + dynamic range compression: %f", audio->config.out.dynamic_range_compression); } @@ -315,14 +338,35 @@ hb_display_job_info( hb_job_t * job ) else { hb_log( " + encoder: %s", ( audio->config.out.codec == HB_ACODEC_FAAC ) ? - "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? "lame" : - "vorbis" ) ); + "faac" : ( ( audio->config.out.codec == HB_ACODEC_LAME ) ? + "lame" : ( ( audio->config.out.codec == HB_ACODEC_CA_AAC ) ? + "ca_aac" : "vorbis" ) ) ); hb_log( " + bitrate: %d kbps, samplerate: %d Hz", audio->config.out.bitrate, audio->config.out.samplerate ); } } } } +/* Corrects framerates when actual duration and frame count numbers are known. */ +void correct_framerate( hb_job_t * job ) +{ + int real_frames; + + hb_interjob_t * interjob = hb_interjob_get( job->h ); + + if( ( job->sequence_id & 0xFFFFFF ) != ( interjob->last_job & 0xFFFFFF) ) + return; // Interjob information is for a different encode. + + /* Cache the original framerate before altering it. */ + interjob->vrate = job->vrate; + interjob->vrate_base = job->vrate_base; + + real_frames = interjob->frame_count - interjob->render_dropped; + + job->vrate = job->vrate_base * ( (double)real_frames * 90000 / interjob->total_time ); +} + + /** * Job initialization rountine. * Initializes fifos. @@ -339,6 +383,7 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_title_t * title; int i, j; hb_work_object_t * w; + hb_interjob_t * interjob; hb_audio_t * audio; hb_subtitle_t * subtitle; @@ -350,50 +395,47 @@ static void do_job( hb_job_t * job, int cpu_count ) unsigned int subtitle_hit = 0; title = job->title; + interjob = hb_interjob_get( job->h ); + + if( job->pass == 2 && !job->cfr ) + { + correct_framerate( job ); + } job->list_work = hb_list_init(); hb_log( "starting job" ); - if ( job->pixel_ratio == 1 ) - { - /* Correct the geometry of the output movie when using PixelRatio */ - job->height=title->height-job->crop[0]-job->crop[1]; - job->width=title->width-job->crop[2]-job->crop[3]; - } - else if ( job->pixel_ratio == 2 ) + if( job->anamorphic.mode ) { + hb_set_anamorphic_size(job, &job->width, &job->height, &job->anamorphic.par_width, &job->anamorphic.par_height); - /* While keeping the DVD storage aspect, resize the job width and height - so they fit into the user's specified dimensions. */ - hb_set_anamorphic_size(job, &job->width, &job->height, &job->pixel_aspect_width, &job->pixel_aspect_height); - } - - if( job->pixel_ratio && job->vcodec == HB_VCODEC_FFMPEG) - { - /* Just to make working with ffmpeg even more fun, - lavc's MPEG-4 encoder can't handle PAR values >= 255, - even though AVRational does. Adjusting downwards - distorts the display aspect slightly, but such is life. */ - while ((job->pixel_aspect_width & ~0xFF) || - (job->pixel_aspect_height & ~0xFF)) + if( job->vcodec == HB_VCODEC_FFMPEG ) { - job->pixel_aspect_width >>= 1; - job->pixel_aspect_height >>= 1; + /* Just to make working with ffmpeg even more fun, + lavc's MPEG-4 encoder can't handle PAR values >= 255, + even though AVRational does. Adjusting downwards + distorts the display aspect slightly, but such is life. */ + while ((job->anamorphic.par_width & ~0xFF) || + (job->anamorphic.par_height & ~0xFF)) + { + job->anamorphic.par_width >>= 1; + job->anamorphic.par_height >>= 1; + } } } - + /* Keep width and height within these boundaries, but ignore for anamorphic. For "loose" anamorphic encodes, this stuff is covered in the pixel_ratio section above. */ - if ( job->maxHeight && ( job->height > job->maxHeight ) && ( !job->pixel_ratio ) ) + if ( job->maxHeight && ( job->height > job->maxHeight ) && ( !job->anamorphic.mode ) ) { job->height = job->maxHeight; hb_fix_aspect( job, HB_KEEP_HEIGHT ); hb_log( "Height out of bounds, scaling down to %i", job->maxHeight ); hb_log( "New dimensions %i * %i", job->width, job->height ); } - if ( job->maxWidth && ( job->width > job->maxWidth ) && ( !job->pixel_ratio ) ) + if ( job->maxWidth && ( job->width > job->maxWidth ) && ( !job->anamorphic.mode ) ) { job->width = job->maxWidth; hb_fix_aspect( job, HB_KEEP_WIDTH ); @@ -401,16 +443,19 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_log( "New dimensions %i * %i", job->width, job->height ); } - if( ( job->mux & HB_MUX_AVI ) || job->cfr ) + if( job->mux & HB_MUX_AVI ) { - /* VFR detelecine is not compatible with AVI or constant frame rates. */ - job->vfr = 0; + // The concept of variable frame rate video was a bit too advanced + // for Microsoft so AVI doesn't support it. Since almost all dvd + // video is VFR we have to convert it to constant frame rate to + // put it in an AVI container. So duplicate, drop and + // otherwise trash video frames to appease the gods of Redmond. + job->cfr = 1; } - if ( job->vfr ) + if ( job->cfr == 0 ) { - /* Ensure we're using "Same as source" FPS, - aka VFR, if we're doing VFR detelecine. */ + /* Ensure we're using "Same as source" FPS */ job->vrate_base = title->rate_base; } @@ -446,9 +491,6 @@ static void do_job( hb_job_t * job, int cpu_count ) case HB_VCODEC_FFMPEG: w = hb_get_work( WORK_ENCAVCODEC ); break; - case HB_VCODEC_XVID: - w = hb_get_work( WORK_ENCXVID ); - break; case HB_VCODEC_X264: w = hb_get_work( WORK_ENCX264 ); break; @@ -463,51 +505,112 @@ static void do_job( hb_job_t * job, int cpu_count ) hb_list_add( job->list_work, w ); } - if( job->select_subtitle && !job->indepth_scan ) + /* + * Look for the scanned subtitle in the existing subtitle list + */ + if ( !job->indepth_scan && interjob->select_subtitle && + ( job->pass == 0 || job->pass == 2 ) ) { /* - * Must be second pass of a two pass with subtitle scan enabled, so - * add the subtitle that we found on the first pass for use in this - * pass. + * Disable forced subtitles if we didn't find any in the scan + * so that we display normal subtitles instead. + * + * select_subtitle implies that we did a scan. */ - if (*(job->select_subtitle)) + if( interjob->select_subtitle->config.force && + interjob->select_subtitle->forced_hits == 0 ) + { + interjob->select_subtitle->config.force = 0; + } + for( i=0; i < hb_list_count(title->list_subtitle); i++ ) { - hb_list_add( title->list_subtitle, *( job->select_subtitle ) ); + subtitle = hb_list_item( title->list_subtitle, i ); + + if( subtitle ) + { + /* + * Disable forced subtitles if we didn't find any in the scan + * so that we display normal subtitles instead. + * + * select_subtitle implies that we did a scan. + */ + if( interjob->select_subtitle->id == subtitle->id ) + { + *subtitle = *(interjob->select_subtitle); + free( interjob->select_subtitle ); + interjob->select_subtitle = NULL; + } + } + } + + if( interjob->select_subtitle ) + { + /* + * Its not in the existing list + * + * Must be second pass of a two pass with subtitle scan enabled, so + * add the subtitle that we found on the first pass for use in this + * pass. + */ + hb_list_add( title->list_subtitle, interjob->select_subtitle ); + interjob->select_subtitle = NULL; } } + for( i=0; i < hb_list_count(title->list_subtitle); i++ ) { subtitle = hb_list_item( title->list_subtitle, i ); if( subtitle ) { - subtitle->fifo_in = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); - subtitle->fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); - - /* - * Disable forced subtitles if we didn't find any in the scan - * so that we display normal subtitles instead. - * - * select_subtitle implies that we did a scan. - */ - if( !job->indepth_scan && job->subtitle_force && - job->select_subtitle ) - { - if( subtitle->forced_hits == 0 ) - { - job->subtitle_force = 0; - } - } + subtitle->fifo_in = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); + subtitle->fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); + subtitle->fifo_sync = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); + subtitle->fifo_out = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); - if (!job->indepth_scan || job->subtitle_force) { + if( (!job->indepth_scan || job->select_subtitle_config.force) && + subtitle->source == VOBSUB ) { /* * Don't add threads for subtitles when we are scanning, unless * looking for forced subtitles. */ - w = hb_get_work( WORK_DECSUB ); + w = hb_get_work( WORK_DECVOBSUB ); + w->fifo_in = subtitle->fifo_in; + w->fifo_out = subtitle->fifo_raw; + w->subtitle = subtitle; + hb_list_add( job->list_work, w ); + } + + if( !job->indepth_scan && subtitle->source == CC608SUB ) + { + w = hb_get_work( WORK_DECCC608 ); + w->fifo_in = subtitle->fifo_in; + w->fifo_out = subtitle->fifo_raw; + hb_list_add( job->list_work, w ); + } + + if( !job->indepth_scan && subtitle->source == SRTSUB ) + { + w = hb_get_work( WORK_DECSRTSUB ); w->fifo_in = subtitle->fifo_in; w->fifo_out = subtitle->fifo_raw; + w->subtitle = subtitle; + hb_list_add( job->list_work, w ); + } + + if( !job->indepth_scan && + subtitle->format == PICTURESUB + && subtitle->config.dest == PASSTHRUSUB ) + { + /* + * Passing through a subtitle picture, this will have to + * be rle encoded before muxing. + */ + w = hb_get_work( WORK_ENCVOBSUB ); + w->fifo_in = subtitle->fifo_sync; + w->fifo_out = subtitle->fifo_out; + w->subtitle = subtitle; hb_list_add( job->list_work, w ); } } @@ -515,9 +618,14 @@ static void do_job( hb_job_t * job, int cpu_count ) if( !job->indepth_scan ) { - /* if we are doing passthru, and the input codec is not the same as the output - * codec, then remove this audio from the job */ - /* otherwise, Bad Things will happen */ + // if we are doing passthru, and the input codec is not the same as the output + // codec, then remove this audio from the job. If we're not doing passthru and + // the input codec is the 'internal' ffmpeg codec, make sure that only one + // audio references that audio stream since the codec context is specific to + // the audio id & multiple copies of the same stream will garble the audio + // or cause aborts. + uint8_t aud_id_uses[MAX_STREAMS]; + memset( aud_id_uses, 0, sizeof(aud_id_uses) ); for( i = 0; i < hb_list_count( title->list_audio ); ) { audio = hb_list_item( title->list_audio, i ); @@ -530,6 +638,18 @@ static void do_job( hb_job_t * job, int cpu_count ) free( audio ); continue; } + if ( audio->config.in.codec == HB_ACODEC_FFMPEG ) + { + if ( aud_id_uses[audio->id] ) + { + hb_log( "Multiple decodes of audio id %d, removing track %d", + audio->id, audio->config.out.track ); + hb_list_rem( title->list_audio, audio ); + free( audio ); + continue; + } + ++aud_id_uses[audio->id]; + } /* Adjust output track number, in case we removed one. * Output tracks sadly still need to be in sequential order. */ @@ -558,7 +678,8 @@ static void do_job( hb_job_t * job, int cpu_count ) /* sense-check the requested mixdown */ if( audio->config.out.mixdown == 0 && - audio->config.out.codec != HB_ACODEC_AC3 ) + audio->config.out.codec != HB_ACODEC_AC3 && + audio->config.out.codec != HB_ACODEC_DCA ) { /* * Mixdown wasn't specified and this is not pass-through, @@ -701,7 +822,7 @@ static void do_job( hb_job_t * job, int cpu_count ) audio->priv.fifo_in = hb_fifo_init( 32 ); audio->priv.fifo_raw = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); audio->priv.fifo_sync = hb_fifo_init( 32 ); - audio->priv.fifo_out = hb_fifo_init( FIFO_CPU_MULT * cpu_count ); + audio->priv.fifo_out = hb_fifo_init( 8 * FIFO_CPU_MULT * cpu_count ); /* @@ -724,7 +845,8 @@ static void do_job( hb_job_t * job, int cpu_count ) /* * Audio Encoder Thread */ - if( audio->config.out.codec != HB_ACODEC_AC3 ) + if( audio->config.out.codec != HB_ACODEC_AC3 && + audio->config.out.codec != HB_ACODEC_DCA ) { /* * Add the encoder thread if not doing AC-3 pass through @@ -835,6 +957,8 @@ cleanup: { hb_fifo_close( &subtitle->fifo_in ); hb_fifo_close( &subtitle->fifo_raw ); + hb_fifo_close( &subtitle->fifo_sync ); + hb_fifo_close( &subtitle->fifo_out ); } } for( i = 0; i < hb_list_count( title->list_audio ); i++ ) @@ -859,9 +983,14 @@ cleanup: for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) { subtitle = hb_list_item( title->list_subtitle, i ); + hb_log( "Subtitle stream 0x%x '%s': %d hits (%d forced)", subtitle->id, subtitle->lang, subtitle->hits, subtitle->forced_hits ); + + if( subtitle->hits == 0 ) + continue; + if( subtitle->hits > subtitle_highest ) { subtitle_highest = subtitle->hits; @@ -883,67 +1012,48 @@ cleanup: } } - if( job->native_language ) { + + if( subtitle_forced_id ) + { /* - * We still have a native_language, so the audio and subtitles are - * different, so in this case it is a foreign film and we want to - * select the subtitle with the highest hits in our language. + * If there are any subtitle streams with forced subtitles + * then select it in preference to the lowest. */ - subtitle_hit = subtitle_highest_id; - hb_log( "Found a native-language subtitle id 0x%x", subtitle_hit); - } else { - if( subtitle_forced_id ) - { - /* - * If there are any subtitle streams with forced subtitles - * then select it in preference to the lowest. - */ - subtitle_hit = subtitle_forced_id; - hb_log("Found a subtitle candidate id 0x%x (contains forced subs)", - subtitle_hit); - } else if( subtitle_lowest < subtitle_highest ) + subtitle_hit = subtitle_forced_id; + hb_log("Found a subtitle candidate id 0x%x (contains forced subs)", + subtitle_hit); + } else if( subtitle_lowest < subtitle_highest ) + { + /* + * OK we have more than one, and the lowest is lower, + * but how much lower to qualify for turning it on by + * default? + * + * Let's say 10% as a default. + */ + if( subtitle_lowest < ( subtitle_highest * 0.1 ) ) { - /* - * OK we have more than one, and the lowest is lower, - * but how much lower to qualify for turning it on by - * default? - * - * Let's say 10% as a default. - */ - if( subtitle_lowest < ( subtitle_highest * 0.1 ) ) - { - subtitle_hit = subtitle_lowest_id; - hb_log( "Found a subtitle candidate id 0x%x", - subtitle_hit ); - } else { - hb_log( "No candidate subtitle detected during subtitle-scan"); - } + subtitle_hit = subtitle_lowest_id; + hb_log( "Found a subtitle candidate id 0x%x", + subtitle_hit ); + } else { + hb_log( "No candidate subtitle detected during subtitle-scan"); } } } - if( job->select_subtitle ) + if( job->indepth_scan ) { - if( job->indepth_scan ) + for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) { - for( i=0; i < hb_list_count( title->list_subtitle ); i++ ) + subtitle = hb_list_item( title->list_subtitle, i ); + if( subtitle->id == subtitle_hit ) { - subtitle = hb_list_item( title->list_subtitle, i ); - if( subtitle->id == subtitle_hit ) - { - hb_list_rem( title->list_subtitle, subtitle ); - *( job->select_subtitle ) = subtitle; - } + subtitle->config = job->select_subtitle_config; + hb_list_rem( title->list_subtitle, subtitle ); + interjob->select_subtitle = subtitle; + break; } - } else { - /* - * Must be the end of pass 0 or 2 - we don't need this anymore. - * - * Have to put the subtitle list back together in the title though - * or the GUI will have a hissy fit. - */ - free( job->select_subtitle ); - job->select_subtitle = NULL; } }