Index: media/filters/ffmpeg_demuxer.cc |
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc |
index d13fd71c80fd529835b73d4499defd44f4a4229b..093e4f539b13847a1f7f6beb0e140674af037f69 100644 |
--- a/media/filters/ffmpeg_demuxer.cc |
+++ b/media/filters/ffmpeg_demuxer.cc |
@@ -54,8 +54,10 @@ static base::Time ExtractTimelineOffset(AVFormatContext* format_context) { |
av_dict_get(format_context->metadata, "creation_time", NULL, 0); |
base::Time timeline_offset; |
+ |
+ // FFmpegDemuxerTests assume base::Time::FromUTCString() is used here. |
if (entry != NULL && entry->value != NULL && |
- FFmpegUTCDateToTime(entry->value, &timeline_offset)) { |
+ base::Time::FromUTCString(entry->value, &timeline_offset)) { |
return timeline_offset; |
} |
} |
@@ -179,11 +181,8 @@ static void RecordVideoCodecStats(const VideoDecoderConfig& video_config, |
static const char kCodecNone[] = "none"; |
-static const char* GetCodecName(const AVCodecContext* context) { |
- if (context->codec_descriptor) |
- return context->codec_descriptor->name; |
- const AVCodecDescriptor* codec_descriptor = |
- avcodec_descriptor_get(context->codec_id); |
+static const char* GetCodecName(enum AVCodecID id) { |
+ const AVCodecDescriptor* codec_descriptor = avcodec_descriptor_get(id); |
// If the codec name can't be determined, return none for tracking. |
return codec_descriptor ? codec_descriptor->name : kCodecNone; |
} |
@@ -210,7 +209,7 @@ std::unique_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create( |
std::unique_ptr<AudioDecoderConfig> audio_config; |
std::unique_ptr<VideoDecoderConfig> video_config; |
- if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) { |
+ if (stream->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) { |
audio_config.reset(new AudioDecoderConfig()); |
// IsValidConfig() checks that the codec is supported and that the channel |
@@ -227,7 +226,7 @@ std::unique_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create( |
MEDIA_LOG(INFO, media_log) << "FFmpegDemuxer: created audio stream, config " |
<< audio_config->AsHumanReadableString(); |
- } else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) { |
+ } else if (stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) { |
video_config.reset(new VideoDecoderConfig()); |
// IsValidConfig() checks that the codec is supported and that the channel |
@@ -284,7 +283,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream( |
AVDictionaryEntry* rotation_entry = NULL; |
// Determine our media format. |
- switch (stream->codec->codec_type) { |
+ switch (stream->codecpar->codec_type) { |
case AVMEDIA_TYPE_AUDIO: |
DCHECK(audio_config_.get() && !video_config_.get()); |
type_ = AUDIO; |
@@ -499,7 +498,7 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) { |
if (fixup_negative_timestamps_ && is_audio && |
stream_timestamp < base::TimeDelta() && |
buffer->duration() != kNoTimestamp) { |
- if (!stream_->codec->delay) { |
+ if (!audio_decoder_config().codec_delay()) { |
DCHECK_EQ(buffer->discard_padding().first, base::TimeDelta()); |
if (stream_timestamp + buffer->duration() < base::TimeDelta()) { |
@@ -664,7 +663,7 @@ void FFmpegDemuxerStream::ResetBitstreamConverter() { |
void FFmpegDemuxerStream::InitBitstreamConverter() { |
#if defined(USE_PROPRIETARY_CODECS) |
- switch (stream_->codec->codec_id) { |
+ switch (stream_->codecpar->codec_id) { |
case AV_CODEC_ID_H264: |
// Clear |extra_data| so that future (fallback) decoders will know that |
// conversion is forcibly enabled on this stream. |
@@ -676,17 +675,17 @@ void FFmpegDemuxerStream::InitBitstreamConverter() { |
if (video_config_) |
video_config_->SetExtraData(std::vector<uint8_t>()); |
bitstream_converter_.reset( |
- new FFmpegH264ToAnnexBBitstreamConverter(stream_->codec)); |
+ new FFmpegH264ToAnnexBBitstreamConverter(stream_->codecpar)); |
break; |
#if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
case AV_CODEC_ID_HEVC: |
bitstream_converter_.reset( |
- new FFmpegH265ToAnnexBBitstreamConverter(stream_->codec)); |
+ new FFmpegH265ToAnnexBBitstreamConverter(stream_->codecpar)); |
break; |
#endif |
case AV_CODEC_ID_AAC: |
bitstream_converter_.reset( |
- new FFmpegAACBitstreamConverter(stream_->codec)); |
+ new FFmpegAACBitstreamConverter(stream_->codecpar)); |
break; |
default: |
break; |
@@ -1111,8 +1110,8 @@ static int CalculateBitrate(AVFormatContext* format_context, |
// Then try to sum the bitrates individually per stream. |
int bitrate = 0; |
for (size_t i = 0; i < format_context->nb_streams; ++i) { |
- AVCodecContext* codec_context = format_context->streams[i]->codec; |
- bitrate += codec_context->bit_rate; |
+ AVCodecParameters* codec_parameters = format_context->streams[i]->codecpar; |
+ bitrate += codec_parameters->bit_rate; |
} |
if (bitrate > 0) |
return bitrate; |
@@ -1223,46 +1222,40 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
int detected_text_track_count = 0; |
for (size_t i = 0; i < format_context->nb_streams; ++i) { |
AVStream* stream = format_context->streams[i]; |
- const AVCodecContext* codec_context = stream->codec; |
- const AVMediaType codec_type = codec_context->codec_type; |
+ const AVCodecParameters* codec_parameters = stream->codecpar; |
+ const AVMediaType codec_type = codec_parameters->codec_type; |
+ const AVCodecID codec_id = codec_parameters->codec_id; |
if (codec_type == AVMEDIA_TYPE_AUDIO) { |
// Log the codec detected, whether it is supported or not, and whether or |
// not we have already detected a supported codec in another stream. |
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash", |
- HashCodecName(GetCodecName(codec_context))); |
+ HashCodecName(GetCodecName(codec_id))); |
detected_audio_track_count++; |
} else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
// Log the codec detected, whether it is supported or not, and whether or |
// not we have already detected a supported codec in another stream. |
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash", |
- HashCodecName(GetCodecName(codec_context))); |
+ HashCodecName(GetCodecName(codec_id))); |
detected_video_track_count++; |
#if BUILDFLAG(ENABLE_HEVC_DEMUXING) |
- if (stream->codec->codec_id == AV_CODEC_ID_HEVC) { |
+ if (codec_id == AV_CODEC_ID_HEVC) { |
// If ffmpeg is built without HEVC parser/decoder support, it will be |
// able to demux HEVC based solely on container-provided information, |
// but unable to get some of the parameters without parsing the stream |
// (e.g. coded size needs to be read from SPS, pixel format is typically |
// deduced from decoder config in hvcC box). These are not really needed |
// when using external decoder (e.g. hardware decoder), so override them |
- // here, to make sure this translates into a valid VideoDecoderConfig. |
- if (stream->codec->coded_width == 0 && |
- stream->codec->coded_height == 0) { |
- DCHECK(stream->codec->width > 0); |
- DCHECK(stream->codec->height > 0); |
- stream->codec->coded_width = stream->codec->width; |
- stream->codec->coded_height = stream->codec->height; |
- } |
- if (stream->codec->pix_fmt == AV_PIX_FMT_NONE) { |
- stream->codec->pix_fmt = AV_PIX_FMT_YUV420P; |
- } |
+ // to make sure this translates into a valid VideoDecoderConfig. Coded |
+ // size is overridden in AVStreamToVideoDecoderConfig(). |
+ if (stream->codecpar->format == AV_PIX_FMT_NONE) |
+ stream->codecpar->format = AV_PIX_FMT_YUV420P; |
} |
#endif |
} else if (codec_type == AVMEDIA_TYPE_SUBTITLE) { |
detected_text_track_count++; |
- if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) { |
+ if (codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) { |
continue; |
} |
} else { |
@@ -1292,17 +1285,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
} |
StreamParser::TrackId track_id = stream->id; |
- |
- if ((codec_type == AVMEDIA_TYPE_AUDIO && |
- media_tracks->getAudioConfig(track_id).IsValidConfig()) || |
- (codec_type == AVMEDIA_TYPE_VIDEO && |
- media_tracks->getVideoConfig(track_id).IsValidConfig())) { |
- MEDIA_LOG(INFO, media_log_) |
- << GetDisplayName() |
- << ": skipping duplicate media stream id=" << track_id; |
- continue; |
- } |
- |
std::string track_label = streams_[i]->GetMetadata("handler_name"); |
std::string track_language = streams_[i]->GetMetadata("language"); |
@@ -1316,6 +1298,16 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
track_label = streams_[i]->GetMetadata("title"); |
} |
+ if ((codec_type == AVMEDIA_TYPE_AUDIO && |
+ media_tracks->getAudioConfig(track_id).IsValidConfig()) || |
+ (codec_type == AVMEDIA_TYPE_VIDEO && |
+ media_tracks->getVideoConfig(track_id).IsValidConfig())) { |
+ MEDIA_LOG(INFO, media_log_) |
+ << GetDisplayName() |
+ << ": skipping duplicate media stream id=" << track_id; |
+ continue; |
+ } |
+ |
// Note when we find our audio/video stream (we only want one of each) and |
// record src= playback UMA stats for the stream's decoder config. |
MediaTrack* media_track = nullptr; |
@@ -1332,7 +1324,7 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
} else if (codec_type == AVMEDIA_TYPE_VIDEO) { |
VideoDecoderConfig video_config = streams_[i]->video_decoder_config(); |
- RecordVideoCodecStats(video_config, stream->codec->color_range, |
+ RecordVideoCodecStats(video_config, stream->codecpar->color_range, |
media_log_.get()); |
media_track = media_tracks->AddVideoTrack(video_config, track_id, "main", |
@@ -1405,9 +1397,9 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb, |
continue; |
const AVStream* audio_stream = stream->av_stream(); |
DCHECK(audio_stream); |
- if (audio_stream->codec->codec_id == AV_CODEC_ID_OPUS || |
+ if (audio_stream->codecpar->codec_id == AV_CODEC_ID_OPUS || |
(strcmp(format_context->iformat->name, "ogg") == 0 && |
- audio_stream->codec->codec_id == AV_CODEC_ID_VORBIS)) { |
+ audio_stream->codecpar->codec_id == AV_CODEC_ID_VORBIS)) { |
for (size_t i = 0; i < streams_.size(); ++i) { |
if (!streams_[i]) |
continue; |
@@ -1487,10 +1479,12 @@ void FFmpegDemuxer::LogMetadata(AVFormatContext* avctx, |
std::string suffix = ""; |
if (audio_track_count > 1) |
suffix = "_track" + base::IntToString(audio_track_count); |
- const AVCodecContext* audio_codec = avctx->streams[i]->codec; |
+ const AVCodecParameters* audio_parameters = avctx->streams[i]->codecpar; |
const AudioDecoderConfig& audio_config = stream->audio_decoder_config(); |
- params.SetString("audio_codec_name" + suffix, GetCodecName(audio_codec)); |
- params.SetInteger("audio_channels_count" + suffix, audio_codec->channels); |
+ params.SetString("audio_codec_name" + suffix, |
+ GetCodecName(audio_parameters->codec_id)); |
+ params.SetInteger("audio_channels_count" + suffix, |
+ audio_parameters->channels); |
params.SetString("audio_sample_format" + suffix, |
SampleFormatToString(audio_config.sample_format())); |
params.SetInteger("audio_samples_per_second" + suffix, |
@@ -1500,14 +1494,21 @@ void FFmpegDemuxer::LogMetadata(AVFormatContext* avctx, |
std::string suffix = ""; |
if (video_track_count > 1) |
suffix = "_track" + base::IntToString(video_track_count); |
- const AVCodecContext* video_codec = avctx->streams[i]->codec; |
+ const AVStream* video_av_stream = avctx->streams[i]; |
+ const AVCodecParameters* video_parameters = video_av_stream->codecpar; |
const VideoDecoderConfig& video_config = stream->video_decoder_config(); |
- params.SetString("video_codec_name" + suffix, GetCodecName(video_codec)); |
- params.SetInteger("width" + suffix, video_codec->width); |
- params.SetInteger("height" + suffix, video_codec->height); |
- params.SetString("time_base" + suffix, |
- base::StringPrintf("%d/%d", video_codec->time_base.num, |
- video_codec->time_base.den)); |
+ params.SetString("video_codec_name" + suffix, |
+ GetCodecName(video_parameters->codec_id)); |
+ params.SetInteger("width" + suffix, video_parameters->width); |
+ params.SetInteger("height" + suffix, video_parameters->height); |
+ |
+ // AVCodecParameters has no time_base field. We use the one from AVStream |
+ // here. |
+ params.SetString( |
+ "time_base" + suffix, |
+ base::StringPrintf("%d/%d", video_av_stream->time_base.num, |
+ video_av_stream->time_base.den)); |
+ |
params.SetString("video_format" + suffix, |
VideoPixelFormatToString(video_config.format())); |
params.SetBoolean("video_is_encrypted" + suffix, |