OSDN Git Service

Found the ffmpeg initialization problem with VC-1 video.
[handbrake-jp/handbrake-jp-git.git] / libhb / stream.c
index d5ab019..1b03ae6 100755 (executable)
@@ -13,6 +13,7 @@
 #include "a52dec/a52.h"
 #include "libavcodec/avcodec.h"
 #include "libavformat/avformat.h"
+#include "mp4v2/mp4v2.h"
 
 #define min(a, b) a < b ? a : b
 
@@ -119,6 +120,9 @@ struct hb_stream_s
 
     hb_buffer_t *fwrite_buf;      /* PS buffer (set by hb_ts_stream_decode) */
 
+    int      chapter;           /* Chapter that we are currently in */
+    uint64_t chapter_end;       /* HB time that the current chapter ends */
+
     /*
      * Stuff before this point is dynamic state updated as we read the
      * stream. Stuff after this point is stream description state that
@@ -1082,6 +1086,75 @@ int hb_stream_read( hb_stream_t * src_stream, hb_buffer_t * b )
 }
 
 /***********************************************************************
+ * hb_stream_seek_chapter
+ ***********************************************************************
+ *
+ **********************************************************************/
+int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num )
+{
+    AVFormatContext *ic = stream->ffmpeg_ic;
+    uint64_t end_offset = 0;
+    uint64_t start_offset = 0;
+    uint64_t pos = 0;
+    hb_chapter_t *chapter = NULL;
+    int i;
+
+    if( !stream || !stream->title )
+    {
+        return 0;
+    }
+    if ( stream->hb_stream_type != ffmpeg )
+    {
+        // currently meaningliess for transport and program streams
+        return 1;
+    }
+
+    for( i = 0; i < chapter_num; i++)
+    {
+        chapter = hb_list_item( stream->title->list_chapter,
+                                i );
+        
+        if( chapter )
+        {
+            /*
+             * Seeking to a chapter means that we are in that chapter,
+             * so track which chapter we are in so that we can output
+             * the correct chapter numbers in buf->new_chap
+             */
+            start_offset = end_offset;
+            end_offset += chapter->duration;
+            stream->chapter = i;
+            stream->chapter_end = end_offset;
+        } else {
+            return 0;
+        }
+    }
+
+    /*
+     * Is the the correct way to convert timebases? It seems to get it pretty
+     * much right - plus a few seconds, which is odd.
+     */
+    pos = ((start_offset * AV_TIME_BASE) / 90000);
+
+    hb_deep_log( 2, "Seeking to chapter %d time (starts: %lld ends %lld) AV pos %lld", chapter_num-1, start_offset, end_offset, pos);
+
+    av_seek_frame( ic, -1, pos, 0);
+
+    return 1;
+}
+
+/***********************************************************************
+ * hb_stream_chapter
+ ***********************************************************************
+ * Return the number of the chapter that we are currently in. We store
+ * the chapter number starting from 0, so + 1 for the real chpater num.
+ **********************************************************************/
+int hb_stream_chapter( hb_stream_t * src_stream )
+{
+    return( src_stream->chapter + 1 );
+}
+
+/***********************************************************************
  * hb_stream_seek
  ***********************************************************************
  *
@@ -1868,14 +1941,6 @@ static void hb_ts_stream_find_pids(hb_stream_t *stream)
                if ((stream->ts_number_video_pids > 0) && (stream->ts_number_audio_pids > 0))
                  break;
        }
-    // XXX - until we figure out how to handle VC1 just bail when we find it so
-    // that ffmpeg will claim the input stream.
-    if ( stream->ts_stream_type[0] == 0xea )
-    {
-        stream->ts_number_video_pids = 0;
-        stream->ts_number_audio_pids = 0;
-        return;
-    }
 
        hb_log("hb_ts_stream_find_pids - found the following PIDS");
        hb_log("    Video PIDS : ");
@@ -2061,6 +2126,22 @@ static int isIframe( hb_stream_t *stream, const uint8_t *buf, int adapt_len )
         // didn't find an I-frame
         return 0;
     }
+    if ( stream->ts_stream_type[0] == 0xea )
+    {
+        // we have an vc1 stream 
+        for (i = 13 + adapt_len; i < 188; i++)
+        {
+            strid = (strid << 8) | buf[i];
+            if ( strid == 0x10f )
+            {
+                // the ffmpeg vc1 decoder requires a seq hdr code in the first
+                // frame.
+                return 1;
+            }
+        }
+        // didn't find an I-frame
+        return 0;
+    }
 
     // we don't understand the stream type so just say "yes" otherwise
     // we'll discard all the video.
@@ -2585,16 +2666,6 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream )
     title->minutes  = ( dur % 3600 ) / 60;
     title->seconds  = dur % 60;
 
-    // One Chapter
-    hb_chapter_t * chapter;
-    chapter = calloc( sizeof( hb_chapter_t ), 1 );
-    chapter->index = 1;
-    chapter->duration = title->duration;
-    chapter->hours = title->hours;
-    chapter->minutes = title->minutes;
-    chapter->seconds = title->seconds;
-    hb_list_add( title->list_chapter, chapter );
-
     // set the title to decode the first video stream in the file
     title->demuxer = HB_NULL_DEMUXER;
     title->video_codec = 0;
@@ -2625,6 +2696,26 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream )
     title->container_name = strdup( ic->iformat->name );
     title->data_rate = ic->bit_rate;
 
+    hb_deep_log( 2, "Found ffmpeg %d chapters, container=%s", ic->nb_chapters, ic->iformat->name);
+
+    /*
+     * Fill the metadata.
+     */
+    decmetadata( title );
+
+    if( hb_list_count( title->list_chapter ) == 0 )
+    {
+        // Need at least one chapter
+        hb_chapter_t * chapter;
+        chapter = calloc( sizeof( hb_chapter_t ), 1 );
+        chapter->index = 1;
+        chapter->duration = title->duration;
+        chapter->hours = title->hours;
+        chapter->minutes = title->minutes;
+        chapter->seconds = title->seconds;
+        hb_list_add( title->list_chapter, chapter );
+    }
+
     return title;
 }
 
@@ -2714,6 +2805,54 @@ static int ffmpeg_read( hb_stream_t *stream, hb_buffer_t *buf )
     {
         buf->start = buf->renderOffset;
     }
+
+    /*
+     * Check to see whether this video buffer is on a chapter
+     * boundary, if so mark it as such in the buffer. The chapters for
+     * a stream have a simple duration for each chapter. So we keep
+     * track of what chapter we are in currently, and when it is due
+     * to end.
+     */
+    hb_deep_log( 3, "title=0x%x, job=0x%x, chapter_markers=%d, time=%lld, chapter=%d, end_chapter=%lld",
+                 stream->title, 
+                 stream->title ? (stream->title->job ? stream->title->job : 0x0) : 0x0, 
+                 stream->title ? (stream->title->job ? stream->title->job->chapter_markers : 2) : 0x0,  
+                 buf->start, stream->chapter, stream->chapter_end);
+
+    if( stream->title &&
+        stream->title->job &&
+        stream->title->job->chapter_markers &&
+        buf->id == stream->ffmpeg_video_id &&
+        buf->start >= stream->chapter_end )
+    {
+        hb_chapter_t *chapter = NULL;
+
+        /*
+         * Store when this chapter ends using HB time.
+         */
+        chapter = hb_list_item( stream->title->list_chapter,
+                                stream->chapter );
+
+        if( chapter )
+        {
+            if( stream->chapter != 0 )
+            {
+                buf->new_chap = stream->chapter + 2;
+            }
+
+            hb_deep_log( 2, "Starting chapter %i at %lld", buf->new_chap, buf->start);
+            stream->chapter_end += chapter->duration;
+            stream->chapter++;
+            hb_deep_log( 2, "Looking for chapter %i at %lld", stream->chapter+1, stream->chapter_end );
+        } else {
+            /*
+             * Must have run out of chapters, stop looking.
+             */
+            stream->chapter_end = -1;
+        }
+    } else {
+        buf->new_chap = 0;
+    }
     av_free_packet( stream->ffmpeg_pkt );
     return 1;
 }