Skip to content

Commit

Permalink
Enable partial playback
Browse files Browse the repository at this point in the history
Currently Chrome supports partial playback of unsupported content.
However it only works for codecs Chrome doesn't know about. This CL
fixes the case where Chrome knows about the codec but does not support
it on a particular platform.

BUG = 127881

Review URL: https://chromiumcodereview.appspot.com/14997005

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@199244 0039d316-1c4b-4281-b951-d872f2087c98
  • Loading branch information
jrummell@chromium.org committed May 9, 2013
1 parent b69cc1d commit ee4e69a
Show file tree
Hide file tree
Showing 3 changed files with 36 additions and 26 deletions.
23 changes: 14 additions & 9 deletions media/ffmpeg/ffmpeg_common.cc
Original file line number Diff line number Diff line change
Expand Up @@ -57,7 +57,8 @@ int64 ConvertToTimeBase(const AVRational& time_base,
return av_rescale_q(timestamp.InMicroseconds(), kMicrosBase, time_base);
}

AudioCodec CodecIDToAudioCodec(AVCodecID codec_id) {
// Converts an FFmpeg audio codec ID into its corresponding supported codec id.
static AudioCodec CodecIDToAudioCodec(AVCodecID codec_id) {
switch (codec_id) {
case AV_CODEC_ID_AAC:
return kCodecAAC;
Expand Down Expand Up @@ -137,7 +138,8 @@ static AVCodecID AudioCodecToCodecID(AudioCodec audio_codec,
return AV_CODEC_ID_NONE;
}

VideoCodec CodecIDToVideoCodec(AVCodecID codec_id) {
// Converts an FFmpeg video codec ID into its corresponding supported codec id.
static VideoCodec CodecIDToVideoCodec(AVCodecID codec_id) {
switch (codec_id) {
case AV_CODEC_ID_H264:
return kCodecH264;
Expand Down Expand Up @@ -264,7 +266,8 @@ static AVSampleFormat SampleFormatToAVSampleFormat(SampleFormat sample_format) {
static void AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
bool is_encrypted,
AudioDecoderConfig* config) {
AudioDecoderConfig* config,
bool record_stats) {
DCHECK_EQ(codec_context->codec_type, AVMEDIA_TYPE_AUDIO);

AudioCodec codec = CodecIDToAudioCodec(codec_context->codec_id);
Expand All @@ -288,7 +291,7 @@ static void AVCodecContextToAudioDecoderConfig(
codec_context->extradata,
codec_context->extradata_size,
is_encrypted,
true);
record_stats);
if (codec != kCodecOpus) {
DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
config->bits_per_channel());
Expand All @@ -297,13 +300,14 @@ static void AVCodecContextToAudioDecoderConfig(

void AVStreamToAudioDecoderConfig(
const AVStream* stream,
AudioDecoderConfig* config) {
AudioDecoderConfig* config,
bool record_stats) {
bool is_encrypted = false;
AVDictionaryEntry* key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
if (key)
is_encrypted = true;
return AVCodecContextToAudioDecoderConfig(stream->codec,
is_encrypted, config);
return AVCodecContextToAudioDecoderConfig(
stream->codec, is_encrypted, config, record_stats);
}

void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
Expand Down Expand Up @@ -336,7 +340,8 @@ void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,

void AVStreamToVideoDecoderConfig(
const AVStream* stream,
VideoDecoderConfig* config) {
VideoDecoderConfig* config,
bool record_stats) {
gfx::Size coded_size(stream->codec->coded_width, stream->codec->coded_height);

// TODO(vrk): This assumes decoded frame data starts at (0, 0), which is true
Expand Down Expand Up @@ -386,7 +391,7 @@ void AVStreamToVideoDecoderConfig(
coded_size, visible_rect, natural_size,
stream->codec->extradata, stream->codec->extradata_size,
is_encrypted,
true);
record_stats);
}

void VideoDecoderConfigToAVCodecContext(
Expand Down
12 changes: 4 additions & 8 deletions media/ffmpeg/ffmpeg_common.h
Original file line number Diff line number Diff line change
Expand Up @@ -74,14 +74,16 @@ MEDIA_EXPORT int64 ConvertToTimeBase(const AVRational& time_base,

void AVStreamToAudioDecoderConfig(
const AVStream* stream,
AudioDecoderConfig* config);
AudioDecoderConfig* config,
bool record_stats);
void AudioDecoderConfigToAVCodecContext(
const AudioDecoderConfig& config,
AVCodecContext* codec_context);

void AVStreamToVideoDecoderConfig(
const AVStream* stream,
VideoDecoderConfig* config);
VideoDecoderConfig* config,
bool record_stats);
void VideoDecoderConfigToAVCodecContext(
const VideoDecoderConfig& config,
AVCodecContext* codec_context);
Expand All @@ -98,12 +100,6 @@ VideoFrame::Format PixelFormatToVideoFormat(PixelFormat pixel_format);
// Converts video formats to its corresponding FFmpeg's pixel formats.
PixelFormat VideoFormatToPixelFormat(VideoFrame::Format video_format);

// Converts an FFmpeg video codec ID into its corresponding supported codec id.
VideoCodec CodecIDToVideoCodec(AVCodecID codec_id);

// Converts an FFmpeg audio codec ID into its corresponding supported codec id.
AudioCodec CodecIDToAudioCodec(AVCodecID codec_id);

} // namespace media

#endif // MEDIA_FFMPEG_FFMPEG_COMMON_H_
27 changes: 18 additions & 9 deletions media/filters/ffmpeg_demuxer.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,12 +54,12 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
type_ = AUDIO;
AVStreamToAudioDecoderConfig(stream, &audio_config_);
AVStreamToAudioDecoderConfig(stream, &audio_config_, true);
is_encrypted = audio_config_.is_encrypted();
break;
case AVMEDIA_TYPE_VIDEO:
type_ = VIDEO;
AVStreamToVideoDecoderConfig(stream, &video_config_);
AVStreamToVideoDecoderConfig(stream, &video_config_, true);
is_encrypted = video_config_.is_encrypted();
break;
default:
Expand Down Expand Up @@ -475,15 +475,19 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
return;
}

// Create demuxer stream entries for each possible AVStream.
// Create demuxer stream entries for each possible AVStream. Each stream
// is examined to determine if it is supported or not (is the codec enabled
// for it in this release?). Unsupported streams are skipped, allowing for
// partial playback. At least one audio or video stream must be playable.
AVFormatContext* format_context = glue_->format_context();
streams_.resize(format_context->nb_streams);
bool found_audio_stream = false;
bool found_video_stream = false;

base::TimeDelta max_duration;
for (size_t i = 0; i < format_context->nb_streams; ++i) {
AVCodecContext* codec_context = format_context->streams[i]->codec;
AVStream* stream = format_context->streams[i];
AVCodecContext* codec_context = stream->codec;
AVMediaType codec_type = codec_context->codec_type;

if (codec_type == AVMEDIA_TYPE_AUDIO) {
Expand All @@ -492,8 +496,11 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
// Log the codec detected, whether it is supported or not.
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodec",
codec_context->codec_id);
// Ensure the codec is supported.
if (CodecIDToAudioCodec(codec_context->codec_id) == kUnknownAudioCodec)
// Ensure the codec is supported. IsValidConfig() also checks that the
// channel layout and sample format are valid.
AudioDecoderConfig audio_config;
AVStreamToAudioDecoderConfig(stream, &audio_config, false);
if (!audio_config.IsValidConfig())
continue;
found_audio_stream = true;
} else if (codec_type == AVMEDIA_TYPE_VIDEO) {
Expand All @@ -502,15 +509,17 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
// Log the codec detected, whether it is supported or not.
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodec",
codec_context->codec_id);
// Ensure the codec is supported.
if (CodecIDToVideoCodec(codec_context->codec_id) == kUnknownVideoCodec)
// Ensure the codec is supported. IsValidConfig() also checks that the
// frame size and visible size are valid.
VideoDecoderConfig video_config;
AVStreamToVideoDecoderConfig(stream, &video_config, false);
if (!video_config.IsValidConfig())
continue;
found_video_stream = true;
} else {
continue;
}

AVStream* stream = format_context->streams[i];
streams_[i] = new FFmpegDemuxerStream(this, stream);
max_duration = std::max(max_duration, streams_[i]->duration());

Expand Down

0 comments on commit ee4e69a

Please sign in to comment.