decsrt: fix p-to-p start time after seeking
authorJohn Stebbins <jstebbins.hb@gmail.com>
Sat, 15 Apr 2017 19:20:21 +0000 (13:20 -0600)
committerJohn Stebbins <jstebbins.hb@gmail.com>
Sat, 15 Apr 2017 19:22:55 +0000 (13:22 -0600)
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

libhb/common.h
libhb/decsrtsub.c
libhb/reader.c
libhb/sync.c
libhb/work.c

index a9bc3d412b914112996a564a6dc16babcac01bf0..266f13fe28ae5788d8da5cb1ee0bad4a01b64a87 100644 (file)
@@ -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
 };
 
index a3646120390b939dbf0d5f1081e56dcb77648b90..f6b3fc28cdb5d4b652d746a8cf5bb69a278148c2 100644 (file)
@@ -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,
@@ -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)
     {
index 71a961a1c4246cd937db1817b0b77b1ed2b2f8c8..7f1e7cc1a6ab36a8d4f854567b80b6ff16365127 100644 (file)
@@ -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
@@ -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
             {
@@ -491,7 +492,8 @@ 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;
@@ -499,15 +501,7 @@ static int reader_work( hb_work_object_t * w, hb_buffer_t ** buf_in,
             // 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;
         }
 
index ac30f7e28883e7150450d713999425971419ac52..fa56e8d7145476d7bd087e54bb1d9d22c66c9b81 100644 (file)
@@ -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;
@@ -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;
@@ -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;
@@ -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
     {
@@ -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)
@@ -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;
index 1358bc12eb997a7fdb0188efa838ba0c49526567..9062111e53f752aef92719602a23a755a8a3e885 100644 (file)
@@ -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 )
     {