]> granicus.if.org Git - handbrake/commitdiff
libhb: work around libav decoder error durint p-to-p encoding
authorjstebbins <jstebbins.hb@gmail.com>
Mon, 14 Jul 2014 16:46:40 +0000 (16:46 +0000)
committerjstebbins <jstebbins.hb@gmail.com>
Mon, 14 Jul 2014 16:46:40 +0000 (16:46 +0000)
In some cases, initial data when in p-to-p mode causes libav decoder
initialization to fail.  This only happens when multi-threaded encoding
is enabled.

git-svn-id: svn://svn.handbrake.fr/HandBrake/trunk@6229 b64f7644-9d1e-0410-96f1-a4d463321fa5

libhb/internal.h
libhb/reader.c
libhb/stream.c

index 2f7cbacc1007fd6e64e8be42cb71516dd82606a8..ed7eab367c6d82efaaf341066b141d7c49abb13d 100644 (file)
@@ -344,6 +344,7 @@ int          hb_stream_seek_chapter( hb_stream_t *, int );
 int          hb_stream_chapter( hb_stream_t * );
 
 hb_buffer_t * hb_ts_decode_pkt( hb_stream_t *stream, const uint8_t * pkt );
+void hb_stream_set_need_keyframe( hb_stream_t *stream, int need_keyframe );
 
 
 #define STR4_TO_UINT32(p) \
index 472b4cfb0fb7cbc56a3a0f4c48b2d787c0a17bc6..5f753a7ed76ea1845b29bc68e05901c590e204ca 100644 (file)
@@ -349,7 +349,7 @@ void ReadLoop( void * _w )
     hb_work_object_t * w = _w;
     hb_work_private_t  * r = w->private_data;
     hb_fifo_t   ** fifos;
-    hb_buffer_t  * buf;
+    hb_buffer_t  * buf = NULL;
     hb_list_t    * list;
     int            n;
     int            chapter = -1;
@@ -456,7 +456,11 @@ void ReadLoop( void * _w )
             r->start_found = 2;
             r->duration -= r->job->pts_to_start;
             r->job->pts_to_start = pts_to_start;
+            hb_buffer_close(&buf);
         }
+        // hb_stream_seek_ts does nothing for TS streams and will return
+        // an error.  In this case, the current buf remains valid and
+        // gets processed below.
     } 
     else if( r->stream )
     {
@@ -503,28 +507,32 @@ void ReadLoop( void * _w )
             break;
         }
 
-        if (r->bd)
+        if (buf == NULL)
         {
-          if( (buf = hb_bd_read( r->bd )) == NULL )
-          {
-              break;
-          }
-        }
-        else if (r->dvd)
-        {
-          if( (buf = hb_dvd_read( r->dvd )) == NULL )
-          {
-              break;
-          }
+            if (r->bd)
+            {
+                if( (buf = hb_bd_read( r->bd )) == NULL )
+                {
+                    break;
+                }
+            }
+            else if (r->dvd)
+            {
+                if( (buf = hb_dvd_read( r->dvd )) == NULL )
+                {
+                    break;
+                }
+            }
+            else if (r->stream)
+            {
+                if ( (buf = hb_stream_read( r->stream )) == NULL )
+                {
+                  break;
+                }
+            }
         }
-        else if (r->stream)
+        if (r->stream && r->start_found == 2 )
         {
-          if ( (buf = hb_stream_read( r->stream )) == NULL )
-          {
-            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.
@@ -537,7 +545,6 @@ void ReadLoop( void * _w )
                 r->job->pts_to_start = 0;
             }
             r->start_found = 1;
-          }
         }
 
         (hb_demux[r->title->demuxer])( buf, list, &r->demux );
@@ -623,11 +630,20 @@ void ReadLoop( void * _w )
                         break;
                     }
 
-                    if ( !r->start_found &&
-                        start >= r->pts_to_start )
+                    if (!r->start_found && start >= r->pts_to_start)
                     {
                         // pts_to_start point found
                         r->start_found = 1;
+                        if (r->stream)
+                        {
+                            // libav multi-threaded decoders can get into
+                            // a bad state if the initial data is not
+                            // decodable.  So try to improve the chances of
+                            // a good start by waiting for an initial iframe
+                            hb_stream_set_need_keyframe(r->stream, 1);
+                            hb_buffer_close( &buf );
+                            continue;
+                        }
                     }
                     // This log is handy when you need to debug timing problems
                     //hb_log("id %x scr_offset %"PRId64
@@ -677,6 +693,7 @@ void ReadLoop( void * _w )
                     push_buf( r, fifos[n], buf_copy );
                 }
                 push_buf( r, fifos[0], buf );
+                buf = NULL;
             }
             else
             {
index 2b551e7cabcf9aec125b5da8a5a73581a9916b39..37f1fc3a2f4bd4f90d59b35d79783c935f75607f 100644 (file)
@@ -4872,6 +4872,30 @@ static hb_buffer_t * hb_ts_stream_decode( hb_stream_t *stream )
     return NULL;
 }
 
+void hb_stream_set_need_keyframe(hb_stream_t *stream, int need_keyframe)
+{
+    if ( stream->hb_stream_type == transport )
+    {
+        // Only wait for a keyframe if the stream is known to have IDRs
+        if ( stream->has_IDRs )
+        {
+            stream->need_keyframe = need_keyframe;
+        }
+    }
+    else if ( stream->hb_stream_type == program )
+    {
+        // Only wait for a keyframe if the stream is known to have IDRs
+        if ( stream->has_IDRs )
+        {
+            stream->need_keyframe = need_keyframe;
+        }
+    }
+    else
+    {
+        stream->need_keyframe = need_keyframe;
+    }
+}
+
 void hb_ts_stream_reset(hb_stream_t *stream)
 {
     int i;