diff options
Diffstat (limited to 'libhb/stream.c')
-rw-r--r-- | libhb/stream.c | 345 |
1 files changed, 102 insertions, 243 deletions
diff --git a/libhb/stream.c b/libhb/stream.c index 1bf17d5f0..84d6c1a63 100644 --- a/libhb/stream.c +++ b/libhb/stream.c @@ -124,6 +124,7 @@ typedef struct { struct hb_stream_s { + int scan; int frames; /* video frames so far */ int errors; /* total errors so far */ int last_error_frame; /* frame # at last error message */ @@ -164,7 +165,8 @@ struct hb_stream_s hb_stream_type_t hb_stream_type; hb_title_t *title; - AVFormatContext *ffmpeg_ic; + AVFormatContext *ffmpeg_info_ic; + AVFormatContext *ffmpeg_reader_ic; AVPacket *ffmpeg_pkt; uint8_t ffmpeg_video_id; @@ -209,10 +211,10 @@ static void hb_ts_stream_set_audio_list(hb_list_t *list_audio, hb_stream_t *stre static void hb_ps_stream_find_audio_ids(hb_stream_t *stream, hb_title_t *title); static off_t align_to_next_packet(hb_stream_t *stream); -static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title ); +static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title, int scan ); static void ffmpeg_close( hb_stream_t *d ); -static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream ); -static hb_buffer_t *ffmpeg_read( hb_stream_t *stream ); +static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ); +hb_buffer_t *hb_ffmpeg_read( hb_stream_t *stream ); static int ffmpeg_seek( hb_stream_t *stream, float frac ); static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts ); @@ -610,7 +612,7 @@ static int audio_inactive( hb_stream_t *stream, int idx ) *********************************************************************** * **********************************************************************/ -hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) +hb_stream_t * hb_stream_open( char *path, hb_title_t *title, int scan ) { FILE *f = fopen( path, "rb" ); if ( f == NULL ) @@ -634,7 +636,7 @@ hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) * (even if we have saved state, the stream may have changed). */ hb_stream_t *ss = hb_stream_lookup( path ); - if ( title && ss && ss->hb_stream_type != ffmpeg ) + if ( !scan && ss && ss->hb_stream_type != ffmpeg ) { /* * copy the saved state since we might be encoding the same stream @@ -643,6 +645,7 @@ hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) memcpy( d, ss, sizeof(*d) ); d->file_handle = f; d->title = title; + d->scan = scan; d->path = strdup( path ); if ( d->hb_stream_type == transport ) @@ -680,6 +683,7 @@ hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) } d->file_handle = f; d->title = title; + d->scan = scan; d->path = strdup( path ); if (d->path != NULL ) { @@ -689,7 +693,7 @@ hb_stream_t * hb_stream_open( char *path, hb_title_t *title ) } fclose( d->file_handle ); d->file_handle = NULL; - if ( ffmpeg_open( d, title ) ) + if ( ffmpeg_open( d, title, scan ) ) { return d; } @@ -831,7 +835,7 @@ void hb_stream_close( hb_stream_t ** _d ) * if the stream was opened for a scan, cache the result, otherwise delete * the state. */ - if ( stream->title == NULL ) + if ( stream->scan ) { hb_stream_delete_dynamic( stream ); if ( stream_state_list == NULL ) @@ -868,13 +872,13 @@ static void hb_stream_delete_entry(hb_stream_t *stream, int indx) *********************************************************************** * **********************************************************************/ -hb_title_t * hb_stream_title_scan(hb_stream_t *stream) +hb_title_t * hb_stream_title_scan(hb_stream_t *stream, hb_title_t * title) { if ( stream->hb_stream_type == ffmpeg ) - return ffmpeg_title_scan( stream ); + return ffmpeg_title_scan( stream, title ); // 'Barebones Title' - hb_title_t *aTitle = hb_title_init( stream->path, 0 ); + hb_title_t *aTitle = title; aTitle->type = HB_STREAM_TYPE; aTitle->index = 1; @@ -1388,7 +1392,7 @@ hb_buffer_t * hb_stream_read( hb_stream_t * src_stream ) { if ( src_stream->hb_stream_type == ffmpeg ) { - return ffmpeg_read( src_stream ); + return hb_ffmpeg_read( src_stream ); } if ( src_stream->hb_stream_type == dvd_program ) { @@ -1483,28 +1487,15 @@ hb_buffer_t * hb_stream_read( hb_stream_t * src_stream ) return hb_ts_stream_decode( src_stream ); } -void ffmpeg_flush_stream_buffers( hb_stream_t *stream ) -{ - int i; - AVFormatContext *ic = stream->ffmpeg_ic; - - for ( i = 0; i < ic->nb_streams; i++ ) - { - if ( ic->streams[i]->codec && ic->streams[i]->codec->codec ) - { - avcodec_flush_buffers( ic->streams[i]->codec ); - } - } -} - int64_t ffmpeg_initial_timestamp( hb_stream_t * stream ) { - AVStream *s = stream->ffmpeg_ic->streams[stream->ffmpeg_video_id]; - if ( s->nb_index_entries < 1 ) + AVFormatContext *ic = stream->ffmpeg_info_ic; + if ( ic->start_time != AV_NOPTS_VALUE && ic->start_time > 0 ) + return ic->start_time; + else return 0; - - return s->index_entries[0].timestamp; } + int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num ) { @@ -1537,8 +1528,11 @@ int hb_stream_seek_chapter( hb_stream_t * stream, int chapter_num ) if ( chapter_num > 1 && pos > 0 ) { - av_seek_frame( stream->ffmpeg_ic, -1, pos, 0); - ffmpeg_flush_stream_buffers( stream ); + AVStream *st = stream->ffmpeg_info_ic->streams[stream->ffmpeg_video_id]; + // timebase must be adjusted to match timebase of stream we are + // using for seeking. + pos = av_rescale(pos, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); + avformat_seek_file( stream->ffmpeg_reader_ic, stream->ffmpeg_video_id, 0, pos, pos, AVSEEK_FLAG_BACKWARD); } return 1; } @@ -1655,7 +1649,6 @@ static void set_ts_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) * formatting routine in scan.c do all the stuff below. */ const char *codec_name; - AVCodecContext *cc; // Names for streams we know about. if ( audio->config.in.stream_type == 0x80 && @@ -1705,24 +1698,6 @@ static void set_ts_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) // To distinguish, Bluray streams have a reg_desc of HDMV codec_name = "E-AC3"; } - // For streams demuxed and decoded by ffmpeg, we have a cached context. - // Use it to get the name and profile information. Obtaining - // the profile requires that ffmpeg has already probed the stream. - else if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK ) && - ( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) && - ( cc = hb_ffmpeg_context( audio->config.in.codec_param ) ) && - avcodec_find_decoder( cc->codec_id ) ) - { - AVCodec *codec = avcodec_find_decoder( cc->codec_id ); - codec_name = codec->name; - - const char *profile_name; - profile_name = av_get_profile_name( codec, cc->profile ); - if ( profile_name ) - { - codec_name = profile_name; - } - } else if ( st2codec[audio->config.in.stream_type].kind == A ) { codec_name = stream_type_name(audio->config.in.reg_desc, @@ -1731,7 +1706,6 @@ static void set_ts_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) // For streams demuxed by us and decoded by ffmpeg, we can lookup the // decoder name. else if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK ) && - !( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) && avcodec_find_decoder( audio->config.in.codec_param ) ) { codec_name = avcodec_find_decoder( audio->config.in.codec_param )->name; @@ -1750,25 +1724,13 @@ static void set_ts_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) strlen(lang->native_name) ? lang->native_name : lang->eng_name, codec_name ); - if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK) && - ( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) ) - { - int layout = audio->config.in.channel_layout; - char *desc = audio->config.lang.description + - strlen( audio->config.lang.description ); - sprintf( desc, " (%d.%d ch)", - HB_INPUT_CH_LAYOUT_GET_DISCRETE_FRONT_COUNT(layout) + - HB_INPUT_CH_LAYOUT_GET_DISCRETE_REAR_COUNT(layout), - HB_INPUT_CH_LAYOUT_GET_DISCRETE_LFE_COUNT(layout) ); - } - snprintf( audio->config.lang.simple, sizeof( audio->config.lang.simple ), "%s", strlen(lang->native_name) ? lang->native_name : lang->eng_name ); snprintf( audio->config.lang.iso639_2, sizeof( audio->config.lang.iso639_2 ), "%s", lang->iso639_2); } -static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) +static void set_audio_description( hb_stream_t * stream, hb_audio_t *audio, iso639_lang_t *lang ) { /* XXX * This is a duplicate of code in dvd.c - it should get factored out @@ -1777,14 +1739,17 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) * formatting routine in scan.c do all the stuff below. */ const char *codec_name; - AVCodecContext *cc; + AVCodecContext *cc = NULL; + + if ( stream && stream->ffmpeg_info_ic ) + { + cc = stream->ffmpeg_info_ic->streams[audio->id]->codec; + } // For streams demuxed and decoded by ffmpeg, we have a cached context. // Use it to get the name and profile information. Obtaining // the profile requires that ffmpeg has already probed the stream. - if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK ) && - ( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) && - ( cc = hb_ffmpeg_context( audio->config.in.codec_param ) ) && + if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK ) && cc && avcodec_find_decoder( cc->codec_id ) ) { AVCodec *codec = avcodec_find_decoder( cc->codec_id ); @@ -1800,7 +1765,6 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) // For streams demuxed by us and decoded by ffmpeg, we can lookup the // decoder name. else if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK ) && - !( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) && avcodec_find_decoder( audio->config.in.codec_param ) ) { codec_name = avcodec_find_decoder( audio->config.in.codec_param )->name; @@ -1818,8 +1782,7 @@ static void set_audio_description( hb_audio_t *audio, iso639_lang_t *lang ) strlen(lang->native_name) ? lang->native_name : lang->eng_name, codec_name ); - if ( ( audio->config.in.codec & HB_ACODEC_FF_MASK) && - ( audio->config.in.codec & HB_ACODEC_FF_I_FLAG ) ) + if ( audio->config.in.channel_layout ) { int layout = audio->config.in.channel_layout; char *desc = audio->config.lang.description + @@ -2042,7 +2005,7 @@ static void add_audio_to_title(hb_title_t *title, int id) return; } - set_audio_description( audio, lang_for_code( 0 ) ); + set_audio_description( NULL, audio, lang_for_code( 0 ) ); // Sort by id when adding to the list int i; @@ -3124,182 +3087,78 @@ static void hb_ts_stream_reset(hb_stream_t *stream) // ------------------------------------------------------------------ // Support for reading media files via the ffmpeg libraries. -static void ffmpeg_add_codec( hb_stream_t *stream, int stream_index ) +static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title, int scan ) { - // add a codec to the context here so it will be there when we - // read the first packet. - AVCodecContext *context = stream->ffmpeg_ic->streams[stream_index]->codec; - context->workaround_bugs = FF_BUG_AUTODETECT; - context->error_recognition = 1; - context->error_concealment = FF_EC_GUESS_MVS|FF_EC_DEBLOCK; - AVCodec *codec = avcodec_find_decoder( context->codec_id ); - hb_ff_set_sample_fmt( context, codec ); -} - -// The ffmpeg stream reader / parser shares a lot of state with the -// decoder via a codec context kept in the AVStream of the reader's -// AVFormatContext. Since decoding is done in a different thread we -// have to somehow pass this codec context to the decoder and we have -// to do it before the first packet is read (so we can't put the info -// in the buf we'll send downstream). Decoders don't have any way to -// get to the stream directly (they're not passed the title or job -// pointers during a scan) so this is a back door for the decoder to -// get the codec context. We just stick the stream pointer in the next -// slot an array of pointers maintained as a circular list then return -// the index into the list combined with the ffmpeg stream index as the -// codec_param that will be passed to the decoder init routine. We make -// the list 'big' (enough for 1024 simultaneously open ffmpeg streams) -// so that we don't have to do a complicated allocator or worry about -// deleting entries on close. -// -// Entries can only be added to this list during a scan and are never -// deleted so the list access doesn't require locking. -static hb_stream_t **ffmpeg_streams; // circular list of stream pointers -static int ffmpeg_stream_cur; // where we put the last stream pointer -#define ffmpeg_sl_bits (10) // log2 stream list size (in entries) -#define ffmpeg_sl_size (1 << ffmpeg_sl_bits) - -// add a stream to the list & return the appropriate codec_param to access it -static int ffmpeg_codec_param( hb_stream_t *stream, int stream_index ) -{ - if ( !ffmpeg_streams ) - { - ffmpeg_streams = calloc( ffmpeg_sl_size, sizeof(stream) ); - } - - // the title scan adds all the ffmpeg media streams at once so we - // only add a new entry to our stream list if the stream is different - // than last time. - int slot = ffmpeg_stream_cur; - if ( ffmpeg_streams[slot] != stream ) - { - // new stream - put it in the next slot of the stream list - slot = ++ffmpeg_stream_cur & (ffmpeg_sl_size - 1); - ffmpeg_streams[slot] = stream; - } - - ffmpeg_add_codec( stream, stream_index ); - - return ( stream_index << ffmpeg_sl_bits ) | slot; -} - -// we're about to open 'title' to convert it - remap the stream associated -// with the video & audio codec params of the title to refer to 'stream' -// (the original scan stream was closed and no longer exists). -static void ffmpeg_remap_stream( hb_stream_t *stream, hb_title_t *title ) -{ - // all the video & audio came from the same stream so remapping - // the video's stream slot takes care of everything. - int slot = title->video_codec_param & (ffmpeg_sl_size - 1); - ffmpeg_streams[slot] = stream; - - // add codecs for all the streams used by the title - ffmpeg_add_codec( stream, title->video_codec_param >> ffmpeg_sl_bits ); - - int i; - hb_audio_t *audio; - for ( i = 0; ( audio = hb_list_item( title->list_audio, i ) ); ++i ) - { - if ( audio->config.in.codec & HB_ACODEC_FF_MASK ) - { - ffmpeg_add_codec( stream, - audio->config.in.codec_param >> ffmpeg_sl_bits ); - } - } -} - -void *hb_ffmpeg_context( int codec_param ) -{ - if ( ffmpeg_streams == NULL ) - return NULL; - - int slot = codec_param & (ffmpeg_sl_size - 1); - int stream_index = codec_param >> ffmpeg_sl_bits; - return ffmpeg_streams[slot]->ffmpeg_ic->streams[stream_index]->codec; -} - -void *hb_ffmpeg_avstream( int codec_param ) -{ - if ( ffmpeg_streams == NULL ) - return NULL; - - int slot = codec_param & (ffmpeg_sl_size - 1); - int stream_index = codec_param >> ffmpeg_sl_bits; - return ffmpeg_streams[slot]->ffmpeg_ic->streams[stream_index]; -} - -static AVFormatContext *ffmpeg_deferred_close; - -static int ffmpeg_open( hb_stream_t *stream, hb_title_t *title ) -{ - if ( ffmpeg_deferred_close ) - { - av_close_input_file( ffmpeg_deferred_close ); - ffmpeg_deferred_close = NULL; - } - AVFormatContext *ic; + AVFormatContext *info_ic = NULL, *reader_ic = NULL; av_log_set_level( AV_LOG_ERROR ); - if ( av_open_input_file( &ic, stream->path, NULL, 0, NULL ) < 0 ) + + // FFMpeg has issues with seeking. After av_find_stream_info, the + // streams are left in an indeterminate position. So a seek is + // necessary to force things back to the beginning of the stream. + // But then the seek fails for some stream types. So the safest thing + // to do seems to be to open 2 AVFormatContext. One for probing info + // and the other for reading. + if ( av_open_input_file( &info_ic, stream->path, NULL, 0, NULL ) < 0 ) { return 0; } - if ( av_find_stream_info( ic ) < 0 ) + if ( av_find_stream_info( info_ic ) < 0 ) goto fail; - stream->ffmpeg_ic = ic; + title->opaque_priv = (void*)info_ic; + stream->ffmpeg_info_ic = info_ic; + if ( av_open_input_file( &reader_ic, stream->path, NULL, 0, NULL ) < 0 ) + { + goto fail; + } + stream->ffmpeg_reader_ic = reader_ic; stream->hb_stream_type = ffmpeg; stream->ffmpeg_pkt = malloc(sizeof(*stream->ffmpeg_pkt)); av_init_packet( stream->ffmpeg_pkt ); stream->chapter_end = INT64_MAX; - if ( title ) + if ( !scan ) { // we're opening for read. scan passed out codec params that // indexed its stream so we need to remap them so they point // to this stream. stream->ffmpeg_video_id = title->video_id; - ffmpeg_remap_stream( stream, title ); av_log_set_level( AV_LOG_ERROR ); } else { // we're opening for scan. let ffmpeg put some info into the // log about what we've got. + stream->ffmpeg_video_id = title->video_id; av_log_set_level( AV_LOG_INFO ); - av_dump_format( ic, 0, stream->path, 0 ); + av_dump_format( info_ic, 0, stream->path, 0 ); av_log_set_level( AV_LOG_ERROR ); // accept this file if it has at least one video stream we can decode int i; - for (i = 0; i < ic->nb_streams; ++i ) + for (i = 0; i < info_ic->nb_streams; ++i ) { - if ( ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) + if ( info_ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO ) { break; } } - if ( i >= ic->nb_streams ) + if ( i >= info_ic->nb_streams ) goto fail; } return 1; fail: - av_close_input_file( ic ); + if ( info_ic ) av_close_input_file( info_ic ); + if ( reader_ic ) av_close_input_file( reader_ic ); return 0; } static void ffmpeg_close( hb_stream_t *d ) { - // XXX since we're sharing the CodecContext with the downstream - // decoder proc we can't close the stream. We need to reference count - // this so we can close it when both are done with their instance but - // for now just defer the close until the next stream open or close. - if ( ffmpeg_deferred_close ) - { - av_close_input_file( ffmpeg_deferred_close ); - } - ffmpeg_deferred_close = d->ffmpeg_ic; + av_close_input_file( d->ffmpeg_info_ic ); + av_close_input_file( d->ffmpeg_reader_ic ); if ( d->ffmpeg_pkt != NULL ) { free( d->ffmpeg_pkt ); @@ -3309,7 +3168,7 @@ static void ffmpeg_close( hb_stream_t *d ) static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) { - AVStream *st = stream->ffmpeg_ic->streams[id]; + AVStream *st = stream->ffmpeg_info_ic->streams[id]; AVCodecContext *codec = st->codec; AVMetadataTag *tag; int layout; @@ -3345,13 +3204,13 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) ( codec->profile == FF_PROFILE_DTS_HD_MA || codec->profile == FF_PROFILE_DTS_HD_HRA ) ) { - audio->config.in.codec = HB_ACODEC_DCA_HD | HB_ACODEC_FF_I_FLAG; + audio->config.in.codec = HB_ACODEC_DCA_HD; } else { - audio->config.in.codec = HB_ACODEC_FFMPEG | HB_ACODEC_FF_I_FLAG; + audio->config.in.codec = HB_ACODEC_FFMPEG; } - audio->config.in.codec_param = ffmpeg_codec_param( stream, id ); + audio->config.in.codec_param = codec->codec_id; audio->config.in.bitrate = codec->bit_rate? codec->bit_rate : 1; audio->config.in.samplerate = codec->sample_rate; @@ -3360,7 +3219,7 @@ static void add_ffmpeg_audio( hb_title_t *title, hb_stream_t *stream, int id ) } tag = av_metadata_get( st->metadata, "language", NULL, 0 ); - set_audio_description( audio, + set_audio_description( stream, audio, lang_for_code2( tag ? tag->value : "und" ) ); hb_list_add( title->list_audio, audio ); @@ -3491,7 +3350,7 @@ static int ffmpeg_parse_vobsub_extradata( AVCodecContext *codec, hb_subtitle_t * static void add_ffmpeg_subtitle( hb_title_t *title, hb_stream_t *stream, int id ) { - AVStream *st = stream->ffmpeg_ic->streams[id]; + AVStream *st = stream->ffmpeg_info_ic->streams[id]; AVCodecContext *codec = st->codec; hb_subtitle_t *subtitle = calloc( 1, sizeof(*subtitle) ); @@ -3560,7 +3419,7 @@ static char *get_ffmpeg_metadata_value( AVMetadata *m, char *key ) static void add_ffmpeg_attachment( hb_title_t *title, hb_stream_t *stream, int id ) { - AVStream *st = stream->ffmpeg_ic->streams[id]; + AVStream *st = stream->ffmpeg_info_ic->streams[id]; AVCodecContext *codec = st->codec; enum attachtype type; @@ -3586,12 +3445,11 @@ static void add_ffmpeg_attachment( hb_title_t *title, hb_stream_t *stream, int i hb_list_add(title->list_attachment, attachment); } -static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream ) +static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream, hb_title_t *title ) { - AVFormatContext *ic = stream->ffmpeg_ic; + AVFormatContext *ic = stream->ffmpeg_info_ic; // 'Barebones Title' - hb_title_t *title = hb_title_init( stream->path, 0 ); title->type = HB_FF_STREAM_TYPE; title->index = 1; @@ -3629,16 +3487,18 @@ static hb_title_t *ffmpeg_title_scan( hb_stream_t *stream ) } title->video_id = i; stream->ffmpeg_video_id = i; + if ( ic->streams[i]->sample_aspect_ratio.num && + ic->streams[i]->sample_aspect_ratio.den ) + { + title->pixel_aspect_width = ic->streams[i]->sample_aspect_ratio.num; + title->pixel_aspect_height = ic->streams[i]->sample_aspect_ratio.den; + } if ( context->codec_id == CODEC_ID_H264 ) title->flags |= HBTF_NO_IDR; - // We have to use the 'internal' avcodec decoder because - // it needs to share the codec context from this video - // stream. The parser internal to av_read_frame - // passes a bunch of state info to the decoder via the context. - title->video_codec = WORK_DECAVCODECVI; - title->video_codec_param = ffmpeg_codec_param( stream, i ); + title->video_codec = WORK_DECAVCODECV; + title->video_codec_param = context->codec_id; } else if ( ic->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO && avcodec_find_decoder( ic->streams[i]->codec->codec_id ) ) @@ -3718,7 +3578,7 @@ static int ffmpeg_is_keyframe( hb_stream_t *stream ) { uint8_t *pkt; - switch ( stream->ffmpeg_ic->streams[stream->ffmpeg_video_id]->codec->codec_id ) + switch ( stream->ffmpeg_info_ic->streams[stream->ffmpeg_video_id]->codec->codec_id ) { case CODEC_ID_VC1: // XXX the VC1 codec doesn't mark key frames so to get previews @@ -3740,7 +3600,7 @@ static int ffmpeg_is_keyframe( hb_stream_t *stream ) // there are bframes or not so we have to look at the sequence // header to get that. pkt = stream->ffmpeg_pkt->data; - uint8_t *seqhdr = stream->ffmpeg_ic->streams[stream->ffmpeg_video_id]->codec->extradata; + uint8_t *seqhdr = stream->ffmpeg_info_ic->streams[stream->ffmpeg_video_id]->codec->extradata; int pshift = 2; if ( ( seqhdr[3] & 0x02 ) == 0 ) // no FINTERPFLAG @@ -3760,13 +3620,13 @@ static int ffmpeg_is_keyframe( hb_stream_t *stream ) return ( stream->ffmpeg_pkt->flags & AV_PKT_FLAG_KEY ); } -static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) +hb_buffer_t * hb_ffmpeg_read( hb_stream_t *stream ) { int err; hb_buffer_t * buf; again: - if ( ( err = av_read_frame( stream->ffmpeg_ic, stream->ffmpeg_pkt )) < 0 ) + if ( ( err = av_read_frame( stream->ffmpeg_reader_ic, stream->ffmpeg_pkt )) < 0 ) { // av_read_frame can return EAGAIN. In this case, it expects // to be called again to get more data. @@ -3818,7 +3678,7 @@ static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) { hb_log( "ffmpeg_read: pkt too big: %d bytes", stream->ffmpeg_pkt->size ); av_free_packet( stream->ffmpeg_pkt ); - return ffmpeg_read( stream ); + return hb_ffmpeg_read( stream ); } buf = hb_buffer_init( stream->ffmpeg_pkt->size ); memcpy( buf->data, stream->ffmpeg_pkt->data, stream->ffmpeg_pkt->size ); @@ -3827,7 +3687,7 @@ static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) // compute a conversion factor to go from the ffmpeg // timebase for the stream to HB's 90kHz timebase. - AVStream *s = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]; + AVStream *s = stream->ffmpeg_info_ic->streams[stream->ffmpeg_pkt->stream_index]; double tsconv = 90000. * (double)s->time_base.num / (double)s->time_base.den; buf->start = av_to_hb_pts( stream->ffmpeg_pkt->pts, tsconv ); @@ -3859,8 +3719,8 @@ static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) */ enum CodecID ffmpeg_pkt_codec; enum AVMediaType codec_type; - ffmpeg_pkt_codec = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_id; - codec_type = stream->ffmpeg_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_type; + ffmpeg_pkt_codec = stream->ffmpeg_info_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_id; + codec_type = stream->ffmpeg_info_ic->streams[stream->ffmpeg_pkt->stream_index]->codec->codec_type; switch ( codec_type ) { case AVMEDIA_TYPE_VIDEO: @@ -3923,38 +3783,37 @@ static hb_buffer_t * ffmpeg_read( hb_stream_t *stream ) static int ffmpeg_seek( hb_stream_t *stream, float frac ) { - AVFormatContext *ic = stream->ffmpeg_ic; + AVFormatContext *ic = stream->ffmpeg_reader_ic; if ( frac > 0. ) { - int64_t pos = (double)ic->duration * (double)frac; - if ( ic->start_time != AV_NOPTS_VALUE && ic->start_time > 0 ) - { - pos += ic->start_time; - } - av_seek_frame( ic, -1, pos, 0 ); - stream->need_keyframe = 1; - ffmpeg_flush_stream_buffers( stream ); + int64_t pos = (double)stream->ffmpeg_info_ic->duration * (double)frac + + ffmpeg_initial_timestamp( stream ); + avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); } else { - av_seek_frame( ic, -1, 0LL, AVSEEK_FLAG_BACKWARD ); - ffmpeg_flush_stream_buffers( stream ); + int64_t pos = ffmpeg_initial_timestamp( stream ); + avformat_seek_file( ic, -1, 0, pos, pos, AVSEEK_FLAG_BACKWARD); } + stream->need_keyframe = 1; return 1; } // Assumes that we are always seeking forward static int ffmpeg_seek_ts( hb_stream_t *stream, int64_t ts ) { - AVFormatContext *ic = stream->ffmpeg_ic; + AVFormatContext *ic = stream->ffmpeg_reader_ic; int64_t pos; int ret; pos = ts * AV_TIME_BASE / 90000 + ffmpeg_initial_timestamp( stream ); + AVStream *st = stream->ffmpeg_info_ic->streams[stream->ffmpeg_video_id]; + // timebase must be adjusted to match timebase of stream we are + // using for seeking. + pos = av_rescale(pos, st->time_base.den, AV_TIME_BASE * (int64_t)st->time_base.num); stream->need_keyframe = 1; // Seek to the nearest timestamp before that requested where // there is an I-frame - ret = av_seek_frame( ic, -1, pos, AVSEEK_FLAG_BACKWARD ); - ffmpeg_flush_stream_buffers( stream ); + ret = avformat_seek_file( ic, stream->ffmpeg_video_id, 0, pos, pos, 0); return ret; } |