Index: test/test.c =================================================================== --- test/test.c (revision 1516) +++ test/test.c (working copy) @@ -91,6 +91,8 @@ static int cfr = 0; static int mp4_optimize = 0; static int ipod_atom = 0; +static int start_frame = 0; +static int frames_to_encode = 0; /* Exit cleanly on Ctrl-C */ static volatile int die = 0; @@ -808,6 +810,12 @@ job->vfr = 1; } + if( frames_to_encode ) + { + job->start_frame = start_frame; + job->frames_to_encode = frames_to_encode; + } + /* Add selected filters */ job->filters = hb_list_init(); if( detelecine ) @@ -1465,6 +1473,7 @@ " -c, --chapters Select chapters (e.g. \"1-3\" for chapters\n" " 1 to 3, or \"3\" for chapter 3 only,\n" " default: all chapters)\n" + " -@, --frames <#>,<#> Encode from frame n for N frames\n" "\n" "### Destination Options------------------------------------------------------\n\n" @@ -1660,7 +1669,7 @@ { "subtitle-scan", no_argument, NULL, 'U' }, { "subtitle-forced", no_argument, NULL, 'F' }, { "native-language", required_argument, NULL,'N' }, - + { "frames", required_argument, NULL, '@' }, { "encoder", required_argument, NULL, 'e' }, { "aencoder", required_argument, NULL, 'E' }, { "two-pass", no_argument, NULL, '2' }, @@ -1698,7 +1707,7 @@ int c; c = getopt_long( argc, argv, - "hvuC:f:4i:Io:t:Lc:m::a:6:s:UFN:e:E:2dD:7895gpOP::w:l:n:b:q:S:B:r:R:Qx:TY:X:VZ:z", + "hvuC:f:4i:Io:t:Lc:m::a:6:s:UFN:e:E:2dD:7895gpOP::w:l:n:b:q:S:B:r:R:Qx:TY:X:VZ:z@:", long_options, &option_index ); if( c < 0 ) { @@ -1788,6 +1797,11 @@ } break; } + case '@': + { + sscanf( optarg, "%d,%d", &start_frame, &frames_to_encode); + break; + } case 'm': if( optarg != NULL ) { Index: libhb/reader.c =================================================================== --- libhb/reader.c (revision 1516) +++ libhb/reader.c (working copy) @@ -183,9 +183,22 @@ { hb_list_rem( list, buf ); fifos = GetFifoForId( r->job, buf->id ); - - if ( ! r->saw_video ) + + if( r->job->current_frame < r->job->start_frame ) { + /* We're only supposed to start encoding at + start_frame, so drop packets until then, + while keeping track of how how many + video buffers have already been dropped. */ + if( buf->id == r->title->video_id ) + { + r->job->current_frame++; + } + fifos = NULL; + } + + if ( ! r->saw_video && r->job->current_frame >= r->job->start_frame ) + { /* The first video packet defines 'time zero' so discard data until we get a video packet with a PTS */ if ( buf->id == r->title->video_id && buf->start != -1 ) Index: libhb/sync.c =================================================================== --- libhb/sync.c (revision 1516) +++ libhb/sync.c (working copy) @@ -283,6 +283,23 @@ return HB_WORK_DONE; } + if(job->frames_to_encode && ( pv->count_frames > job->frames_to_encode ) ) + { + /* If we've reached the requested last frame, end early. */ + hb_log("sync: hit %i frames, ending early.", job->frames_to_encode); + + pv->done = 1; + + // Drop an empty buffer into our output to ensure that things + // get flushed all the way out. + hb_buffer_t * buf_tmp; + buf_tmp = hb_buffer_init(0); // Empty end buffer + hb_fifo_push( job->fifo_sync, buf_tmp ); + + return HB_WORK_DONE; + } + + if( !pv->cur && !( pv->cur = hb_fifo_get( job->fifo_raw ) ) ) { /* We haven't even got a frame yet */ @@ -320,7 +337,7 @@ { /* This is our first frame */ pv->pts_offset = 0; - if ( cur->start != 0 ) + if ( (cur->start != 0 && job->start_frame == 0) || (job->start_frame == job->current_frame) ) { /* * The first pts from a dvd should always be zero but Index: libhb/render.c =================================================================== --- libhb/render.c (revision 1516) +++ libhb/render.c (working copy) @@ -29,6 +29,7 @@ uint64_t total_gained_time; int64_t chapter_time; int chapter_val; + int rendered_frames; }; int renderInit( hb_work_object_t *, hb_job_t * ); @@ -310,7 +311,8 @@ /* Pop the frame's subtitle and dispose of it. */ hb_buffer_t * subtitles = hb_fifo_get( pv->subtitle_queue ); hb_buffer_close( &subtitles ); - + if( job->frames_to_encode ) + job->frames_to_encode++; buf_tmp_in = NULL; break; } @@ -404,6 +406,10 @@ hb_fifo_push( pv->delay_queue, *buf_out ); *buf_out = NULL; } + else if(*buf_out) + { + pv->rendered_frames++; + } /* * Keep the last three frames in our queue, this ensures that we have the last @@ -415,6 +421,7 @@ if( hb_fifo_size( pv->delay_queue ) >= 3 ) { *buf_out = hb_fifo_get( pv->delay_queue ); + pv->rendered_frames++; } } @@ -497,6 +504,17 @@ } + if(job->frames_to_encode && ( pv->rendered_frames > job->frames_to_encode ) ) + { + /* If we've reached the requested last frame, end early. */ + hb_log("render: hit %i frames, ending early.", job->frames_to_encode); + + // Drop an empty buffer into our output to ensure that things + // get flushed all the way out. + *buf_out = hb_buffer_init(0); + return HB_WORK_DONE; + } + return HB_WORK_OK; } @@ -571,6 +589,7 @@ pv->lost_time[0] = 0; pv->lost_time[1] = 0; pv->lost_time[2] = 0; pv->lost_time[3] = 0; pv->chapter_time = 0; pv->chapter_val = 0; + pv->rendered_frames = 0; /* Setup filters */ /* TODO: Move to work.c? */ Index: libhb/work.c =================================================================== --- libhb/work.c (revision 1516) +++ libhb/work.c (working copy) @@ -145,6 +145,13 @@ hb_log( " + device %s", title->dvd ); hb_log( " + title %d, chapter(s) %d to %d", title->index, job->chapter_start, job->chapter_end ); + + if(job->start_frame && job->frames_to_encode) + { + /* Set up for an encode of a set number of frames. */ + job->current_frame = 0; + } + if ( job->pixel_ratio == 1 ) { /* Correct the geometry of the output movie when using PixelRatio */ Index: libhb/common.h =================================================================== --- libhb/common.h (revision 1516) +++ libhb/common.h (working copy) @@ -222,6 +222,10 @@ int subtitle_force; char * native_language; + int start_frame; + int frames_to_encode; + int current_frame; + #ifdef __LIBHB__ /* Internal data */ hb_handle_t * h;