#include "a52dec/a52.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
+#include "mp4v2/mp4v2.h"
#define min(a, b) a < b ? a : b
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
}
/***********************************************************************
+ * 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
***********************************************************************
*
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 : ");
// 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.
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;
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;
}
{
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;
}