Skip to content

Commit

Permalink
Browse files Browse the repository at this point in the history
decsrt: fix p-to-p start time after seeking
Reader can skip data at the beginning of the file.  We were not
informing decsrt how much was skipped when pts_to_start caused the skip.

Fixes https://forum.handbrake.fr/viewtopic.php?f=11&t=36258
  • Loading branch information
jstebbins committed Apr 15, 2017
1 parent 52d4c21 commit bb92ab0
Show file tree
Hide file tree
Showing 5 changed files with 130 additions and 76 deletions.
4 changes: 4 additions & 0 deletions libhb/common.h
Expand Up @@ -671,6 +671,10 @@ struct hb_job_s
hb_esconfig_t config;

hb_mux_data_t * mux_data;

int64_t reader_pts_offset; // Reader can discard some video.
// Other pipeline stages need to know
// this. E.g. sync and decsrtsub
#endif
};

Expand Down
150 changes: 90 additions & 60 deletions libhb/decsrtsub.c
Expand Up @@ -601,85 +601,100 @@ static hb_buffer_t *srt_read( hb_work_private_t *pv )

static int decsrtInit( hb_work_object_t * w, hb_job_t * job )
{
int retval = 1;
hb_work_private_t * pv;
int i;
hb_chapter_t * chapter;

pv = calloc( 1, sizeof( hb_work_private_t ) );
if( pv )
if (pv == NULL)
{
w->private_data = pv;

pv->job = job;
pv->current_state = k_state_potential_new_entry;
pv->number_of_entries = 0;
pv->last_entry_number = 0;
pv->current_time = 0;
pv->subtitle = w->subtitle;

/*
* Figure out the start and stop times from teh chapters being
* encoded - drop subtitle not in this range.
*/
pv->start_time = 0;
for( i = 1; i < job->chapter_start; ++i )
goto fail;
}

w->private_data = pv;

pv->job = job;
pv->current_state = k_state_potential_new_entry;
pv->number_of_entries = 0;
pv->last_entry_number = 0;
pv->current_time = 0;
pv->subtitle = w->subtitle;

/*
* Figure out the start and stop times from teh chapters being
* encoded - drop subtitle not in this range.
*/
pv->start_time = 0;
for( i = 1; i < job->chapter_start; ++i )
{
chapter = hb_list_item( job->list_chapter, i - 1 );
if( chapter )
{
chapter = hb_list_item( job->list_chapter, i - 1 );
if( chapter )
{
pv->start_time += chapter->duration;
} else {
hb_error( "Could not locate chapter %d for SRT start time", i );
retval = 0;
}
pv->start_time += chapter->duration;
} else {
hb_error( "Could not locate chapter %d for SRT start time", i );
}
pv->stop_time = pv->start_time;
for( i = job->chapter_start; i <= job->chapter_end; ++i )
}
pv->stop_time = pv->start_time;
for( i = job->chapter_start; i <= job->chapter_end; ++i )
{
chapter = hb_list_item( job->list_chapter, i - 1 );
if( chapter )
{
chapter = hb_list_item( job->list_chapter, i - 1 );
if( chapter )
{
pv->stop_time += chapter->duration;
} else {
hb_error( "Could not locate chapter %d for SRT start time", i );
retval = 0;
}
pv->stop_time += chapter->duration;
} else {
hb_error( "Could not locate chapter %d for SRT start time", i );
}
}

hb_deep_log( 3, "SRT Start time %"PRId64", stop time %"PRId64, pv->start_time, pv->stop_time);

pv->iconv_context = iconv_open( "utf-8", pv->subtitle->config.src_codeset );

hb_deep_log(3, "SRT Start time %"PRId64", stop time %"PRId64,
pv->start_time, pv->stop_time);

if( pv->iconv_context == (iconv_t) -1 )
{
hb_error("Could not open the iconv library with those file formats\n");
if (job->pts_to_start != 0)
{
pv->start_time = AV_NOPTS_VALUE;
}

} else {
memset( &pv->current_entry, 0, sizeof( srt_entry_t ) );
pv->iconv_context = iconv_open( "utf-8", pv->subtitle->config.src_codeset );
if( pv->iconv_context == (iconv_t) -1 )
{
hb_error("Could not open the iconv library with those file formats\n");
goto fail;
} else {
memset( &pv->current_entry, 0, sizeof( srt_entry_t ) );

pv->file = hb_fopen(w->subtitle->config.src_filename, "r");
pv->file = hb_fopen(w->subtitle->config.src_filename, "r");

if( !pv->file )
{
hb_error("Could not open the SRT subtitle file '%s'\n",
w->subtitle->config.src_filename);
} else {
retval = 0;
}
if( !pv->file )
{
hb_error("Could not open the SRT subtitle file '%s'\n",
w->subtitle->config.src_filename);
goto fail;
}
}
if (!retval)

// Generate generic SSA Script Info.
int height = job->title->geometry.height - job->crop[0] - job->crop[1];
int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, HB_FONT_SANS,
.066 * job->title->geometry.height,
width, height);
return 0;

fail:
if (pv != NULL)
{
// Generate generic SSA Script Info.
int height = job->title->geometry.height - job->crop[0] - job->crop[1];
int width = job->title->geometry.width - job->crop[2] - job->crop[3];
hb_subtitle_add_ssa_header(w->subtitle, HB_FONT_SANS,
.066 * job->title->geometry.height,
width, height);
if (pv->iconv_context != (iconv_t) -1)
{
iconv_close(pv->iconv_context);
}
if (pv->file != NULL)
{
fclose(pv->file);
}
free(pv);
}
return retval;
return 1;
}

static int decsrtWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
Expand All @@ -688,6 +703,21 @@ static int decsrtWork( hb_work_object_t * w, hb_buffer_t ** buf_in,
hb_work_private_t * pv = w->private_data;
hb_buffer_t * out = NULL;

if (pv->job->reader_pts_offset == AV_NOPTS_VALUE)
{
// We need to wait for reader to initialize it's pts offset so that
// we know where to start reading SRTs.
*buf_out = NULL;
return HB_WORK_OK;
}
if (pv->start_time == AV_NOPTS_VALUE)
{
pv->start_time = pv->job->reader_pts_offset;
if (pv->job->pts_to_stop > 0)
{
pv->stop_time = pv->job->pts_to_start + pv->job->pts_to_stop;
}
}
out = srt_read( pv );
if (out != NULL)
{
Expand Down
16 changes: 5 additions & 11 deletions libhb/reader.c
Expand Up @@ -115,7 +115,7 @@ static int hb_reader_open( hb_work_private_t * r )
// to start decoding early using r->pts_to_start
hb_bd_seek_pts(r->bd, r->job->pts_to_start);
r->duration -= r->job->pts_to_start;
r->job->pts_to_start = 0;
r->job->reader_pts_offset = r->job->pts_to_start;
r->start_found = 1;
}
else
Expand Down Expand Up @@ -172,6 +172,7 @@ static int hb_reader_open( hb_work_private_t * r )
// first packet we get, subtract that from pts_to_start, and
// inspect the reset of the frames in sync.
r->duration -= r->job->pts_to_start;
r->job->reader_pts_offset = AV_NOPTS_VALUE;
}
else
{
Expand Down Expand Up @@ -491,23 +492,16 @@ static int reader_work( hb_work_object_t * w, hb_buffer_t ** buf_in,
// libav is allowing SSA subtitles to leak through that are
// prior to the seek point. So only make the adjustment to
// pts_to_start after we see the next video buffer.
if (buf->s.id != r->job->title->video_id)
if (buf->s.id != r->job->title->video_id ||
buf->s.start == AV_NOPTS_VALUE)
{
hb_buffer_close(&buf);
continue;
}
// 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 (buf->s.start != AV_NOPTS_VALUE &&
buf->s.start < r->job->pts_to_start)
{
r->job->pts_to_start -= buf->s.start;
}
else if ( buf->s.start >= r->job->pts_to_start )
{
r->job->pts_to_start = 0;
}
r->job->reader_pts_offset = buf->s.start;
r->start_found = 1;
}

Expand Down
29 changes: 24 additions & 5 deletions libhb/sync.c
Expand Up @@ -158,6 +158,7 @@ struct sync_common_s

// point-to-point support
int start_found;
int64_t pts_to_start;
int64_t start_pts;
int64_t stop_pts;
int wait_for_frame;
Expand Down Expand Up @@ -1350,7 +1351,7 @@ static void OutputBuffer( sync_common_t * common )
else if (common->wait_for_pts &&
out_stream->type != SYNC_TYPE_SUBTITLE)
{
if (buf->s.start >= common->job->pts_to_start)
if (buf->s.start >= common->pts_to_start)
{
common->start_found = 1;
common->streams[0].frame_count = 0;
Expand Down Expand Up @@ -1881,6 +1882,20 @@ static void QueueBuffer( sync_stream_t * stream, hb_buffer_t * buf )
}
}

// Reader can change job->reader_pts_offset after initialization
// and before we receive the first buffer here. Calculate
// common->pts_to_start here since this is the first opportunity where
// all the necessary information exists.
if (stream->common->pts_to_start == AV_NOPTS_VALUE)
{
hb_job_t * job = stream->common->job;
if (job->pts_to_start > 0)
{
stream->common->pts_to_start =
MAX(0, job->pts_to_start - job->reader_pts_offset);
}
}

// Render offset is only useful for decoders, which are all
// upstream of sync. Squash it.
buf->s.renderOffset = AV_NOPTS_VALUE;
Expand Down Expand Up @@ -2242,10 +2257,14 @@ static int syncVideoInit( hb_work_object_t * w, hb_job_t * job)

if (job->frame_to_start || job->pts_to_start)
{
pv->common->start_found = 0;
pv->common->start_pts = pv->common->job->pts_to_start;
pv->common->start_found = 0;
pv->common->start_pts = job->pts_to_start;
pv->common->wait_for_frame = !!job->frame_to_start;
pv->common->wait_for_pts = !!job->pts_to_start;
if (job->pts_to_start)
{
pv->common->pts_to_start = AV_NOPTS_VALUE;
}
}
else
{
Expand Down Expand Up @@ -3048,7 +3067,7 @@ static void UpdateSearchState( sync_common_t * common, int64_t start,
if (common->wait_for_frame)
p.progress = (float)frame_count / job->frame_to_start;
else if (common->wait_for_pts)
p.progress = (float) start / job->pts_to_start;
p.progress = (float) start / common->pts_to_start;
else
p.progress = 0;
if (p.progress > 1.0)
Expand All @@ -3067,7 +3086,7 @@ static void UpdateSearchState( sync_common_t * common, int64_t start,
else if (common->wait_for_pts)
{
avg = 1000.0 * start / (now - common->st_first);
eta = (job->pts_to_start - start) / avg;
eta = (common->pts_to_start - start) / avg;
}
p.hours = eta / 3600;
p.minutes = (eta % 3600) / 60;
Expand Down
7 changes: 7 additions & 0 deletions libhb/work.c
Expand Up @@ -1927,6 +1927,13 @@ void hb_work_loop( void * _w )
}
}
}
else if (w->fifo_in == NULL)
{
// If this work object is a generator (no input fifo) and it
// generated no output, it may be waiting for status from
// another thread. Yield so that we don't spin doing nothing.
hb_yield();
}
}
if ( buf_out )
{
Expand Down

0 comments on commit bb92ab0

Please sign in to comment.