summaryrefslogtreecommitdiffstats
path: root/libhb
diff options
context:
space:
mode:
Diffstat (limited to 'libhb')
-rw-r--r--libhb/common.h6
-rw-r--r--libhb/hb.c3
-rw-r--r--libhb/internal.h1
-rw-r--r--libhb/ports.c7
-rw-r--r--libhb/ports.h1
-rw-r--r--libhb/reader.c121
-rw-r--r--libhb/stream.c23
-rw-r--r--libhb/sync.c324
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;
+}