diff options
-rw-r--r-- | libhb/common.h | 6 | ||||
-rw-r--r-- | libhb/hb.c | 3 | ||||
-rw-r--r-- | libhb/internal.h | 1 | ||||
-rw-r--r-- | libhb/ports.c | 7 | ||||
-rw-r--r-- | libhb/ports.h | 1 | ||||
-rw-r--r-- | libhb/reader.c | 121 | ||||
-rw-r--r-- | libhb/stream.c | 23 | ||||
-rw-r--r-- | libhb/sync.c | 324 |
8 files changed, 449 insertions, 37 deletions
diff --git a/libhb/common.h b/libhb/common.h index 57447b09a..ec45250da 100644 --- a/libhb/common.h +++ b/libhb/common.h @@ -260,7 +260,10 @@ struct hb_job_s hb_subtitle_config_t select_subtitle_config; int angle; // dvd angle to encode - int frame_to_stop; // declare eof when we hit this frame + int frame_to_start; // declare eof when we hit this frame + int64_t pts_to_start; // drop frames until we pass this pts + // in the time-linearized input stream + int frame_to_stop; // declare eof when we hit this frame int64_t pts_to_stop; // declare eof when we pass this pts in // the time-linearized input stream int start_at_preview; // if non-zero, encoding will start @@ -566,6 +569,7 @@ struct hb_state_s #define HB_STATE_PAUSED 16 #define HB_STATE_WORKDONE 32 #define HB_STATE_MUXING 64 +#define HB_STATE_SEARCHING 128 int state; union diff --git a/libhb/hb.c b/libhb/hb.c index 3db173f0a..ad51962c5 100644 --- a/libhb/hb.c +++ b/libhb/hb.c @@ -1454,7 +1454,8 @@ void hb_set_state( hb_handle_t * h, hb_state_t * s ) hb_lock( h->pause_lock ); hb_lock( h->state_lock ); memcpy( &h->state, s, sizeof( hb_state_t ) ); - if( h->state.state == HB_STATE_WORKING ) + if( h->state.state == HB_STATE_WORKING || + h->state.state == HB_STATE_SEARCHING ) { /* XXX Hack */ if (h->job_count < 1) diff --git a/libhb/internal.h b/libhb/internal.h index ada06b6b7..59753022e 100644 --- a/libhb/internal.h +++ b/libhb/internal.h @@ -210,6 +210,7 @@ void hb_stream_close( hb_stream_t ** ); hb_title_t * hb_stream_title_scan( hb_stream_t *); int hb_stream_read( hb_stream_t *, hb_buffer_t *); int hb_stream_seek( hb_stream_t *, float ); +int hb_stream_seek_ts( hb_stream_t * stream, int64_t ts ); int hb_stream_seek_chapter( hb_stream_t *, int ); int hb_stream_chapter( hb_stream_t * ); diff --git a/libhb/ports.c b/libhb/ports.c index 10b598c37..85e009a36 100644 --- a/libhb/ports.c +++ b/libhb/ports.c @@ -657,6 +657,13 @@ void hb_cond_signal( hb_cond_t * c ) #endif } +void hb_cond_broadcast( hb_cond_t * c ) +{ +#if USE_PTHREAD + pthread_cond_broadcast( &c->cond ); +#endif +} + /************************************************************************ * Network ***********************************************************************/ diff --git a/libhb/ports.h b/libhb/ports.h index 318a7d717..bc671b960 100644 --- a/libhb/ports.h +++ b/libhb/ports.h @@ -82,6 +82,7 @@ hb_cond_t * hb_cond_init(); void hb_cond_wait( hb_cond_t *, hb_lock_t * ); void hb_cond_timedwait( hb_cond_t * c, hb_lock_t * lock, int msec ); void hb_cond_signal( hb_cond_t * ); +void hb_cond_broadcast( hb_cond_t * c ); void hb_cond_close( hb_cond_t ** ); /************************************************************************ diff --git a/libhb/reader.c b/libhb/reader.c index 928d8696b..bef7e1c32 100644 --- a/libhb/reader.c +++ b/libhb/reader.c @@ -31,6 +31,9 @@ typedef struct uint8_t st_slots; // size (in slots) of stream_timing array uint8_t saw_video; // != 0 if we've seen video uint8_t saw_audio; // != 0 if we've seen audio + + int start_found; // found pts_to_start point + uint64_t st_first; } hb_reader_t; /*********************************************************************** @@ -38,6 +41,7 @@ typedef struct **********************************************************************/ static void ReaderFunc( void * ); static hb_fifo_t ** GetFifoForId( hb_job_t * job, int id ); +static void UpdateState( hb_reader_t * r, int64_t start); /*********************************************************************** * hb_reader_init @@ -63,13 +67,16 @@ hb_thread_t * hb_reader_init( hb_job_t * job ) r->stream_timing[0].last = -r->stream_timing[0].average; r->stream_timing[1].id = -1; + if ( !job->pts_to_start ) + r->start_found = 1; + return hb_thread_init( "reader", ReaderFunc, r, HB_NORMAL_PRIORITY ); } static void push_buf( const hb_reader_t *r, hb_fifo_t *fifo, hb_buffer_t *buf ) { - while ( !*r->die ) + while ( !*r->die && !r->job->done ) { if ( hb_fifo_full_wait( fifo ) ) { @@ -209,6 +216,7 @@ static void ReaderFunc( void * _r ) return; } + hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); if (r->dvd) { /* @@ -233,6 +241,7 @@ static void ReaderFunc( void * _r ) if( !hb_dvd_start( r->dvd, r->title, start ) ) { hb_dvd_close( &r->dvd ); + hb_buffer_close( &ps ); return; } if (r->job->angle) @@ -255,6 +264,27 @@ static void ReaderFunc( void * _r ) ( r->job->seek_points ? ( r->job->seek_points + 1.0 ) : 11.0 ) ); } + else if ( r->stream && r->job->pts_to_start ) + { + + // Find out what the first timestamp of the stream is + // and then seek to the appropriate offset from it + if ( hb_stream_read( r->stream, ps ) ) + { + if ( ps->start > 0 ) + r->job->pts_to_start += ps->start; + } + + if ( hb_stream_seek_ts( r->stream, r->job->pts_to_start ) >= 0 ) + { + // Seek takes us to the nearest I-frame before the timestamp + // that we want. So we will retrieve the start time of the + // first packet we get, subtract that from pts_to_start, and + // inspect the reset of the frames in sync. + r->start_found = 2; + } + + } else if( r->stream ) { /* @@ -278,7 +308,6 @@ static void ReaderFunc( void * _r ) } list = hb_list_init(); - hb_buffer_t *ps = hb_buffer_init( HB_DVD_READ_BUFFER_SIZE ); while( !*r->die && !r->job->done ) { @@ -312,6 +341,15 @@ static void ReaderFunc( void * _r ) { break; } + if ( r->start_found == 2 ) + { + // We will inspect the timestamps of each frame in sync + // to skip from this seek point to the timestamp we + // want to start at. + if ( ps->start > 0 && ps->start < r->job->pts_to_start ) + r->job->pts_to_start -= ps->start; + r->start_found = 1; + } } if( r->job->indepth_scan ) @@ -367,6 +405,32 @@ static void ReaderFunc( void * _r ) } if( fifos ) { + if ( buf->start != -1 ) + { + int64_t start = buf->start - r->scr_offset; + if ( !r->start_found ) + UpdateState( r, start ); + + if ( !r->start_found && + r->job->pts_to_start && + buf->renderOffset != -1 && + start >= r->job->pts_to_start ) + { + // pts_to_start point found + // force a new scr offset computation + stream_timing_t *st = find_st( r, buf ); + if ( st && + (st->is_audio || + ( st == r->stream_timing && !r->saw_audio ) ) ) + { + // Re-zero our timestamps + st->last = -st->average; + new_scr_offset( r, buf ); + r->start_found = 1; + r->job->pts_to_start = 0; + } + } + } if ( buf->renderOffset != -1 ) { if ( r->scr_changes == r->demux.scr_changes ) @@ -433,13 +497,11 @@ static void ReaderFunc( void * _r ) if ( buf->start != -1 ) { buf->start -= r->scr_offset; - if ( r->job->pts_to_stop && buf->start > r->job->pts_to_stop ) - { - // we're doing a subset of the input and we've hit the - // stopping point. - hb_buffer_close( &buf ); - goto done; - } + } + if ( !r->start_found ) + { + hb_buffer_close( &buf ); + continue; } buf->sequence = r->sequence++; @@ -463,7 +525,6 @@ static void ReaderFunc( void * _r ) } } - done: // send empty buffers downstream to video & audio decoders to signal we're done. if( !*r->die && !r->job->done ) { @@ -511,6 +572,46 @@ static void ReaderFunc( void * _r ) _r = NULL; } +static void UpdateState( hb_reader_t * r, int64_t start) +{ + hb_state_t state; + uint64_t now; + double avg; + + now = hb_get_date(); + if( !r->st_first ) + { + r->st_first = now; + } + +#define p state.param.working + state.state = HB_STATE_SEARCHING; + p.progress = (float) start / (float) r->job->pts_to_start; + if( p.progress > 1.0 ) + { + p.progress = 1.0; + } + if (now > r->st_first) + { + int eta; + + avg = 1000.0 * (double)start / (now - r->st_first); + eta = ( r->job->pts_to_start - start ) / avg; + p.hours = eta / 3600; + p.minutes = ( eta % 3600 ) / 60; + p.seconds = eta % 60; + } + else + { + p.rate_avg = 0.0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; + } +#undef p + + hb_set_state( r->job->h, &state ); +} /*********************************************************************** * GetFifoForId *********************************************************************** diff --git a/libhb/stream.c b/libhb/stream.c index d1244f5ee..fc51b1b23 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -207,6 +207,7 @@ static void ffmpeg_close( hb_stream_t *d ); static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream ); static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf ); static int ffmpeg_seek( hb_stream_t *stream, float frac ); +static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts ); /* * streams have a bunch of state that's learned during the scan. We don't @@ -1309,6 +1310,15 @@ int hb_stream_seek( hb_stream_t * stream, float f ) return 1; } +int hb_stream_seek_ts( hb_stream_t * stream, int64_t ts ) +{ + if ( stream->hb_stream_type == ffmpeg ) + { + return ffmpeg_seek_ts( stream, ts ); + } + return -1; +} + static const char* make_upper( const char* s ) { static char name[8]; @@ -2983,3 +2993,16 @@ static int ffmpeg_seek( hb_stream_t *stream, float frac ) } return 1; } + +// Assumes that we are always seeking forward +static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts ) +{ + AVFormatContext *ic = stream->ffmpeg_ic; + int64_t pos; + + pos = ts * AV_TIME_BASE / 90000; + stream->need_keyframe = 1; + // Seek to the nearest timestamp before that requested where + // there is an I-frame + return av_seek_frame( ic, -1, pos, AVSEEK_FLAG_BACKWARD ); +} diff --git a/libhb/sync.c b/libhb/sync.c index 81e0e35ab..1501ea02b 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -23,10 +23,19 @@ typedef struct int count_frames; int64_t audio_passthru_slip; int64_t video_pts_slip; + int64_t pts_offset; + + /* Frame based point-to-point support */ + int64_t audio_pts_thresh; + int start_found; + hb_cond_t * next_frame; + int pts_count; + int64_t * first_pts; } hb_sync_common_t; typedef struct { + int index; int64_t next_start; /* start time of next output frame */ int64_t next_pts; /* start time of next input frame */ int64_t first_drop; /* PTS of first 'went backwards' frame dropped */ @@ -44,7 +53,7 @@ typedef struct typedef struct { /* Video */ - int64_t pts_offset; + int first_frame; int64_t pts_skip; int64_t next_start; /* start time of next output frame */ int64_t next_pts; /* start time of next input frame */ @@ -77,9 +86,12 @@ struct hb_work_private_s /*********************************************************************** * Local prototypes **********************************************************************/ +static void getPtsOffset( hb_work_object_t * w ); +static int checkPtsOffset( hb_work_object_t * w ); static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ); static void InsertSilence( hb_work_object_t * w, int64_t d ); static void UpdateState( hb_work_object_t * w ); +static void UpdateSearchState( hb_work_object_t * w, int64_t start ); static hb_buffer_t * OutputAudioFrame( hb_audio_t *audio, hb_buffer_t *buf, hb_sync_audio_t *sync ); @@ -103,6 +115,20 @@ int hb_sync_init( hb_job_t * job ) pv->common = calloc( 1, sizeof( hb_sync_common_t ) ); pv->common->ref++; pv->common->mutex = hb_lock_init(); + pv->common->audio_pts_thresh = 0; + pv->common->next_frame = hb_cond_init(); + pv->common->pts_count = 1 + hb_list_count( title->list_audio ); + pv->common->first_pts = malloc( sizeof(int64_t) * pv->common->pts_count ); + for ( i = 0; i < pv->common->pts_count; i++ ) + pv->common->first_pts[i] = INT64_MAX; + if ( job->frame_to_start || job->pts_to_start ) + { + pv->common->start_found = 0; + } + else + { + pv->common->start_found = 1; + } w = hb_get_work( WORK_SYNC_VIDEO ); w->private_data = pv; @@ -110,7 +136,8 @@ int hb_sync_init( hb_job_t * job ) w->fifo_out = job->fifo_sync; pv->job = job; - sync->pts_offset = INT64_MIN; + pv->common->pts_offset = INT64_MIN; + sync->first_frame = 1; if( job->pass == 2 ) { @@ -226,10 +253,94 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, int i; *buf_out = NULL; + next = *buf_in; + *buf_in = NULL; + + /* Wait for start of point-to-point encoding */ + if( !pv->common->start_found ) + { + hb_sync_video_t * sync = &pv->type.video; + + if( next->size == 0 ) + { + *buf_out = next; + pv->common->start_found = 1; + hb_cond_broadcast( pv->common->next_frame ); + + /* + * Push through any subtitle EOFs in case they + * were not synced through. + */ + for( i = 0; i < hb_list_count( job->list_subtitle ); i++) + { + subtitle = hb_list_item( job->list_subtitle, i ); + if( subtitle->config.dest == PASSTHRUSUB ) + { + hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) ); + } + } + return HB_WORK_DONE; + } + if ( pv->common->count_frames < job->frame_to_start || + next->start < job->pts_to_start ) + { + // Flush any subtitles that have pts prior to the + // current frame + for( i = 0; i < hb_list_count( job->list_subtitle ); i++) + { + subtitle = hb_list_item( job->list_subtitle, i ); + while( ( sub = hb_fifo_see( subtitle->fifo_raw ) ) ) + { + if ( sub->start > next->start ) + break; + sub = hb_fifo_get( subtitle->fifo_raw ); + hb_buffer_close( &sub ); + } + } + hb_lock( pv->common->mutex ); + // Tell the audio threads what must be dropped + pv->common->audio_pts_thresh = next->start; + hb_cond_broadcast( pv->common->next_frame ); + hb_unlock( pv->common->mutex ); + + UpdateSearchState( w, next->start ); + hb_buffer_close( &next ); + + return HB_WORK_OK; + } + hb_lock( pv->common->mutex ); + pv->common->start_found = 1; + pv->common->count_frames = 0; + hb_cond_broadcast( pv->common->next_frame ); + hb_unlock( pv->common->mutex ); + sync->st_first = 0; + } + + /* Wait till we can determine the initial pts of all streams */ + if( pv->common->pts_offset == INT64_MIN ) + { + pv->common->first_pts[0] = next->start; + hb_lock( pv->common->mutex ); + while( pv->common->pts_offset == INT64_MIN ) + { + // Full fifos will make us wait forever, so get the + // pts offset from the available streams if full + if ( hb_fifo_is_full( job->fifo_raw ) ) + { + getPtsOffset( w ); + hb_cond_broadcast( pv->common->next_frame ); + } + else if ( checkPtsOffset( w ) ) + hb_cond_broadcast( pv->common->next_frame ); + else + hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 ); + } + hb_unlock( pv->common->mutex ); + } + if( !sync->cur ) { - sync->cur = *buf_in; - *buf_in = NULL; + sync->cur = next; if( sync->cur->size == 0 ) { /* we got an end-of-stream as our first video packet? @@ -237,6 +348,9 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, */ *buf_out = hb_buffer_init( 0 ); + pv->common->start_found = 1; + hb_cond_broadcast( pv->common->next_frame ); + /* * Push through any subtitle EOFs in case they * were not synced through. @@ -253,21 +367,7 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, } return HB_WORK_OK; } - next = *buf_in; - *buf_in = NULL; cur = sync->cur; - if( job->frame_to_stop && pv->common->count_frames > job->frame_to_stop ) - { - // Drop an empty buffer into our output to ensure that things - // get flushed all the way out. - hb_buffer_close( &sync->cur ); - hb_buffer_close( &next ); - *buf_out = hb_buffer_init( 0 ); - hb_log( "sync: reached %d frames, exiting early", - pv->common->count_frames ); - return HB_WORK_DONE; - } - /* At this point we have a frame to process. Let's check 1) if we will be able to push into the fifo ahead 2) if the next frame is there already, since we need it to @@ -303,13 +403,41 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_fifo_push( subtitle->fifo_out, hb_buffer_init( 0 ) ); } } + pv->common->start_found = 1; + hb_cond_broadcast( pv->common->next_frame ); + return HB_WORK_DONE; + } + + /* Check for end of point-to-point frame encoding */ + if( job->frame_to_stop && pv->common->count_frames > job->frame_to_stop ) + { + // Drop an empty buffer into our output to ensure that things + // get flushed all the way out. + hb_buffer_close( &sync->cur ); + hb_buffer_close( &next ); + *buf_out = hb_buffer_init( 0 ); + hb_log( "sync: reached %d frames, exiting early", + pv->common->count_frames ); return HB_WORK_DONE; } - if( sync->pts_offset == INT64_MIN ) + + /* Check for end of point-to-point pts encoding */ + if( job->pts_to_stop && sync->next_start >= job->pts_to_stop ) + { + // Drop an empty buffer into our output to ensure that things + // get flushed all the way out. + hb_log( "sync: reached pts %"PRId64", exiting early", + sync->cur->start ); + hb_buffer_close( &sync->cur ); + hb_buffer_close( &next ); + *buf_out = hb_buffer_init( 0 ); + return HB_WORK_DONE; + } + + if( sync->first_frame ) { /* This is our first frame */ - sync->pts_offset = 0; - if ( cur->start != 0 ) + if ( cur->start > pv->common->pts_offset ) { /* * The first pts from a dvd should always be zero but @@ -320,8 +448,9 @@ int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, * be in sync. */ hb_log( "sync: first pts is %"PRId64, cur->start ); - cur->start = 0; + cur->start = pv->common->pts_offset; } + sync->first_frame = 0; } /* @@ -744,9 +873,6 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, *buf_out = NULL; buf = *buf_in; *buf_in = NULL; - hb_lock( pv->common->mutex ); - start = buf->start - pv->common->audio_passthru_slip; - hb_unlock( pv->common->mutex ); /* if the next buffer is an eof send it downstream */ if ( buf->size <= 0 ) { @@ -754,12 +880,70 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, *buf_out = hb_buffer_init( 0 ); return HB_WORK_DONE; } + + /* Wait for start frame if doing point-to-point */ + hb_lock( pv->common->mutex ); + while ( !pv->common->start_found ) + { + if ( buf->start < pv->common->audio_pts_thresh ) + { + hb_buffer_close( &buf ); + hb_unlock( pv->common->mutex ); + return HB_WORK_OK; + } + while ( !pv->common->start_found && + buf->start >= pv->common->audio_pts_thresh ) + { + hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 ); + } + } + if ( buf->start < pv->common->audio_pts_thresh ) + { + hb_buffer_close( &buf ); + hb_unlock( pv->common->mutex ); + return HB_WORK_OK; + } + hb_unlock( pv->common->mutex ); + + /* Wait till we can determine the initial pts of all streams */ + if( pv->common->pts_offset == INT64_MIN ) + { + pv->common->first_pts[sync->index+1] = buf->start; + hb_lock( pv->common->mutex ); + while( pv->common->pts_offset == INT64_MIN ) + { + // Full fifos will make us wait forever, so get the + // pts offset from the available streams if full + if (hb_fifo_is_full(w->fifo_in)) + { + getPtsOffset( w ); + hb_cond_broadcast( pv->common->next_frame ); + } + else if ( checkPtsOffset( w ) ) + hb_cond_broadcast( pv->common->next_frame ); + else + hb_cond_timedwait( pv->common->next_frame, pv->common->mutex, 200 ); + } + hb_unlock( pv->common->mutex ); + } + if( job->frame_to_stop && pv->common->count_frames >= job->frame_to_stop ) { hb_buffer_close( &buf ); *buf_out = hb_buffer_init( 0 ); return HB_WORK_DONE; } + + if( job->pts_to_stop && sync->next_start >= job->pts_to_stop ) + { + hb_buffer_close( &buf ); + *buf_out = hb_buffer_init( 0 ); + return HB_WORK_DONE; + } + + hb_lock( pv->common->mutex ); + start = buf->start - pv->common->audio_passthru_slip; + hb_unlock( pv->common->mutex ); if ( (int64_t)( start - sync->next_pts ) < 0 ) { // audio time went backwards. @@ -859,6 +1043,7 @@ static void InitAudio( hb_job_t * job, hb_sync_common_t * common, int i ) pv = calloc( 1, sizeof( hb_work_private_t ) ); sync = &pv->type.audio; + sync->index = i; pv->job = job; pv->common = common; pv->common->ref++; @@ -1087,3 +1272,92 @@ static void UpdateState( hb_work_object_t * w ) hb_set_state( pv->job->h, &state ); } + +static void UpdateSearchState( hb_work_object_t * w, int64_t start ) +{ + hb_work_private_t * pv = w->private_data; + hb_sync_video_t * sync = &pv->type.video; + hb_state_t state; + uint64_t now; + double avg; + + now = hb_get_date(); + if( !pv->common->count_frames ) + { + sync->st_first = now; + pv->job->st_pause_date = -1; + pv->job->st_paused = 0; + } + pv->common->count_frames++; + +#define p state.param.working + state.state = HB_STATE_SEARCHING; + if ( pv->job->frame_to_start ) + p.progress = (float) pv->common->count_frames / + (float) pv->job->frame_to_start; + else if ( pv->job->pts_to_start ) + p.progress = (float) start / (float) pv->job->pts_to_start; + else + p.progress = 0; + if( p.progress > 1.0 ) + { + p.progress = 1.0; + } + if (now > sync->st_first) + { + int eta; + + if ( pv->job->frame_to_start ) + { + avg = 1000.0 * (double)pv->common->count_frames / (now - sync->st_first); + eta = ( pv->job->frame_to_start - pv->common->count_frames ) / avg; + } + else if ( pv->job->pts_to_start ) + { + avg = 1000.0 * (double)start / (now - sync->st_first); + eta = ( pv->job->pts_to_start - start ) / avg; + } + p.hours = eta / 3600; + p.minutes = ( eta % 3600 ) / 60; + p.seconds = eta % 60; + } + else + { + p.rate_avg = 0.0; + p.hours = -1; + p.minutes = -1; + p.seconds = -1; + } +#undef p + + hb_set_state( pv->job->h, &state ); +} + +static void getPtsOffset( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + int i ; + int64_t first_pts = INT64_MAX; + + for( i = 0; i < pv->common->pts_count; i++ ) + { + if ( pv->common->first_pts[i] < first_pts ) + first_pts = pv->common->first_pts[i]; + } + pv->common->audio_passthru_slip = pv->common->pts_offset = first_pts; + return; +} + +static int checkPtsOffset( hb_work_object_t * w ) +{ + hb_work_private_t * pv = w->private_data; + int i ; + + for( i = 0; i < pv->common->pts_count; i++ ) + { + if ( pv->common->first_pts[i] == INT64_MAX ) + return 0; + } + getPtsOffset( w ); + return 1; +} |