From dbc9a88a30efe853ab8d061d1fca7e6a501dc6ea Mon Sep 17 00:00:00 2001 From: John Stebbins Date: Thu, 9 Jun 2016 12:59:30 -0600 Subject: sync: fix some p-to-p issues After finding the start position, some data prior to the start from other streams could leak through causing duplicate timestamps in the output. Also, improves alignment of stop times of all streams when a stop time is set. --- libhb/sync.c | 195 +++++++++++++++++++++++++++++++++++++---------------------- 1 file changed, 123 insertions(+), 72 deletions(-) (limited to 'libhb') diff --git a/libhb/sync.c b/libhb/sync.c index 6a9eefd4a..284663492 100644 --- a/libhb/sync.c +++ b/libhb/sync.c @@ -71,6 +71,8 @@ typedef struct sync_common_t * common; // Stream I/O control + int done; + int flush; hb_list_t * in_queue; hb_list_t * scr_delay_queue; int max_len; @@ -148,7 +150,6 @@ struct sync_common_s int stream_count; sync_stream_t * streams; int found_first_pts; - int done; // SCR adjustments scr_t scr[SCR_HASH_SZ]; @@ -157,6 +158,7 @@ struct sync_common_s // point-to-point support int start_found; int64_t start_pts; + int64_t stop_pts; // sync audio work objects hb_list_t * list_work; @@ -912,16 +914,6 @@ static void fifo_push( hb_fifo_t * fifo, hb_buffer_t * buf ) } } -static void sendEof( sync_common_t * common ) -{ - int ii; - - for (ii = 0; ii < common->stream_count; ii++) - { - fifo_push(common->streams[ii].fifo_out, hb_buffer_eof_init()); - } -} - static void streamFlush( sync_stream_t * stream ) { hb_lock(stream->common->mutex); @@ -948,29 +940,32 @@ static void streamFlush( sync_stream_t * stream ) if (buf != NULL) { hb_list_rem(stream->in_queue, buf); - if (!stream->first_frame && buf->s.start >= 0) + if (!stream->first_frame) { - switch (stream->type) + if (buf->s.start >= 0) { - case SYNC_TYPE_VIDEO: - hb_log("sync: first pts video is %"PRId64, - buf->s.start); - break; - case SYNC_TYPE_AUDIO: - hb_log("sync: first pts audio 0x%x is %"PRId64, - stream->audio.audio->id, buf->s.start); - break; - case SYNC_TYPE_SUBTITLE: - hb_log("sync: first pts subtitle 0x%x is %"PRId64, - stream->subtitle.subtitle->id, buf->s.start); - break; - default: - break; + switch (stream->type) + { + case SYNC_TYPE_VIDEO: + hb_log("sync: first pts video is %"PRId64, + buf->s.start); + break; + case SYNC_TYPE_AUDIO: + hb_log("sync: first pts audio 0x%x is %"PRId64, + stream->audio.audio->id, buf->s.start); + break; + case SYNC_TYPE_SUBTITLE: + hb_log("sync: first pts subtitle 0x%x is %"PRId64, + stream->subtitle.subtitle->id, buf->s.start); + break; + default: + break; + } + stream->first_frame = 1; + stream->first_pts = buf->s.start; + stream->min_frame_duration = buf->s.duration; } - stream->first_frame = 1; - stream->first_pts = buf->s.start; - stream->next_pts = buf->s.start; - stream->min_frame_duration = buf->s.duration; + stream->next_pts = buf->s.start; } if (stream->type == SYNC_TYPE_AUDIO) { @@ -1053,6 +1048,32 @@ static void streamFlush( sync_stream_t * stream ) hb_unlock(stream->common->mutex); } +static void flushStreams( sync_common_t * common ) +{ + int ii; + + // Make sure all streams are complete + for (ii = 0; ii < common->stream_count; ii++) + { + sync_stream_t * stream = &common->streams[ii]; + if (!stream->done && !stream->flush) + { + return; + } + } + + // Flush all streams + for (ii = 0; ii < common->stream_count; ii++) + { + sync_stream_t * stream = &common->streams[ii]; + if (stream->done) + { + continue; + } + streamFlush(stream); + } +} + static void log_chapter( sync_common_t *common, int chap_num, int nframes, int64_t pts ) { @@ -1179,13 +1200,6 @@ static void OutputBuffer( sync_common_t * common ) sync_stream_t * out_stream; hb_buffer_t * buf; - if (common->done) - { - // It is possible to get here when one stream triggers - // end of output (i.e. pts_to_stop or frame_to_stop) while - // another stream is waiting on the mutex. - return; - } do { full = 0; @@ -1232,6 +1246,13 @@ static void OutputBuffer( sync_common_t * common ) // minimum queue level break; } + if (out_stream->done) + { + buf = hb_list_item(out_stream->in_queue, 0); + hb_list_rem(out_stream->in_queue, buf); + hb_buffer_close(&buf); + continue; + } if (out_stream->next_pts == (int64_t)AV_NOPTS_VALUE) { @@ -1294,26 +1315,46 @@ static void OutputBuffer( sync_common_t * common ) } // reset frame count to track number of frames after // the start position till the end of encode. + out_stream->frame_count = 0; shiftTS(common, buf->s.start); } // If pts_to_stop or frame_to_stop were specified, stop output - if (common->job->pts_to_stop && - buf->s.start >= common->job->pts_to_stop ) + if (common->stop_pts && + buf->s.start >= common->stop_pts ) { - hb_log("sync: reached pts %"PRId64", exiting early", buf->s.start); - common->done = 1; - sendEof(common); + switch (out_stream->type) + { + case SYNC_TYPE_VIDEO: + hb_log("sync: reached video pts %"PRId64", exiting early", + buf->s.start); + break; + case SYNC_TYPE_AUDIO: + hb_log("sync: reached audio 0x%x pts %"PRId64 + ", exiting early", + out_stream->audio.audio->id, buf->s.start); + break; + case SYNC_TYPE_SUBTITLE: + hb_log("sync: reached subtitle 0x%x pts %"PRId64 + ", exiting early", + out_stream->subtitle.subtitle->id, buf->s.start); + break; + default: + break; + } + out_stream->done = 1; + fifo_push(out_stream->fifo_out, hb_buffer_eof_init()); return; } if (out_stream->type == SYNC_TYPE_VIDEO && common->job->frame_to_stop && out_stream->frame_count >= common->job->frame_to_stop) { - hb_log("sync: reached %d frames, exiting early", + hb_log("sync: reached video frame %d, exiting early", out_stream->frame_count); - common->done = 1; - sendEof(common); + common->stop_pts = buf->s.start; + out_stream->done = 1; + fifo_push(out_stream->fifo_out, hb_buffer_eof_init()); return; } @@ -1329,29 +1370,32 @@ static void OutputBuffer( sync_common_t * common ) { UpdateState(common, out_stream->frame_count); } - if (!out_stream->first_frame && buf->s.start >= 0) + if (!out_stream->first_frame) { - switch (out_stream->type) + if (buf->s.start >= 0) { - case SYNC_TYPE_VIDEO: - hb_log("sync: first pts video is %"PRId64, - buf->s.start); - break; - case SYNC_TYPE_AUDIO: - hb_log("sync: first pts audio 0x%x is %"PRId64, - out_stream->audio.audio->id, buf->s.start); - break; - case SYNC_TYPE_SUBTITLE: - hb_log("sync: first pts subtitle 0x%x is %"PRId64, - out_stream->subtitle.subtitle->id, buf->s.start); - break; - default: - break; + switch (out_stream->type) + { + case SYNC_TYPE_VIDEO: + hb_log("sync: first pts video is %"PRId64, + buf->s.start); + break; + case SYNC_TYPE_AUDIO: + hb_log("sync: first pts audio 0x%x is %"PRId64, + out_stream->audio.audio->id, buf->s.start); + break; + case SYNC_TYPE_SUBTITLE: + hb_log("sync: first pts subtitle 0x%x is %"PRId64, + out_stream->subtitle.subtitle->id, buf->s.start); + break; + default: + break; + } + out_stream->first_frame = 1; + out_stream->first_pts = buf->s.start; + out_stream->min_frame_duration = buf->s.duration; } - out_stream->first_frame = 1; - out_stream->first_pts = buf->s.start; - out_stream->next_pts = buf->s.start; - out_stream->min_frame_duration = buf->s.duration; + out_stream->next_pts = buf->s.start; } if (out_stream->type == SYNC_TYPE_AUDIO) @@ -2117,6 +2161,10 @@ static int syncVideoInit( hb_work_object_t * w, hb_job_t * job) { pv->common->start_found = 1; } + if (job->pts_to_stop) + { + pv->common->stop_pts = job->pts_to_stop; + } return 0; @@ -2575,13 +2623,14 @@ static int syncVideoWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in; - if (pv->common->done) + if (pv->stream->done) { return HB_WORK_DONE; } if (in->s.flags & HB_BUF_FLAG_EOF) { - streamFlush(pv->stream); + pv->stream->flush = 1; + flushStreams(pv->common); // Ideally, we would only do this subtitle scan check in // syncSubtitleWork, but someone might try to do a subtitle // scan on a source that has no subtitles :-( @@ -2659,13 +2708,14 @@ static int syncAudioWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in; - if (pv->common->done) + if (pv->stream->done) { return HB_WORK_DONE; } if (in->s.flags & HB_BUF_FLAG_EOF) { - streamFlush(pv->stream); + pv->stream->flush = 1; + flushStreams(pv->common); return HB_WORK_DONE; } @@ -2960,16 +3010,17 @@ static int syncSubtitleWork( hb_work_object_t * w, hb_buffer_t ** buf_in, hb_work_private_t * pv = w->private_data; hb_buffer_t * in = *buf_in; - if (pv->common->done) + if (pv->stream->done) { return HB_WORK_DONE; } if (in->s.flags & HB_BUF_FLAG_EOF) { + pv->stream->flush = 1; // sanitizeSubtitle requires EOF buffer to recognize that // it needs to flush all subtitles. hb_list_add(pv->stream->in_queue, hb_buffer_eof_init()); - streamFlush(pv->stream); + flushStreams(pv->common); if (pv->common->job->indepth_scan) { // When doing subtitle indepth scan, the pipeline ends at sync. -- cgit v1.2.3