OSDN Git Service

WinGui:
[handbrake-jp/handbrake-jp-git.git] / libhb / stream.c
index a12c4ba..156fe99 100755 (executable)
@@ -62,7 +62,7 @@ static const stream2codec_t st2codec[256] = {
 
     st(0x1b, V, WORK_DECAVCODECV,  CODEC_ID_H264,  "H.264"),
 
-    st(0x80, U, 0,                 0,              "DigiCipher II Video"),
+    //st(0x80, U, 0,                 0,              "DigiCipher II Video"),
     se(0x81, A, HB_ACODEC_AC3,     0,              "AC-3"),
     se(0x82, A, HB_ACODEC_DCA,     0,              "HDMV DTS"),
     st(0x83, A, HB_ACODEC_LPCM,    0,              "LPCM"),
@@ -119,6 +119,8 @@ struct hb_stream_s
     uint8_t *fwrite_buf;        /* PS buffer (set by hb_ts_stream_decode) */
     uint8_t *fwrite_buf_orig;   /* PS buffer start (set by hb_ts_stream_decode) */
 
+    uint8_t need_keyframe;
+
     /*
      * Stuff before this point is dynamic state updated as we read the
      * stream. Stuff after this point is stream description state that
@@ -143,6 +145,7 @@ struct hb_stream_s
     AVFormatContext *ffmpeg_ic;
     AVPacket *ffmpeg_pkt;
     double ffmpeg_tsconv[MAX_STREAMS];
+    uint8_t ffmpeg_video_id;
 
     struct {
         int lang_code;
@@ -1078,6 +1081,7 @@ int hb_stream_seek( hb_stream_t * src_stream, float f )
         // We need to drop the current decoder output and move
         // forwards to the next transport stream packet.
         hb_ts_stream_reset(src_stream);
+        src_stream->need_keyframe = ( f != 0 );
     }
     else if ( src_stream->hb_stream_type == program )
     {
@@ -1577,19 +1581,6 @@ static int build_program_map(const uint8_t *buf, hb_stream_t *stream)
 
     // Get pointer length - only valid in packets with a start flag
     int pointer_len = 0;
-       if (start && stream->pmt_info.reading)
-       {
-               // We just finished a bunch of packets - parse the program map details
-               int decode_ok = 0;
-               if (stream->pmt_info.tablebuf[0] == 0x02)
-                       decode_ok = decode_program_map(stream);
-               free(stream->pmt_info.tablebuf);
-               stream->pmt_info.tablebuf = NULL;
-               stream->pmt_info.tablepos = 0;
-        stream->pmt_info.reading = 0;
-        if (decode_ok)
-                       return decode_ok;
-       }
 
        if (start)
        {
@@ -1615,6 +1606,27 @@ static int build_program_map(const uint8_t *buf, hb_stream_t *stream)
             memcpy(stream->pmt_info.tablebuf + stream->pmt_info.tablepos, buf + 4 + adapt_len + pointer_len, amount_to_copy);
             stream->pmt_info.tablepos += amount_to_copy;
     }
+    if (stream->pmt_info.tablepos > 3)
+    {
+        // We have enough to check the section length
+        int length;
+        length = ((stream->pmt_info.tablebuf[1] << 8) + 
+                  stream->pmt_info.tablebuf[2]) & 0xFFF;
+        if (stream->pmt_info.tablepos > length + 1)
+        {
+            // We just finished a bunch of packets - parse the program map details
+            int decode_ok = 0;
+            if (stream->pmt_info.tablebuf[0] == 0x02)
+                decode_ok = decode_program_map(stream);
+            free(stream->pmt_info.tablebuf);
+            stream->pmt_info.tablebuf = NULL;
+            stream->pmt_info.tablepos = 0;
+            stream->pmt_info.reading = 0;
+            if (decode_ok)
+                return decode_ok;
+        }
+
+    }
 
     return 0;
 }
@@ -1740,6 +1752,7 @@ static void hb_ts_stream_find_pids(hb_stream_t *stream)
        for (;;)
        {
         const uint8_t *buf = next_packet( stream );
+
         if ( buf == NULL )
         {
                        hb_log("hb_ts_stream_find_pids - end of file");
@@ -1769,7 +1782,8 @@ static void hb_ts_stream_find_pids(hb_stream_t *stream)
                        // on the first pat entry for which we find a matching program map PID.  The ideal solution would
                        // be to build a title choice popup from the PAT program number details and then select from
                        // their - but right now the API's not capable of that.
-                       if (pid == stream->pat_info[pat_index].program_map_PID)
+            if (stream->pat_info[pat_index].program_number != 0 &&
+                pid == stream->pat_info[pat_index].program_map_PID)
                        {
                          if (build_program_map(buf, stream) > 0)
                                break;
@@ -2064,6 +2078,14 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len )
                     // h.264 IDR picture start
                     return 1;
 
+                if ( stream->packetsize == 192 )
+                {
+                    // m2ts files have idr frames so keep looking for one
+                    continue;
+                }
+
+                // h226 in ts files (ATSC or DVB video) often seem to be
+                // missing IDR frames so look for at least an I
                 if ( nal_type == 0x01 )
                 {
                     // h.264 slice: has to be start MB 0 & type I (2, 4, 7 or 9)
@@ -2224,10 +2246,14 @@ static int hb_ts_stream_decode( hb_stream_t *stream, uint8_t *obuf )
             {
                 if ( !stream->ts_foundfirst[0] )
                 {
-                    if ( !isIframe( stream, buf, adapt_len ) )
+                    if ( stream->need_keyframe )
                     {
-                        // didn't find an I frame
-                        continue;
+                        if ( !isIframe( stream, buf, adapt_len ) )
+                        {
+                            // didn't find an I frame
+                            continue;
+                        }
+                        stream->need_keyframe = 0;
                     }
                     stream->ts_foundfirst[0] = 1;
                 }
@@ -2319,6 +2345,7 @@ static void hb_ts_stream_reset(hb_stream_t *stream)
 
     stream->frames = 0;
     stream->errors = 0;
+    stream->need_keyframe = 0;
     stream->last_error_frame = -10000;
     stream->last_error_count = 0;
 
@@ -2459,7 +2486,6 @@ static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title )
         // indexed its stream so we need to remap them so they point
         // to this stream.
         ffmpeg_remap_stream( stream, title );
-        ffmpeg_seek( stream, 0. );
         av_log_set_level( AV_LOG_ERROR );
     }
     else
@@ -2600,6 +2626,7 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream )
              title->video_codec == 0 )
         {
             title->video_id = i;
+            stream->ffmpeg_video_id = i;
 
             // We have to use the 'internal' avcodec decoder because
             // it needs to share the codec context from this video
@@ -2631,6 +2658,7 @@ static int64_t av_to_hb_pts( int64_t pts, double conv_factor )
 static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
 {
     int err;
+  again:
     if ( ( err = av_read_frame( stream->ffmpeg_ic, stream->ffmpeg_pkt )) < 0 )
     {
         // XXX the following conditional is to handle avi files that
@@ -2657,6 +2685,13 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
     {
         if ( stream->ffmpeg_pkt->size > buf->alloc )
         {
+            // sometimes we get absurd sizes from ffmpeg
+            if ( stream->ffmpeg_pkt->size >= (1 << 25) )
+            {
+                hb_log( "ffmpeg_read: pkt too big: %d bytes", stream->ffmpeg_pkt->size );
+                av_free_packet( stream->ffmpeg_pkt );
+                return ffmpeg_read( stream, buf );
+            }
             // need to expand buffer
             hb_buffer_realloc( buf, stream->ffmpeg_pkt->size );
         }
@@ -2664,6 +2699,24 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
         buf->size = stream->ffmpeg_pkt->size;
     }
     buf->id = stream->ffmpeg_pkt->stream_index;
+    if ( buf->id == stream->ffmpeg_video_id )
+    {
+        if ( stream->need_keyframe &&
+             stream->ffmpeg_ic->streams[stream->ffmpeg_video_id]->codec->codec_id == 
+               CODEC_ID_VC1 )
+        {
+            // XXX the VC1 codec doesn't seek to key frames so to get previews
+            // we do it ourselves here. The decoder gets messed up if it
+            // doesn't get a SEQ header first so we consider that to be a key frame.
+            uint8_t *pkt = stream->ffmpeg_pkt->data;
+            if ( pkt[0] || pkt[1] || pkt[2] != 1 || pkt[3] != 0x0f )
+            {
+                goto again;
+            }
+            stream->need_keyframe = 0;
+        }
+        ++stream->frames;
+    }
 
     // if we haven't done it already, compute a conversion factor to go
     // from the ffmpeg timebase for the stream to HB's 90KHz timebase.
@@ -2689,6 +2742,14 @@ static int ffmpeg_seek( hb_stream_t *stream, float frac )
 {
     AVFormatContext *ic = stream->ffmpeg_ic;
     int64_t pos = (double)ic->duration * (double)frac;
-    av_seek_frame( ic, -1, pos, pos? 0 : AVSEEK_FLAG_BACKWARD );
+    if ( pos )
+    {
+        av_seek_frame( ic, -1, pos, 0 );
+        stream->need_keyframe = 1;
+    }
+    else
+    {
+        av_seek_frame( ic, -1, pos, AVSEEK_FLAG_BACKWARD );
+    }
     return 1;
 }