summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorchcunningham <chcunningham@chromium.org>2015-10-19 18:42:09 -0700
committerCommit bot <commit-bot@chromium.org>2015-10-20 01:42:56 +0000
commit9812dd8df19bc65839f48d914a1c4e296107a49a (patch)
tree71925688be60d95b7a73518e0c704c142ff0ccab
parent2c81561ee4f6bf0f19810070ce594c2a109b4e03 (diff)
downloadchromium_src-9812dd8df19bc65839f48d914a1c4e296107a49a.zip
chromium_src-9812dd8df19bc65839f48d914a1c4e296107a49a.tar.gz
chromium_src-9812dd8df19bc65839f48d914a1c4e296107a49a.tar.bz2
Fail playback when VideoDecoderConfig has invalid extra data.
Invalid extra data occurs when: (extra_data_ptr == NULL) != (extra_data_size == 0) We were previously crashing (CHECK) on this condition. {Audio|Video}DecoderConfig now use a vector and pointer/size issues are detected/handled in the path of creating the FFmpegDemuxerStream. Skipping presubmit due to formatting issues. I'd like to have some hope of merging this back to dev. NOPRESUBMIT=true BUG=517163 TEST=New unit test. Manually verified graceful failure for MSE & SRC= R=bbudge@chromium.org, gunsch@chromium.org, sandersd@chromium.org, xhwang@chromium.org Review URL: https://codereview.chromium.org/1396583002 Cr-Commit-Position: refs/heads/master@{#354952}
-rw-r--r--chromecast/common/media/cma_param_traits.cc29
-rw-r--r--chromecast/media/audio/cast_audio_output_stream.cc2
-rw-r--r--chromecast/media/cma/base/decoder_config_adapter.cc17
-rw-r--r--chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc18
-rw-r--r--chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc18
-rw-r--r--chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc7
-rw-r--r--chromecast/media/cma/test/mock_frame_provider.cc6
-rw-r--r--chromecast/renderer/media/demuxer_stream_for_test.cc7
-rw-r--r--content/common/gpu/media/video_encode_accelerator_unittest.cc5
-rw-r--r--content/renderer/media/android/media_source_delegate.cc6
-rw-r--r--content/renderer/pepper/content_decryptor_delegate.cc16
-rw-r--r--content/renderer/pepper/video_decoder_shim.cc5
-rw-r--r--media/base/BUILD.gn2
-rw-r--r--media/base/audio_decoder_config.cc18
-rw-r--r--media/base/audio_decoder_config.h23
-rw-r--r--media/base/fake_demuxer_stream.cc6
-rw-r--r--media/base/media_util.cc13
-rw-r--r--media/base/media_util.h21
-rw-r--r--media/base/test_helpers.cc5
-rw-r--r--media/base/video_decoder_config.cc30
-rw-r--r--media/base/video_decoder_config.h11
-rw-r--r--media/base/video_decoder_config_unittest.cc17
-rw-r--r--media/cast/sender/h264_vt_encoder_unittest.cc3
-rw-r--r--media/ffmpeg/ffmpeg_common.cc93
-rw-r--r--media/ffmpeg/ffmpeg_common.h17
-rw-r--r--media/ffmpeg/ffmpeg_common_unittest.cc102
-rw-r--r--media/filters/audio_decoder_selector_unittest.cc9
-rw-r--r--media/filters/audio_decoder_unittest.cc18
-rw-r--r--media/filters/chunk_demuxer_unittest.cc14
-rw-r--r--media/filters/decrypting_audio_decoder_unittest.cc19
-rw-r--r--media/filters/decrypting_demuxer_stream.cc2
-rw-r--r--media/filters/decrypting_demuxer_stream_unittest.cc35
-rw-r--r--media/filters/ffmpeg_demuxer.cc114
-rw-r--r--media/filters/ffmpeg_demuxer.h25
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc6
-rw-r--r--media/filters/ffmpeg_glue.cc2
-rw-r--r--media/filters/ffmpeg_video_decoder_unittest.cc11
-rw-r--r--media/filters/frame_processor_unittest.cc12
-rw-r--r--media/filters/opus_audio_decoder.cc4
-rw-r--r--media/filters/source_buffer_stream_unittest.cc19
-rw-r--r--media/formats/mp2t/es_adapter_video_unittest.cc3
-rw-r--r--media/formats/mp2t/es_parser_adts.cc10
-rw-r--r--media/formats/mp2t/es_parser_h264.cc4
-rw-r--r--media/formats/mp2t/es_parser_mpeg1audio.cc4
-rw-r--r--media/formats/mp4/mp4_stream_parser.cc21
-rw-r--r--media/formats/mpeg/mpeg_audio_stream_parser_base.cc3
-rw-r--r--media/formats/webm/webm_audio_client.cc10
-rw-r--r--media/formats/webm/webm_video_client.cc10
-rw-r--r--media/media.gyp2
-rw-r--r--media/mojo/services/media_type_converters.cc23
-rw-r--r--media/mojo/services/media_type_converters_unittest.cc16
-rw-r--r--media/renderers/audio_renderer_impl_unittest.cc4
52 files changed, 544 insertions, 353 deletions
diff --git a/chromecast/common/media/cma_param_traits.cc b/chromecast/common/media/cma_param_traits.cc
index ab0f62a..2ae4fd9 100644
--- a/chromecast/common/media/cma_param_traits.cc
+++ b/chromecast/common/media/cma_param_traits.cc
@@ -34,13 +34,7 @@ void ParamTraits<media::AudioDecoderConfig>::Write(
WriteParam(m, p.channel_layout());
WriteParam(m, p.samples_per_second());
WriteParam(m, p.is_encrypted());
- std::vector<uint8> extra_data;
- if (p.extra_data_size() > 0) {
- extra_data =
- std::vector<uint8>(p.extra_data(),
- p.extra_data() + p.extra_data_size());
- }
- WriteParam(m, extra_data);
+ WriteParam(m, p.extra_data());
}
bool ParamTraits<media::AudioDecoderConfig>::Read(
@@ -58,13 +52,8 @@ bool ParamTraits<media::AudioDecoderConfig>::Read(
!ReadParam(m, iter, &samples_per_second) ||
!ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
return false;
- const uint8* extra_data_ptr = nullptr;
- if (!extra_data.empty())
- extra_data_ptr = &extra_data[0];
*r = media::AudioDecoderConfig(codec, sample_format, channel_layout,
- samples_per_second,
- extra_data_ptr, extra_data.size(),
- is_encrypted);
+ samples_per_second, extra_data, is_encrypted);
return true;
}
@@ -83,13 +72,7 @@ void ParamTraits<media::VideoDecoderConfig>::Write(
WriteParam(m, p.visible_rect());
WriteParam(m, p.natural_size());
WriteParam(m, p.is_encrypted());
- std::vector<uint8> extra_data;
- if (p.extra_data_size() > 0) {
- extra_data =
- std::vector<uint8>(p.extra_data(),
- p.extra_data() + p.extra_data_size());
- }
- WriteParam(m, extra_data);
+ WriteParam(m, p.extra_data());
}
bool ParamTraits<media::VideoDecoderConfig>::Read(
@@ -111,13 +94,9 @@ bool ParamTraits<media::VideoDecoderConfig>::Read(
!ReadParam(m, iter, &natural_size) ||
!ReadParam(m, iter, &is_encrypted) || !ReadParam(m, iter, &extra_data))
return false;
- const uint8* extra_data_ptr = nullptr;
- if (!extra_data.empty())
- extra_data_ptr = &extra_data[0];
*r = media::VideoDecoderConfig(codec, profile, format, color_space,
coded_size, visible_rect, natural_size,
- extra_data_ptr, extra_data.size(),
- is_encrypted);
+ extra_data, is_encrypted);
return true;
}
diff --git a/chromecast/media/audio/cast_audio_output_stream.cc b/chromecast/media/audio/cast_audio_output_stream.cc
index e55f127..69eda32 100644
--- a/chromecast/media/audio/cast_audio_output_stream.cc
+++ b/chromecast/media/audio/cast_audio_output_stream.cc
@@ -42,8 +42,6 @@ MediaPipelineBackend::AudioDecoder* InitializeBackend(
audio_config.bytes_per_channel = audio_params.bits_per_sample() / 8;
audio_config.channel_number = audio_params.channels();
audio_config.samples_per_second = audio_params.sample_rate();
- audio_config.extra_data = nullptr;
- audio_config.extra_data_size = 0;
audio_config.is_encrypted = false;
if (!decoder->SetConfig(audio_config))
diff --git a/chromecast/media/cma/base/decoder_config_adapter.cc b/chromecast/media/cma/base/decoder_config_adapter.cc
index b75d5f2..248edd0 100644
--- a/chromecast/media/cma/base/decoder_config_adapter.cc
+++ b/chromecast/media/cma/base/decoder_config_adapter.cc
@@ -182,8 +182,8 @@ AudioConfig DecoderConfigAdapter::ToCastAudioConfig(
::media::ChannelLayoutToChannelCount(config.channel_layout()),
audio_config.samples_per_second = config.samples_per_second();
audio_config.extra_data =
- (config.extra_data_size() > 0) ? config.extra_data() : nullptr;
- audio_config.extra_data_size = config.extra_data_size();
+ (config.extra_data().empty()) ? nullptr : &config.extra_data()[0];
+ audio_config.extra_data_size = config.extra_data().size();
audio_config.is_encrypted = config.is_encrypted();
return audio_config;
}
@@ -191,11 +191,16 @@ AudioConfig DecoderConfigAdapter::ToCastAudioConfig(
// static
::media::AudioDecoderConfig DecoderConfigAdapter::ToMediaAudioDecoderConfig(
const AudioConfig& config) {
+ std::vector<uint8_t> extra_data;
+ if (config.extra_data_size > 0)
+ extra_data.assign(config.extra_data,
+ config.extra_data + config.extra_data_size);
+
return ::media::AudioDecoderConfig(
ToMediaAudioCodec(config.codec),
ToMediaSampleFormat(config.sample_format),
ToMediaChannelLayout(config.channel_number), config.samples_per_second,
- config.extra_data, config.extra_data_size, config.is_encrypted);
+ extra_data, config.is_encrypted);
}
// static
@@ -210,9 +215,9 @@ VideoConfig DecoderConfigAdapter::ToCastVideoConfig(
video_config.id = id;
video_config.codec = ToVideoCodec(config.codec());
video_config.profile = ToVideoProfile(config.profile());
- video_config.extra_data = (config.extra_data_size() > 0) ?
- config.extra_data() : nullptr;
- video_config.extra_data_size = config.extra_data_size();
+ video_config.extra_data = (config.extra_data().empty()) ?
+ nullptr : &config.extra_data()[0];
+ video_config.extra_data_size = config.extra_data().size();
video_config.is_encrypted = config.is_encrypted();
return video_config;
}
diff --git a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
index d595bda..2bc40f4 100644
--- a/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
+++ b/chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.cc
@@ -4,6 +4,8 @@
#include "chromecast/media/cma/ipc_streamer/audio_decoder_config_marshaller.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "chromecast/media/cma/ipc/media_message.h"
@@ -24,9 +26,10 @@ void AudioDecoderConfigMarshaller::Write(
CHECK(msg->WritePod(config.samples_per_second()));
CHECK(msg->WritePod(config.sample_format()));
CHECK(msg->WritePod(config.is_encrypted()));
- CHECK(msg->WritePod(config.extra_data_size()));
- if (config.extra_data_size() > 0)
- CHECK(msg->WriteBuffer(config.extra_data(), config.extra_data_size()));
+ CHECK(msg->WritePod(config.extra_data().size()));
+ if (!config.extra_data().empty())
+ CHECK(msg->WriteBuffer(&config.extra_data()[0],
+ config.extra_data().size()));
}
// static
@@ -38,7 +41,7 @@ void AudioDecoderConfigMarshaller::Write(
int samples_per_second;
bool is_encrypted;
size_t extra_data_size;
- scoped_ptr<uint8[]> extra_data;
+ std::vector<uint8_t> extra_data;
CHECK(msg->ReadPod(&codec));
CHECK(msg->ReadPod(&channel_layout));
@@ -55,15 +58,14 @@ void AudioDecoderConfigMarshaller::Write(
CHECK_LE(sample_format, ::media::kSampleFormatMax);
CHECK_LT(extra_data_size, kMaxExtraDataSize);
if (extra_data_size > 0) {
- extra_data.reset(new uint8[extra_data_size]);
- CHECK(msg->ReadBuffer(extra_data.get(), extra_data_size));
+ extra_data.resize(extra_data_size);
+ CHECK(msg->ReadBuffer(&extra_data[0], extra_data.size()));
}
return ::media::AudioDecoderConfig(
codec, sample_format,
channel_layout, samples_per_second,
- extra_data.get(), extra_data_size,
- is_encrypted);
+ extra_data, is_encrypted);
}
} // namespace media
diff --git a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
index 1c07352..8cd28ae 100644
--- a/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
+++ b/chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.cc
@@ -4,6 +4,8 @@
#include "chromecast/media/cma/ipc_streamer/video_decoder_config_marshaller.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "chromecast/media/cma/ipc/media_message.h"
@@ -64,9 +66,10 @@ void VideoDecoderConfigMarshaller::Write(
RectMarshaller::Write(config.visible_rect(), msg);
SizeMarshaller::Write(config.natural_size(), msg);
CHECK(msg->WritePod(config.is_encrypted()));
- CHECK(msg->WritePod(config.extra_data_size()));
- if (config.extra_data_size() > 0)
- CHECK(msg->WriteBuffer(config.extra_data(), config.extra_data_size()));
+ CHECK(msg->WritePod(config.extra_data().size()));
+ if (!config.extra_data().empty())
+ CHECK(msg->WriteBuffer(&config.extra_data()[0],
+ config.extra_data().size()));
}
// static
@@ -81,7 +84,7 @@ void VideoDecoderConfigMarshaller::Write(
gfx::Size natural_size;
bool is_encrypted;
size_t extra_data_size;
- scoped_ptr<uint8[]> extra_data;
+ std::vector<uint8_t> extra_data;
CHECK(msg->ReadPod(&codec));
CHECK(msg->ReadPod(&profile));
@@ -103,15 +106,14 @@ void VideoDecoderConfigMarshaller::Write(
CHECK_LE(color_space, ::media::COLOR_SPACE_MAX);
CHECK_LT(extra_data_size, kMaxExtraDataSize);
if (extra_data_size > 0) {
- extra_data.reset(new uint8[extra_data_size]);
- CHECK(msg->ReadBuffer(extra_data.get(), extra_data_size));
+ extra_data.resize(extra_data_size);
+ CHECK(msg->ReadBuffer(&extra_data[0], extra_data.size()));
}
return ::media::VideoDecoderConfig(
codec, profile, format, color_space,
coded_size, visible_rect, natural_size,
- extra_data.get(), extra_data_size,
- is_encrypted);
+ extra_data, is_encrypted);
}
} // namespace media
diff --git a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
index 040f96e..981247c 100644
--- a/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
+++ b/chromecast/media/cma/pipeline/audio_video_pipeline_impl_unittest.cc
@@ -25,6 +25,7 @@
#include "chromecast/media/cma/test/mock_frame_provider.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "media/base/video_decoder_config.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -80,13 +81,13 @@ void AudioVideoPipelineImplTest::Initialize(
::media::kSampleFormatS16,
::media::CHANNEL_LAYOUT_STEREO,
44100,
- NULL, 0, false);
+ ::media::EmptyExtraData(), false);
std::vector<::media::VideoDecoderConfig> video_configs;
video_configs.push_back(::media::VideoDecoderConfig(
::media::kCodecH264, ::media::H264PROFILE_MAIN,
::media::PIXEL_FORMAT_I420, ::media::COLOR_SPACE_UNSPECIFIED,
- gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480), NULL,
- 0, false));
+ gfx::Size(640, 480), gfx::Rect(0, 0, 640, 480), gfx::Size(640, 480),
+ ::media::EmptyExtraData(), false));
// Frame generation on the producer side.
std::vector<FrameGeneratorForTest::FrameSpec> frame_specs;
diff --git a/chromecast/media/cma/test/mock_frame_provider.cc b/chromecast/media/cma/test/mock_frame_provider.cc
index 27649a7..fdab889 100644
--- a/chromecast/media/cma/test/mock_frame_provider.cc
+++ b/chromecast/media/cma/test/mock_frame_provider.cc
@@ -13,6 +13,7 @@
#include "chromecast/media/cma/test/frame_generator_for_test.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "media/base/video_decoder_config.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "ui/gfx/geometry/rect.h"
@@ -80,14 +81,15 @@ void MockFrameProvider::DoRead(const ReadCB& read_cb) {
video_config = ::media::VideoDecoderConfig(
::media::kCodecH264, ::media::VIDEO_CODEC_PROFILE_UNKNOWN,
::media::PIXEL_FORMAT_YV12, ::media::COLOR_SPACE_UNSPECIFIED,
- coded_size, visible_rect, natural_size, NULL, 0, false);
+ coded_size, visible_rect, natural_size, ::media::EmptyExtraData(),
+ false);
audio_config = ::media::AudioDecoderConfig(
::media::kCodecAAC,
::media::kSampleFormatS16,
::media::CHANNEL_LAYOUT_STEREO,
44100,
- NULL, 0,
+ ::media::EmptyExtraData(),
false);
}
diff --git a/chromecast/renderer/media/demuxer_stream_for_test.cc b/chromecast/renderer/media/demuxer_stream_for_test.cc
index 228f1de..89b45ea 100644
--- a/chromecast/renderer/media/demuxer_stream_for_test.cc
+++ b/chromecast/renderer/media/demuxer_stream_for_test.cc
@@ -2,9 +2,11 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
-#include "base/threading/thread.h"
#include "chromecast/renderer/media/demuxer_stream_for_test.h"
+#include "base/threading/thread.h"
+#include "media/base/media_util.h"
+
namespace chromecast {
namespace media {
@@ -60,8 +62,7 @@ void DemuxerStreamForTest::Read(const ReadCB& read_cb) {
coded_size,
visible_rect,
natural_size,
- NULL,
- 0,
+ ::media::EmptyExtraData(),
false);
}
diff --git a/content/common/gpu/media/video_encode_accelerator_unittest.cc b/content/common/gpu/media/video_encode_accelerator_unittest.cc
index b612bd8..e22bd42 100644
--- a/content/common/gpu/media/video_encode_accelerator_unittest.cc
+++ b/content/common/gpu/media/video_encode_accelerator_unittest.cc
@@ -28,6 +28,7 @@
#include "media/base/bind_to_current_loop.h"
#include "media/base/bitstream_buffer.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "media/base/test_data_util.h"
#include "media/base/video_decoder.h"
#include "media/base/video_frame.h"
@@ -659,11 +660,11 @@ void VideoFrameQualityValidator::Initialize(const gfx::Size& coded_size,
if (IsVP8(profile_))
config.Initialize(media::kCodecVP8, media::VP8PROFILE_ANY, kInputFormat,
media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size,
- natural_size, NULL, 0, false);
+ natural_size, media::EmptyExtraData(), false);
else if (IsH264(profile_))
config.Initialize(media::kCodecH264, media::H264PROFILE_MAIN, kInputFormat,
media::COLOR_SPACE_UNSPECIFIED, coded_size, visible_size,
- natural_size, NULL, 0, false);
+ natural_size, media::EmptyExtraData(), false);
else
LOG_ASSERT(0) << "Invalid profile " << profile_;
diff --git a/content/renderer/media/android/media_source_delegate.cc b/content/renderer/media/android/media_source_delegate.cc
index 139be4a..4c0477b 100644
--- a/content/renderer/media/android/media_source_delegate.cc
+++ b/content/renderer/media/android/media_source_delegate.cc
@@ -736,8 +736,7 @@ bool MediaSourceDelegate::GetDemuxerConfigFromStream(
media::ChannelLayoutToChannelCount(config.channel_layout());
configs->audio_sampling_rate = config.samples_per_second();
configs->is_audio_encrypted = config.is_encrypted();
- configs->audio_extra_data = std::vector<uint8>(
- config.extra_data(), config.extra_data() + config.extra_data_size());
+ configs->audio_extra_data = config.extra_data();
configs->audio_codec_delay_ns = static_cast<int64_t>(
config.codec_delay() *
(static_cast<double>(base::Time::kNanosecondsPerSecond) /
@@ -752,8 +751,7 @@ bool MediaSourceDelegate::GetDemuxerConfigFromStream(
configs->video_codec = config.codec();
configs->video_size = config.natural_size();
configs->is_video_encrypted = config.is_encrypted();
- configs->video_extra_data = std::vector<uint8>(
- config.extra_data(), config.extra_data() + config.extra_data_size());
+ configs->video_extra_data = config.extra_data();
return true;
}
return false;
diff --git a/content/renderer/pepper/content_decryptor_delegate.cc b/content/renderer/pepper/content_decryptor_delegate.cc
index a3596c8..2efb849 100644
--- a/content/renderer/pepper/content_decryptor_delegate.cc
+++ b/content/renderer/pepper/content_decryptor_delegate.cc
@@ -4,6 +4,8 @@
#include "content/renderer/pepper/content_decryptor_delegate.h"
+#include <vector>
+
#include "base/callback_helpers.h"
#include "base/metrics/sparse_histogram.h"
#include "base/numerics/safe_conversions.h"
@@ -53,27 +55,25 @@ namespace {
// reference-count of 0. If |data| is NULL, sets |*resource| to NULL. Returns
// true upon success and false if any error happened.
bool MakeBufferResource(PP_Instance instance,
- const uint8_t* data,
- uint32_t size,
+ const std::vector<uint8_t>& data,
scoped_refptr<PPB_Buffer_Impl>* resource) {
TRACE_EVENT0("media", "ContentDecryptorDelegate - MakeBufferResource");
DCHECK(resource);
- if (!data || !size) {
- DCHECK(!data && !size);
+ if (data.empty()) {
resource = NULL;
return true;
}
scoped_refptr<PPB_Buffer_Impl> buffer(
- PPB_Buffer_Impl::CreateResource(instance, size));
+ PPB_Buffer_Impl::CreateResource(instance, data.size()));
if (!buffer.get())
return false;
BufferAutoMapper mapper(buffer.get());
- if (!mapper.data() || mapper.size() < size)
+ if (!mapper.data() || mapper.size() < data.size())
return false;
- memcpy(mapper.data(), data, size);
+ memcpy(mapper.data(), &data[0], data.size());
*resource = buffer;
return true;
@@ -592,7 +592,6 @@ bool ContentDecryptorDelegate::InitializeAudioDecoder(
scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
if (!MakeBufferResource(pp_instance_,
decoder_config.extra_data(),
- decoder_config.extra_data_size(),
&extra_data_resource)) {
return false;
}
@@ -621,7 +620,6 @@ bool ContentDecryptorDelegate::InitializeVideoDecoder(
scoped_refptr<PPB_Buffer_Impl> extra_data_resource;
if (!MakeBufferResource(pp_instance_,
decoder_config.extra_data(),
- decoder_config.extra_data_size(),
&extra_data_resource)) {
return false;
}
diff --git a/content/renderer/pepper/video_decoder_shim.cc b/content/renderer/pepper/video_decoder_shim.cc
index d84ac81..d3c3d1b 100644
--- a/content/renderer/pepper/video_decoder_shim.cc
+++ b/content/renderer/pepper/video_decoder_shim.cc
@@ -23,6 +23,7 @@
#include "gpu/command_buffer/client/gles2_implementation.h"
#include "media/base/decoder_buffer.h"
#include "media/base/limits.h"
+#include "media/base/media_util.h"
#include "media/base/video_decoder.h"
#include "media/blink/skcanvas_video_renderer.h"
#include "media/filters/ffmpeg_video_decoder.h"
@@ -882,8 +883,8 @@ bool VideoDecoderShim::Initialize(
codec, profile, media::PIXEL_FORMAT_YV12, media::COLOR_SPACE_UNSPECIFIED,
gfx::Size(32, 24), // Small sizes that won't fail.
gfx::Rect(32, 24), gfx::Size(32, 24),
- NULL /* extra_data */, // TODO(bbudge) Verify this isn't needed.
- 0 /* extra_data_size */, false /* decryption */);
+ // TODO(bbudge): Verify extra data isn't needed.
+ media::EmptyExtraData(), false /* decryption */);
media_task_runner_->PostTask(
FROM_HERE,
diff --git a/media/base/BUILD.gn b/media/base/BUILD.gn
index 0bab261..0e9ec454 100644
--- a/media/base/BUILD.gn
+++ b/media/base/BUILD.gn
@@ -122,6 +122,8 @@ source_set("base") {
"media_resources.h",
"media_switches.cc",
"media_switches.h",
+ "media_util.cc",
+ "media_util.h",
"mime_util.cc",
"mime_util.h",
"moving_average.cc",
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index 6dc5b2f..213cb10 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -24,30 +24,26 @@ AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec,
SampleFormat sample_format,
ChannelLayout channel_layout,
int samples_per_second,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted) {
Initialize(codec, sample_format, channel_layout, samples_per_second,
- extra_data, extra_data_size, is_encrypted, base::TimeDelta(), 0);
+ extra_data, is_encrypted, base::TimeDelta(), 0);
}
void AudioDecoderConfig::Initialize(AudioCodec codec,
SampleFormat sample_format,
ChannelLayout channel_layout,
int samples_per_second,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted,
base::TimeDelta seek_preroll,
int codec_delay) {
- CHECK((extra_data_size != 0) == (extra_data != NULL));
-
codec_ = codec;
channel_layout_ = channel_layout;
samples_per_second_ = samples_per_second;
sample_format_ = sample_format;
bytes_per_channel_ = SampleFormatToBytesPerChannel(sample_format);
- extra_data_.assign(extra_data, extra_data + extra_data_size);
+ extra_data_ = extra_data;
is_encrypted_ = is_encrypted;
seek_preroll_ = seek_preroll;
codec_delay_ = codec_delay;
@@ -75,9 +71,7 @@ bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
(bytes_per_channel() == config.bytes_per_channel()) &&
(channel_layout() == config.channel_layout()) &&
(samples_per_second() == config.samples_per_second()) &&
- (extra_data_size() == config.extra_data_size()) &&
- (!extra_data() || !memcmp(extra_data(), config.extra_data(),
- extra_data_size())) &&
+ (extra_data() == config.extra_data()) &&
(is_encrypted() == config.is_encrypted()) &&
(sample_format() == config.sample_format()) &&
(seek_preroll() == config.seek_preroll()) &&
@@ -94,7 +88,7 @@ std::string AudioDecoderConfig::AsHumanReadableString() const {
<< " bytes_per_frame: " << bytes_per_frame()
<< " seek_preroll: " << seek_preroll().InMilliseconds() << "ms"
<< " codec_delay: " << codec_delay()
- << " has extra data? " << (extra_data() ? "true" : "false")
+ << " has extra data? " << (extra_data().empty() ? "false" : "true")
<< " encrypted? " << (is_encrypted() ? "true" : "false");
return s.str();
}
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index c9c8593..ae72383 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -55,22 +55,22 @@ class MEDIA_EXPORT AudioDecoderConfig {
// appropriate values before using.
AudioDecoderConfig();
- // Constructs an initialized object. It is acceptable to pass in NULL for
- // |extra_data|, otherwise the memory is copied.
- AudioDecoderConfig(AudioCodec codec, SampleFormat sample_format,
- ChannelLayout channel_layout, int samples_per_second,
- const uint8* extra_data, size_t extra_data_size,
+ // Constructs an initialized object.
+ AudioDecoderConfig(AudioCodec codec,
+ SampleFormat sample_format,
+ ChannelLayout channel_layout,
+ int samples_per_second,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted);
~AudioDecoderConfig();
- // Resets the internal state of this object. |codec_delay| is in frames.
+ // Resets the internal state of this object. |codec_delay| is in frames.
void Initialize(AudioCodec codec,
SampleFormat sample_format,
ChannelLayout channel_layout,
int samples_per_second,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8>& extra_data,
bool is_encrypted,
base::TimeDelta seek_preroll,
int codec_delay);
@@ -101,10 +101,7 @@ class MEDIA_EXPORT AudioDecoderConfig {
// Optional byte data required to initialize audio decoders such as Vorbis
// codebooks.
- const uint8* extra_data() const {
- return extra_data_.empty() ? NULL : &extra_data_[0];
- }
- size_t extra_data_size() const { return extra_data_.size(); }
+ const std::vector<uint8_t>& extra_data() const { return extra_data_; }
// Whether the audio stream is potentially encrypted.
// Note that in a potentially encrypted audio stream, individual buffers
@@ -118,7 +115,7 @@ class MEDIA_EXPORT AudioDecoderConfig {
ChannelLayout channel_layout_;
int samples_per_second_;
int bytes_per_frame_;
- std::vector<uint8> extra_data_;
+ std::vector<uint8_t> extra_data_;
bool is_encrypted_;
// |seek_preroll_| is the duration of the data that the decoder must decode
diff --git a/media/base/fake_demuxer_stream.cc b/media/base/fake_demuxer_stream.cc
index 30ff406..fab0396 100644
--- a/media/base/fake_demuxer_stream.cc
+++ b/media/base/fake_demuxer_stream.cc
@@ -4,6 +4,8 @@
#include "media/base/fake_demuxer_stream.h"
+#include <vector>
+
#include "base/bind.h"
#include "base/callback_helpers.h"
#include "base/location.h"
@@ -12,6 +14,7 @@
#include "base/thread_task_runner_handle.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "media/base/test_helpers.h"
#include "media/base/timestamp_constants.h"
#include "media/base/video_frame.h"
@@ -146,7 +149,8 @@ void FakeDemuxerStream::UpdateVideoDecoderConfig() {
video_decoder_config_.Initialize(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED,
next_coded_size_, kVisibleRect,
- next_coded_size_, NULL, 0, is_encrypted_);
+ next_coded_size_, EmptyExtraData(),
+ is_encrypted_);
next_coded_size_.Enlarge(kWidthDelta, kHeightDelta);
}
diff --git a/media/base/media_util.cc b/media/base/media_util.cc
new file mode 100644
index 0000000..bd7929f
--- /dev/null
+++ b/media/base/media_util.cc
@@ -0,0 +1,13 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#include "media/base/media_util.h"
+
+namespace media {
+
+std::vector<uint8_t> EmptyExtraData() {
+ return std::vector<uint8_t>();
+}
+
+} // namespace media
diff --git a/media/base/media_util.h b/media/base/media_util.h
new file mode 100644
index 0000000..4e53c9a
--- /dev/null
+++ b/media/base/media_util.h
@@ -0,0 +1,21 @@
+// Copyright 2015 The Chromium Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef MEDIA_BASE_UTIL_H_
+#define MEDIA_BASE_UTIL_H_
+
+#include <stdint.h>
+#include <vector>
+
+#include "media/base/media_export.h"
+
+namespace media {
+
+// Simply returns an empty vector. {Audio|Video}DecoderConfig are often
+// constructed with empty extra data.
+MEDIA_EXPORT std::vector<uint8_t> EmptyExtraData();
+
+} // namespace media
+
+#endif // MEDIA_BASE_UTIL_H_
diff --git a/media/base/test_helpers.cc b/media/base/test_helpers.cc
index 5da16ad..84074bf 100644
--- a/media/base/test_helpers.cc
+++ b/media/base/test_helpers.cc
@@ -15,6 +15,7 @@
#include "media/base/audio_buffer.h"
#include "media/base/bind_to_current_loop.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "ui/gfx/geometry/rect.h"
using ::testing::_;
@@ -127,8 +128,8 @@ static VideoDecoderConfig GetTestConfig(VideoCodec codec,
return VideoDecoderConfig(codec, VIDEO_CODEC_PROFILE_UNKNOWN,
PIXEL_FORMAT_YV12, COLOR_SPACE_UNSPECIFIED,
- coded_size, visible_rect, natural_size, NULL, 0,
- is_encrypted);
+ coded_size, visible_rect, natural_size,
+ EmptyExtraData(), is_encrypted);
}
static const gfx::Size kNormalSize(320, 240);
diff --git a/media/base/video_decoder_config.cc b/media/base/video_decoder_config.cc
index f867ad1..84058e4 100644
--- a/media/base/video_decoder_config.cc
+++ b/media/base/video_decoder_config.cc
@@ -4,6 +4,8 @@
#include "media/base/video_decoder_config.h"
+#include <vector>
+
#include "base/logging.h"
#include "media/base/video_frame.h"
@@ -34,13 +36,11 @@ VideoCodec VideoCodecProfileToVideoCodec(VideoCodecProfile profile) {
return kUnknownVideoCodec;
}
-
VideoDecoderConfig::VideoDecoderConfig()
: codec_(kUnknownVideoCodec),
profile_(VIDEO_CODEC_PROFILE_UNKNOWN),
format_(PIXEL_FORMAT_UNKNOWN),
- is_encrypted_(false) {
-}
+ is_encrypted_(false) {}
VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
VideoCodecProfile profile,
@@ -49,11 +49,10 @@ VideoDecoderConfig::VideoDecoderConfig(VideoCodec codec,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted) {
Initialize(codec, profile, format, color_space, coded_size, visible_rect,
- natural_size, extra_data, extra_data_size, is_encrypted);
+ natural_size, extra_data, is_encrypted);
}
VideoDecoderConfig::~VideoDecoderConfig() {}
@@ -65,11 +64,8 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted) {
- CHECK((extra_data_size != 0) == (extra_data != NULL));
-
codec_ = codec;
profile_ = profile;
format_ = format;
@@ -77,7 +73,7 @@ void VideoDecoderConfig::Initialize(VideoCodec codec,
coded_size_ = coded_size;
visible_rect_ = visible_rect;
natural_size_ = natural_size;
- extra_data_.assign(extra_data, extra_data + extra_data_size);
+ extra_data_ = extra_data;
is_encrypted_ = is_encrypted;
}
@@ -96,9 +92,7 @@ bool VideoDecoderConfig::Matches(const VideoDecoderConfig& config) const {
(coded_size() == config.coded_size()) &&
(visible_rect() == config.visible_rect()) &&
(natural_size() == config.natural_size()) &&
- (extra_data_size() == config.extra_data_size()) &&
- (!extra_data() || !memcmp(extra_data(), config.extra_data(),
- extra_data_size())) &&
+ (extra_data() == config.extra_data()) &&
(is_encrypted() == config.is_encrypted()));
}
@@ -115,7 +109,7 @@ std::string VideoDecoderConfig::AsHumanReadableString() const {
<< "," << visible_rect().height() << "]"
<< " natural size: [" << natural_size().width()
<< "," << natural_size().height() << "]"
- << " has extra data? " << (extra_data() ? "true" : "false")
+ << " has extra data? " << (extra_data().empty() ? "false" : "true")
<< " encrypted? " << (is_encrypted() ? "true" : "false");
return s.str();
}
@@ -146,10 +140,4 @@ std::string VideoDecoderConfig::GetHumanReadableCodecName() const {
return "";
}
-const uint8* VideoDecoderConfig::extra_data() const {
- if (extra_data_.empty())
- return NULL;
- return &extra_data_[0];
-}
-
} // namespace media
diff --git a/media/base/video_decoder_config.h b/media/base/video_decoder_config.h
index 0dae77c8..3de0d2f 100644
--- a/media/base/video_decoder_config.h
+++ b/media/base/video_decoder_config.h
@@ -35,8 +35,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted);
~VideoDecoderConfig();
@@ -49,8 +48,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
const gfx::Size& coded_size,
const gfx::Rect& visible_rect,
const gfx::Size& natural_size,
- const uint8* extra_data,
- size_t extra_data_size,
+ const std::vector<uint8_t>& extra_data,
bool is_encrypted);
// Returns true if this object has appropriate configuration values, false
@@ -91,8 +89,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
// Optional byte data required to initialize video decoders, such as H.264
// AAVC data.
- const uint8* extra_data() const;
- size_t extra_data_size() const { return extra_data_.size(); }
+ const std::vector<uint8_t>& extra_data() const { return extra_data_; }
// Whether the video stream is potentially encrypted.
// Note that in a potentially encrypted video stream, individual buffers
@@ -110,7 +107,7 @@ class MEDIA_EXPORT VideoDecoderConfig {
gfx::Rect visible_rect_;
gfx::Size natural_size_;
- std::vector<uint8> extra_data_;
+ std::vector<uint8_t> extra_data_;
bool is_encrypted_;
diff --git a/media/base/video_decoder_config_unittest.cc b/media/base/video_decoder_config_unittest.cc
index d3787d2..7885c8f 100644
--- a/media/base/video_decoder_config_unittest.cc
+++ b/media/base/video_decoder_config_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include "media/base/limits.h"
+#include "media/base/media_util.h"
#include "media/base/video_decoder_config.h"
#include "media/base/video_util.h"
#include "testing/gtest/include/gtest/gtest.h"
@@ -17,8 +18,8 @@ static const gfx::Size kNaturalSize(320, 240);
TEST(VideoDecoderConfigTest, Invalid_UnsupportedPixelFormat) {
VideoDecoderConfig config(kCodecVP8, VIDEO_CODEC_PROFILE_UNKNOWN,
PIXEL_FORMAT_UNKNOWN, COLOR_SPACE_UNSPECIFIED,
- kCodedSize, kVisibleRect, kNaturalSize, NULL, 0,
- false);
+ kCodedSize, kVisibleRect, kNaturalSize,
+ EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -26,7 +27,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioNumeratorZero) {
gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 0, 1);
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -34,7 +35,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioDenominatorZero) {
gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, 0);
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -42,7 +43,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioNumeratorNegative) {
gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), -1, 1);
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -50,7 +51,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioDenominatorNegative) {
gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), 1, -1);
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -60,7 +61,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioNumeratorTooLarge) {
gfx::Size natural_size = GetNaturalSize(kVisibleRect.size(), num, 1);
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
@@ -71,7 +72,7 @@ TEST(VideoDecoderConfigTest, Invalid_AspectRatioDenominatorTooLarge) {
EXPECT_EQ(0, natural_size.width());
VideoDecoderConfig config(kCodecVP8, VP8PROFILE_ANY, kVideoFormat,
COLOR_SPACE_UNSPECIFIED, kCodedSize, kVisibleRect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
EXPECT_FALSE(config.IsValidConfig());
}
diff --git a/media/cast/sender/h264_vt_encoder_unittest.cc b/media/cast/sender/h264_vt_encoder_unittest.cc
index 7ef7eef..e44d9f8 100644
--- a/media/cast/sender/h264_vt_encoder_unittest.cc
+++ b/media/cast/sender/h264_vt_encoder_unittest.cc
@@ -15,6 +15,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/media.h"
#include "media/base/media_switches.h"
+#include "media/base/media_util.h"
#include "media/cast/sender/h264_vt_encoder.h"
#include "media/cast/sender/video_frame_factory.h"
#include "media/cast/test/utility/default_config.h"
@@ -308,7 +309,7 @@ TEST_F(H264VideoToolboxEncoderTest, CheckFramesAreDecodable) {
VideoDecoderConfig config(kCodecH264, H264PROFILE_MAIN, frame_->format(),
COLOR_SPACE_UNSPECIFIED, frame_->coded_size(),
frame_->visible_rect(), frame_->natural_size(),
- nullptr, 0, false);
+ EmptyExtraData(), false);
scoped_refptr<EndToEndFrameChecker> checker(new EndToEndFrameChecker(config));
VideoEncoder::FrameEncodedCallback cb =
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index e6d5e91..c9d8669 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -6,6 +6,7 @@
#include "base/basictypes.h"
#include "base/logging.h"
+#include "base/memory/scoped_ptr.h"
#include "base/sha1.h"
#include "base/strings/string_number_conversions.h"
#include "base/strings/string_split.h"
@@ -285,7 +286,7 @@ static AVSampleFormat SampleFormatToAVSampleFormat(SampleFormat sample_format) {
return AV_SAMPLE_FMT_NONE;
}
-void AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
+bool AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
bool is_encrypted,
AudioDecoderConfig* config) {
DCHECK_EQ(codec_context->codec_type, AVMEDIA_TYPE_AUDIO);
@@ -319,12 +320,26 @@ void AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
codec_context->seek_preroll * 1000000.0 / codec_context->sample_rate);
}
+ // AVStream occasionally has invalid extra data. See http://crbug.com/517163
+ if ((codec_context->extradata_size == 0) !=
+ (codec_context->extradata == nullptr)) {
+ LOG(ERROR) << __FUNCTION__
+ << (codec_context->extradata == nullptr ? " NULL" : " Non-NULL")
+ << " extra data cannot have size of "
+ << codec_context->extradata_size << ".";
+ return false;
+ }
+
+ std::vector<uint8_t> extra_data;
+ if (codec_context->extradata_size > 0) {
+ extra_data.assign(codec_context->extradata,
+ codec_context->extradata + codec_context->extradata_size);
+ }
config->Initialize(codec,
sample_format,
channel_layout,
sample_rate,
- codec_context->extradata,
- codec_context->extradata_size,
+ extra_data,
is_encrypted,
seek_preroll,
codec_context->delay);
@@ -333,15 +348,19 @@ void AVCodecContextToAudioDecoderConfig(const AVCodecContext* codec_context,
DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
config->bits_per_channel());
}
+
+ return true;
}
-void AVStreamToAudioDecoderConfig(const AVStream* stream,
+bool AVStreamToAudioDecoderConfig(const AVStream* stream,
AudioDecoderConfig* config) {
bool is_encrypted = false;
- AVDictionaryEntry* key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
+ AVDictionaryEntry* key =
+ av_dict_get(stream->metadata, "enc_key_id", nullptr, 0);
if (key)
is_encrypted = true;
- AVCodecContextToAudioDecoderConfig(stream->codec, is_encrypted, config);
+ return AVCodecContextToAudioDecoderConfig(stream->codec, is_encrypted,
+ config);
}
void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
@@ -358,21 +377,21 @@ void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
ChannelLayoutToChannelCount(config.channel_layout());
codec_context->sample_rate = config.samples_per_second();
- if (config.extra_data()) {
- codec_context->extradata_size = config.extra_data_size();
+ if (config.extra_data().empty()) {
+ codec_context->extradata = nullptr;
+ codec_context->extradata_size = 0;
+ } else {
+ codec_context->extradata_size = config.extra_data().size();
codec_context->extradata = reinterpret_cast<uint8_t*>(
- av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
- memcpy(codec_context->extradata, config.extra_data(),
- config.extra_data_size());
- memset(codec_context->extradata + config.extra_data_size(), '\0',
+ av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE));
+ memcpy(codec_context->extradata, &config.extra_data()[0],
+ config.extra_data().size());
+ memset(codec_context->extradata + config.extra_data().size(), '\0',
FF_INPUT_BUFFER_PADDING_SIZE);
- } else {
- codec_context->extradata = NULL;
- codec_context->extradata_size = 0;
}
}
-void AVStreamToVideoDecoderConfig(const AVStream* stream,
+bool AVStreamToVideoDecoderConfig(const AVStream* stream,
VideoDecoderConfig* config) {
gfx::Size coded_size(stream->codec->coded_width, stream->codec->coded_height);
@@ -433,12 +452,13 @@ void AVStreamToVideoDecoderConfig(const AVStream* stream,
}
bool is_encrypted = false;
- AVDictionaryEntry* key = av_dict_get(stream->metadata, "enc_key_id", NULL, 0);
+ AVDictionaryEntry* key =
+ av_dict_get(stream->metadata, "enc_key_id", nullptr, 0);
if (key)
is_encrypted = true;
AVDictionaryEntry* webm_alpha =
- av_dict_get(stream->metadata, "alpha_mode", NULL, 0);
+ av_dict_get(stream->metadata, "alpha_mode", nullptr, 0);
if (webm_alpha && !strcmp(webm_alpha->value, "1")) {
format = PIXEL_FORMAT_YV12A;
}
@@ -453,9 +473,24 @@ void AVStreamToVideoDecoderConfig(const AVStream* stream,
: COLOR_SPACE_HD_REC709;
}
+ // AVStream occasionally has invalid extra data. See http://crbug.com/517163
+ if ((stream->codec->extradata_size == 0) !=
+ (stream->codec->extradata == nullptr)) {
+ LOG(ERROR) << __FUNCTION__
+ << (stream->codec->extradata == nullptr ? " NULL" : " Non-Null")
+ << " extra data cannot have size of "
+ << stream->codec->extradata_size << ".";
+ return false;
+ }
+
+ std::vector<uint8_t> extra_data;
+ if (stream->codec->extradata_size > 0) {
+ extra_data.assign(stream->codec->extradata,
+ stream->codec->extradata + stream->codec->extradata_size);
+ }
config->Initialize(codec, profile, format, color_space, coded_size,
- visible_rect, natural_size, stream->codec->extradata,
- stream->codec->extradata_size, is_encrypted);
+ visible_rect, natural_size, extra_data, is_encrypted);
+ return true;
}
void VideoDecoderConfigToAVCodecContext(
@@ -470,17 +505,17 @@ void VideoDecoderConfigToAVCodecContext(
if (config.color_space() == COLOR_SPACE_JPEG)
codec_context->color_range = AVCOL_RANGE_JPEG;
- if (config.extra_data()) {
- codec_context->extradata_size = config.extra_data_size();
+ if (config.extra_data().empty()) {
+ codec_context->extradata = nullptr;
+ codec_context->extradata_size = 0;
+ } else {
+ codec_context->extradata_size = config.extra_data().size();
codec_context->extradata = reinterpret_cast<uint8_t*>(
- av_malloc(config.extra_data_size() + FF_INPUT_BUFFER_PADDING_SIZE));
- memcpy(codec_context->extradata, config.extra_data(),
- config.extra_data_size());
- memset(codec_context->extradata + config.extra_data_size(), '\0',
+ av_malloc(config.extra_data().size() + FF_INPUT_BUFFER_PADDING_SIZE));
+ memcpy(codec_context->extradata, &config.extra_data()[0],
+ config.extra_data().size());
+ memset(codec_context->extradata + config.extra_data().size(), '\0',
FF_INPUT_BUFFER_PADDING_SIZE);
- } else {
- codec_context->extradata = NULL;
- codec_context->extradata_size = 0;
}
}
diff --git a/media/ffmpeg/ffmpeg_common.h b/media/ffmpeg/ffmpeg_common.h
index 677bd76..f4a8237 100644
--- a/media/ffmpeg/ffmpeg_common.h
+++ b/media/ffmpeg/ffmpeg_common.h
@@ -85,19 +85,26 @@ MEDIA_EXPORT base::TimeDelta ConvertFromTimeBase(const AVRational& time_base,
MEDIA_EXPORT int64 ConvertToTimeBase(const AVRational& time_base,
const base::TimeDelta& timestamp);
-void AVStreamToAudioDecoderConfig(const AVStream* stream,
- AudioDecoderConfig* config);
+// Returns true if AVStream is successfully converted to a AudioDecoderConfig.
+// Returns false if conversion fails, in which case |config| is not modified.
+MEDIA_EXPORT bool AVStreamToAudioDecoderConfig(const AVStream* stream,
+ AudioDecoderConfig* config);
void AudioDecoderConfigToAVCodecContext(
const AudioDecoderConfig& config,
AVCodecContext* codec_context);
-void AVStreamToVideoDecoderConfig(const AVStream* stream,
- VideoDecoderConfig* config);
+// Returns true if AVStream is successfully converted to a VideoDecoderConfig.
+// Returns false if conversion fails, in which case |config| is not modified.
+MEDIA_EXPORT bool AVStreamToVideoDecoderConfig(const AVStream* stream,
+ VideoDecoderConfig* config);
void VideoDecoderConfigToAVCodecContext(
const VideoDecoderConfig& config,
AVCodecContext* codec_context);
-MEDIA_EXPORT void AVCodecContextToAudioDecoderConfig(
+// Returns true if AVCodecContext is successfully converted to an
+// AudioDecoderConfig. Returns false if conversion fails, in which case |config|
+// is not modified.
+MEDIA_EXPORT bool AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
bool is_encrypted,
AudioDecoderConfig* config);
diff --git a/media/ffmpeg/ffmpeg_common_unittest.cc b/media/ffmpeg/ffmpeg_common_unittest.cc
index ca68fa7..aa8a06d 100644
--- a/media/ffmpeg/ffmpeg_common_unittest.cc
+++ b/media/ffmpeg/ffmpeg_common_unittest.cc
@@ -2,11 +2,19 @@
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
+#include <cstring>
+
+#include "base/bind.h"
+#include "base/files/memory_mapped_file.h"
#include "base/logging.h"
#include "base/memory/scoped_ptr.h"
+#include "media/base/audio_decoder_config.h"
#include "media/base/media.h"
+#include "media/base/test_data_util.h"
+#include "media/base/video_decoder_config.h"
#include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"
+#include "media/filters/in_memory_url_protocol.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
@@ -19,6 +27,97 @@ class FFmpegCommonTest : public testing::Test {
~FFmpegCommonTest() override{};
};
+uint8_t kExtraData[5] = {0x00, 0x01, 0x02, 0x03, 0x04};
+
+template <typename T>
+void TestConfigConvertExtraData(
+ AVStream* stream,
+ T* decoder_config,
+ const base::Callback<bool(const AVStream*, T*)>& converter_fn) {
+ // Should initially convert.
+ EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+
+ // Store orig to let FFmpeg free whatever it allocated.
+ AVCodecContext* codec_context = stream->codec;
+ uint8_t* orig_extradata = codec_context->extradata;
+ int orig_extradata_size = codec_context->extradata_size;
+
+ // Valid combination: extra_data = NULL && size = 0.
+ codec_context->extradata = NULL;
+ codec_context->extradata_size = 0;
+ EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+ EXPECT_EQ(static_cast<size_t>(codec_context->extradata_size),
+ decoder_config->extra_data().size());
+
+ // Valid combination: extra_data = non-NULL && size > 0.
+ codec_context->extradata = &kExtraData[0];
+ codec_context->extradata_size = arraysize(kExtraData);
+ EXPECT_TRUE(converter_fn.Run(stream, decoder_config));
+ EXPECT_EQ(static_cast<size_t>(codec_context->extradata_size),
+ decoder_config->extra_data().size());
+ EXPECT_EQ(0, memcmp(codec_context->extradata,
+ &decoder_config->extra_data()[0],
+ decoder_config->extra_data().size()));
+
+ // Invalid combination: extra_data = NULL && size != 0.
+ codec_context->extradata = NULL;
+ codec_context->extradata_size = 10;
+ EXPECT_FALSE(converter_fn.Run(stream, decoder_config));
+
+ // Invalid combination: extra_data = non-NULL && size = 0.
+ codec_context->extradata = &kExtraData[0];
+ codec_context->extradata_size = 0;
+ EXPECT_FALSE(converter_fn.Run(stream, decoder_config));
+
+ // Restore orig values for sane cleanup.
+ codec_context->extradata = orig_extradata;
+ codec_context->extradata_size = orig_extradata_size;
+}
+
+TEST_F(FFmpegCommonTest, AVStreamToDecoderConfig) {
+ // Open a file to get a real AVStreams from FFmpeg.
+ base::MemoryMappedFile file;
+ file.Initialize(GetTestDataFilePath("bear-320x240.webm"));
+ InMemoryUrlProtocol protocol(file.data(), file.length(), false);
+ FFmpegGlue glue(&protocol);
+ ASSERT_TRUE(glue.OpenContext());
+ AVFormatContext* format_context = glue.format_context();
+
+ // Find the audio and video streams and test valid and invalid combinations
+ // for extradata and extradata_size.
+ bool found_audio = false;
+ bool found_video = false;
+ for (size_t i = 0;
+ i < format_context->nb_streams && (!found_audio || !found_video);
+ ++i) {
+ AVStream* stream = format_context->streams[i];
+ AVCodecContext* codec_context = stream->codec;
+ AVMediaType codec_type = codec_context->codec_type;
+
+ if (codec_type == AVMEDIA_TYPE_AUDIO) {
+ if (found_audio)
+ continue;
+ found_audio = true;
+ AudioDecoderConfig audio_config;
+ TestConfigConvertExtraData(stream, &audio_config,
+ base::Bind(&AVStreamToAudioDecoderConfig));
+ } else if (codec_type == AVMEDIA_TYPE_VIDEO) {
+ if (found_video)
+ continue;
+ found_video = true;
+ VideoDecoderConfig video_config;
+ TestConfigConvertExtraData(stream, &video_config,
+ base::Bind(&AVStreamToVideoDecoderConfig));
+ } else {
+ // Only process audio/video.
+ continue;
+ }
+ }
+
+ ASSERT_TRUE(found_audio);
+ ASSERT_TRUE(found_video);
+}
+
TEST_F(FFmpegCommonTest, OpusAudioDecoderConfig) {
AVCodecContext context = {0};
context.codec_type = AVMEDIA_TYPE_AUDIO;
@@ -31,7 +130,8 @@ TEST_F(FFmpegCommonTest, OpusAudioDecoderConfig) {
context.sample_rate = 44100;
AudioDecoderConfig decoder_config;
- AVCodecContextToAudioDecoderConfig(&context, false, &decoder_config);
+ ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(&context, false,
+ &decoder_config));
EXPECT_EQ(48000, decoder_config.samples_per_second());
}
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index 1932be3..6e248fe 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -7,6 +7,7 @@
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
#include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/filters/decoder_selector.h"
@@ -84,16 +85,16 @@ class AudioDecoderSelectorTest : public ::testing::Test {
}
void UseClearStream() {
- AudioDecoderConfig clear_audio_config(
- kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, false);
+ AudioDecoderConfig clear_audio_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100,
+ EmptyExtraData(), false);
demuxer_stream_->set_audio_decoder_config(clear_audio_config);
}
void UseEncryptedStream() {
AudioDecoderConfig encrypted_audio_config(
kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ EmptyExtraData(), true);
demuxer_stream_->set_audio_decoder_config(encrypted_audio_config);
}
diff --git a/media/filters/audio_decoder_unittest.cc b/media/filters/audio_decoder_unittest.cc
index 65db8f3..cfe6a1c 100644
--- a/media/filters/audio_decoder_unittest.cc
+++ b/media/filters/audio_decoder_unittest.cc
@@ -3,6 +3,7 @@
// found in the LICENSE file.
#include <deque>
+#include <vector>
#include "base/bind.h"
#include "base/format_macros.h"
@@ -16,6 +17,7 @@
#include "media/base/audio_bus.h"
#include "media/base/audio_hash.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
#include "media/base/timestamp_constants.h"
@@ -151,8 +153,8 @@ class AudioDecoderTest : public testing::TestWithParam<DecoderTestData> {
ASSERT_TRUE(reader_->SeekForTesting(start_timestamp_));
AudioDecoderConfig config;
- AVCodecContextToAudioDecoderConfig(reader_->codec_context_for_testing(),
- false, &config);
+ ASSERT_TRUE(AVCodecContextToAudioDecoderConfig(
+ reader_->codec_context_for_testing(), false, &config));
EXPECT_EQ(GetParam().codec, config.codec());
EXPECT_EQ(GetParam().samples_per_second, config.samples_per_second());
@@ -374,13 +376,15 @@ TEST_P(AudioDecoderTest, NoTimestamp) {
TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) {
ASSERT_EQ(GetParam().decoder_type, OPUS);
+ std::vector<uint8_t> extra_data(
+ kOpusExtraData,
+ kOpusExtraData + arraysize(kOpusExtraData));
AudioDecoderConfig decoder_config;
decoder_config.Initialize(kCodecOpus,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
48000,
- kOpusExtraData,
- arraysize(kOpusExtraData),
+ extra_data,
false,
base::TimeDelta::FromMilliseconds(80),
0);
@@ -389,14 +393,16 @@ TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithNoCodecDelay) {
TEST_P(OpusAudioDecoderBehavioralTest, InitializeWithBadCodecDelay) {
ASSERT_EQ(GetParam().decoder_type, OPUS);
+ std::vector<uint8_t> extra_data(
+ kOpusExtraData,
+ kOpusExtraData + arraysize(kOpusExtraData));
AudioDecoderConfig decoder_config;
decoder_config.Initialize(
kCodecOpus,
kSampleFormatF32,
CHANNEL_LAYOUT_STEREO,
48000,
- kOpusExtraData,
- arraysize(kOpusExtraData),
+ extra_data,
false,
base::TimeDelta::FromMilliseconds(80),
// Use a different codec delay than in the extradata.
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 747e512..1b6b894 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -736,8 +736,8 @@ class ChunkDemuxerTest : public ::testing::Test {
// bear-320x240.webm : [0-501) [801-2736)
// bear-640x360.webm : [527-793)
//
- // bear-320x240.webm AudioDecoderConfig returns 3863 for its extra_data_size()
- // bear-640x360.webm AudioDecoderConfig returns 3935 for its extra_data_size()
+ // bear-320x240.webm AudioDecoderConfig returns 3863 for its extra_data size.
+ // bear-640x360.webm AudioDecoderConfig returns 3935 for its extra_data size.
// The resulting audio stream returns data from each file for the following
// time ranges.
// bear-320x240.webm : [0-524) [779-2736)
@@ -1247,8 +1247,7 @@ TEST_F(ChunkDemuxerTest, Init) {
EXPECT_EQ(32, config.bits_per_channel());
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
EXPECT_EQ(44100, config.samples_per_second());
- EXPECT_TRUE(config.extra_data());
- EXPECT_GT(config.extra_data_size(), 0u);
+ EXPECT_GT(config.extra_data().size(), 0u);
EXPECT_EQ(kSampleFormatPlanarF32, config.sample_format());
EXPECT_EQ(is_audio_encrypted,
audio_stream->audio_decoder_config().is_encrypted());
@@ -1317,8 +1316,7 @@ TEST_F(ChunkDemuxerTest, InitText) {
EXPECT_EQ(32, config.bits_per_channel());
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, config.channel_layout());
EXPECT_EQ(44100, config.samples_per_second());
- EXPECT_TRUE(config.extra_data());
- EXPECT_GT(config.extra_data_size(), 0u);
+ EXPECT_GT(config.extra_data().size(), 0u);
EXPECT_EQ(kSampleFormatPlanarF32, config.sample_format());
EXPECT_EQ(is_audio_encrypted,
audio_stream->audio_decoder_config().is_encrypted());
@@ -2887,7 +2885,7 @@ TEST_F(ChunkDemuxerTest, ConfigChange_Audio) {
const AudioDecoderConfig& audio_config_1 = audio->audio_decoder_config();
ASSERT_TRUE(audio_config_1.IsValidConfig());
EXPECT_EQ(audio_config_1.samples_per_second(), 44100);
- EXPECT_EQ(audio_config_1.extra_data_size(), 3863u);
+ EXPECT_EQ(audio_config_1.extra_data().size(), 3863u);
ExpectRead(DemuxerStream::AUDIO, 0);
@@ -2901,7 +2899,7 @@ TEST_F(ChunkDemuxerTest, ConfigChange_Audio) {
const AudioDecoderConfig& audio_config_2 = audio->audio_decoder_config();
ASSERT_TRUE(audio_config_2.IsValidConfig());
EXPECT_EQ(audio_config_2.samples_per_second(), 44100);
- EXPECT_EQ(audio_config_2.extra_data_size(), 3935u);
+ EXPECT_EQ(audio_config_2.extra_data().size(), 3935u);
// The next config change is from a splice frame representing an overlap of
// buffers from config 2 by buffers from config 1.
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index d6ef2b9..4f749ce 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -12,6 +12,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/base/timestamp_constants.h"
@@ -118,8 +119,8 @@ class DecryptingAudioDecoderTest : public testing::Test {
.WillOnce(SaveArg<1>(&key_added_cb_));
config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true,
- base::TimeDelta(), 0);
+ CHANNEL_LAYOUT_STEREO, kSampleRate, EmptyExtraData(),
+ true, base::TimeDelta(), 0);
InitializeAndExpectResult(config_, true);
}
@@ -287,7 +288,8 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_Normal) {
// Ensure that DecryptingAudioDecoder only accepts encrypted audio.
TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, false);
+ CHANNEL_LAYOUT_STEREO, kSampleRate,
+ EmptyExtraData(), false);
InitializeAndExpectResult(config, false);
}
@@ -295,7 +297,7 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
// Ensure decoder handles invalid audio configs without crashing.
TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat,
- CHANNEL_LAYOUT_STEREO, 0, NULL, 0, true);
+ CHANNEL_LAYOUT_STEREO, 0, EmptyExtraData(), true);
InitializeAndExpectResult(config, false);
}
@@ -307,14 +309,16 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
ExpectDecryptorNotification(decryptor_.get(), true);
AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
+ CHANNEL_LAYOUT_STEREO, kSampleRate,
+ EmptyExtraData(), true);
InitializeAndExpectResult(config, false);
}
TEST_F(DecryptingAudioDecoderTest, Initialize_NullDecryptor) {
ExpectDecryptorNotification(NULL, false);
AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, kSampleRate, NULL, 0, true);
+ CHANNEL_LAYOUT_STEREO, kSampleRate,
+ EmptyExtraData(), true);
InitializeAndExpectResult(config, false);
}
@@ -382,7 +386,8 @@ TEST_F(DecryptingAudioDecoderTest, Reinitialize_ConfigChange) {
// The new config is different from the initial config in bits-per-channel,
// channel layout and samples_per_second.
AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarS16,
- CHANNEL_LAYOUT_5_1, 88200, NULL, 0, true);
+ CHANNEL_LAYOUT_5_1, 88200, EmptyExtraData(),
+ true);
EXPECT_NE(new_config.bits_per_channel(), config_.bits_per_channel());
EXPECT_NE(new_config.channel_layout(), config_.channel_layout());
EXPECT_NE(new_config.samples_per_second(), config_.samples_per_second());
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index ff98122..3e67a29 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -385,7 +385,6 @@ void DecryptingDemuxerStream::InitializeDecoderConfig() {
input_audio_config.channel_layout(),
input_audio_config.samples_per_second(),
input_audio_config.extra_data(),
- input_audio_config.extra_data_size(),
false, // Output audio is not encrypted.
input_audio_config.seek_preroll(),
input_audio_config.codec_delay());
@@ -400,7 +399,6 @@ void DecryptingDemuxerStream::InitializeDecoderConfig() {
input_video_config.format(), input_video_config.color_space(),
input_video_config.coded_size(), input_video_config.visible_rect(),
input_video_config.natural_size(), input_video_config.extra_data(),
- input_video_config.extra_data_size(),
false); // Output video is not encrypted.
break;
}
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index e5a8f4b..c679b56 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -11,6 +11,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/decrypt_config.h"
#include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/filters/decrypting_demuxer_stream.h"
@@ -134,9 +135,9 @@ class DecryptingDemuxerStreamTest : public testing::Test {
EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
.WillOnce(SaveArg<1>(&key_added_cb_));
- AudioDecoderConfig input_config(
- kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100,
+ EmptyExtraData(), true);
InitializeAudioAndExpectStatus(input_config, PIPELINE_OK);
const AudioDecoderConfig& output_config =
@@ -309,18 +310,14 @@ TEST_F(DecryptingDemuxerStreamTest, Initialize_NormalVideo) {
EXPECT_EQ(input_config.coded_size(), output_config.coded_size());
EXPECT_EQ(input_config.visible_rect(), output_config.visible_rect());
EXPECT_EQ(input_config.natural_size(), output_config.natural_size());
- ASSERT_EQ(input_config.extra_data_size(), output_config.extra_data_size());
- if (input_config.extra_data_size() > 0) {
- EXPECT_FALSE(output_config.extra_data());
- EXPECT_EQ(0, memcmp(output_config.extra_data(), input_config.extra_data(),
- input_config.extra_data_size()));
- }
+ ASSERT_EQ(input_config.extra_data(), output_config.extra_data());
}
TEST_F(DecryptingDemuxerStreamTest, Initialize_NullDecryptor) {
ExpectDecryptorNotification(NULL, false);
AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
+ CHANNEL_LAYOUT_STEREO, 44100,
+ EmptyExtraData(), true);
InitializeAudioAndExpectStatus(input_config, DECODER_ERROR_NOT_SUPPORTED);
}
@@ -394,9 +391,9 @@ TEST_F(DecryptingDemuxerStreamTest, Reset_DuringDecryptorRequested) {
// One for decryptor request, one for canceling request during Reset().
EXPECT_CALL(*this, RequestDecryptorNotification(_))
.Times(2);
- AudioDecoderConfig input_config(
- kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100,
+ EmptyExtraData(), true);
InitializeAudioAndExpectStatus(input_config, PIPELINE_ERROR_ABORT);
Reset();
}
@@ -482,9 +479,9 @@ TEST_F(DecryptingDemuxerStreamTest, Reset_DuringAbortedDemuxerRead) {
TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_ConfigChanged) {
Initialize();
- AudioDecoderConfig new_config(
- kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 88200, NULL,
- 0, true);
+ AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 88200, EmptyExtraData(),
+ true);
input_audio_stream_->set_audio_decoder_config(new_config);
EXPECT_CALL(*input_audio_stream_, Read(_))
@@ -515,9 +512,9 @@ TEST_F(DecryptingDemuxerStreamTest, Destroy_DuringDecryptorRequested) {
// One for decryptor request, one for canceling request during Reset().
EXPECT_CALL(*this, RequestDecryptorNotification(_))
.Times(2);
- AudioDecoderConfig input_config(
- kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ AudioDecoderConfig input_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100,
+ EmptyExtraData(), true);
InitializeAudioAndExpectStatus(input_config, PIPELINE_ERROR_ABORT);
}
diff --git a/media/filters/ffmpeg_demuxer.cc b/media/filters/ffmpeg_demuxer.cc
index 155e980..c06dd29 100644
--- a/media/filters/ffmpeg_demuxer.cc
+++ b/media/filters/ffmpeg_demuxer.cc
@@ -172,14 +172,58 @@ static int32_t GetCodecHash(const AVCodecContext* context) {
return HashCodecName("none");
}
+scoped_ptr<FFmpegDemuxerStream> FFmpegDemuxerStream::Create(
+ FFmpegDemuxer* demuxer,
+ AVStream* stream) {
+ if (!demuxer || !stream)
+ return nullptr;
+
+ scoped_ptr<FFmpegDemuxerStream> demuxer_stream;
+ scoped_ptr<AudioDecoderConfig> audio_config;
+ scoped_ptr<VideoDecoderConfig> video_config;
+
+ if (stream->codec->codec_type == AVMEDIA_TYPE_AUDIO) {
+ audio_config.reset(new AudioDecoderConfig());
+
+ // IsValidConfig() checks that the codec is supported and that the channel
+ // layout and sample format are valid.
+ //
+ // TODO(chcunningham): Change AVStreamToAudioDecoderConfig to check
+ // IsValidConfig internally and return a null scoped_ptr if not valid.
+ if (!AVStreamToAudioDecoderConfig(stream, audio_config.get()) ||
+ !audio_config->IsValidConfig())
+ return nullptr;
+
+ } else if (stream->codec->codec_type == AVMEDIA_TYPE_VIDEO) {
+ video_config.reset(new VideoDecoderConfig());
+
+ // IsValidConfig() checks that the codec is supported and that the channel
+ // layout and sample format are valid.
+ //
+ // TODO(chcunningham): Change AVStreamToVideoDecoderConfig to check
+ // IsValidConfig internally and return a null scoped_ptr if not valid.
+ if (!AVStreamToVideoDecoderConfig(stream, video_config.get()) ||
+ !video_config->IsValidConfig())
+ return nullptr;
+ }
+
+ return make_scoped_ptr(new FFmpegDemuxerStream(
+ demuxer, stream, audio_config.Pass(), video_config.Pass()));
+}
+
//
// FFmpegDemuxerStream
//
-FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
- AVStream* stream)
+FFmpegDemuxerStream::FFmpegDemuxerStream(
+ FFmpegDemuxer* demuxer,
+ AVStream* stream,
+ scoped_ptr<AudioDecoderConfig> audio_config,
+ scoped_ptr<VideoDecoderConfig> video_config)
: demuxer_(demuxer),
task_runner_(base::ThreadTaskRunnerHandle::Get()),
stream_(stream),
+ audio_config_(audio_config.release()),
+ video_config_(video_config.release()),
type_(UNKNOWN),
liveness_(LIVENESS_UNKNOWN),
end_of_stream_(false),
@@ -196,14 +240,14 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
// Determine our media format.
switch (stream->codec->codec_type) {
case AVMEDIA_TYPE_AUDIO:
+ DCHECK(audio_config_.get() && !video_config_.get());
type_ = AUDIO;
- AVStreamToAudioDecoderConfig(stream, &audio_config_);
- is_encrypted = audio_config_.is_encrypted();
+ is_encrypted = audio_config_->is_encrypted();
break;
case AVMEDIA_TYPE_VIDEO:
+ DCHECK(video_config_.get() && !audio_config_.get());
type_ = VIDEO;
- AVStreamToVideoDecoderConfig(stream, &video_config_);
- is_encrypted = video_config_.is_encrypted();
+ is_encrypted = video_config_->is_encrypted();
rotation_entry = av_dict_get(stream->metadata, "rotate", NULL, 0);
if (rotation_entry && rotation_entry->value && rotation_entry->value[0])
@@ -228,6 +272,7 @@ FFmpegDemuxerStream::FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
break;
case AVMEDIA_TYPE_SUBTITLE:
+ DCHECK(!video_config_.get() && !audio_config_.get());
type_ = TEXT;
break;
default:
@@ -315,8 +360,8 @@ void FFmpegDemuxerStream::EnqueuePacket(ScopedAVPacket packet) {
scoped_ptr<DecryptConfig> decrypt_config;
int data_offset = 0;
- if ((type() == DemuxerStream::AUDIO && audio_config_.is_encrypted()) ||
- (type() == DemuxerStream::VIDEO && video_config_.is_encrypted())) {
+ if ((type() == DemuxerStream::AUDIO && audio_config_->is_encrypted()) ||
+ (type() == DemuxerStream::VIDEO && video_config_->is_encrypted())) {
if (!WebMCreateDecryptConfig(
packet->data, packet->size,
reinterpret_cast<const uint8*>(encryption_key_id_.data()),
@@ -580,14 +625,16 @@ bool FFmpegDemuxerStream::SupportsConfigChanges() { return false; }
AudioDecoderConfig FFmpegDemuxerStream::audio_decoder_config() {
DCHECK(task_runner_->BelongsToCurrentThread());
- CHECK_EQ(type_, AUDIO);
- return audio_config_;
+ DCHECK_EQ(type_, AUDIO);
+ DCHECK(audio_config_.get());
+ return *audio_config_;
}
VideoDecoderConfig FFmpegDemuxerStream::video_decoder_config() {
DCHECK(task_runner_->BelongsToCurrentThread());
- CHECK_EQ(type_, VIDEO);
- return video_config_;
+ DCHECK_EQ(type_, VIDEO);
+ DCHECK(video_config_.get());
+ return *video_config_;
}
VideoRotation FFmpegDemuxerStream::video_rotation() {
@@ -987,7 +1034,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
AVStream* audio_stream = NULL;
AudioDecoderConfig audio_config;
-
AVStream* video_stream = NULL;
VideoDecoderConfig video_config;
@@ -1007,13 +1053,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
// Log the codec detected, whether it is supported or not.
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedAudioCodecHash",
GetCodecHash(codec_context));
-
- // Ensure the codec is supported. IsValidConfig() also checks that the
- // channel layout and sample format are valid.
- AVStreamToAudioDecoderConfig(stream, &audio_config);
- if (!audio_config.IsValidConfig())
- continue;
- audio_stream = stream;
} else if (codec_type == AVMEDIA_TYPE_VIDEO) {
if (video_stream)
continue;
@@ -1042,14 +1081,6 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
// Log the codec detected, whether it is supported or not.
UMA_HISTOGRAM_SPARSE_SLOWLY("Media.DetectedVideoCodecHash",
GetCodecHash(codec_context));
-
- // Ensure the codec is supported. IsValidConfig() also checks that the
- // frame size and visible size are valid.
- AVStreamToVideoDecoderConfig(stream, &video_config);
-
- if (!video_config.IsValidConfig())
- continue;
- video_stream = stream;
} else if (codec_type == AVMEDIA_TYPE_SUBTITLE) {
if (codec_context->codec_id != AV_CODEC_ID_WEBVTT || !text_enabled_) {
continue;
@@ -1058,15 +1089,30 @@ void FFmpegDemuxer::OnFindStreamInfoDone(const PipelineStatusCB& status_cb,
continue;
}
- streams_[i] = new FFmpegDemuxerStream(this, stream);
+ // Attempt to create a FFmpegDemuxerStream from the AVStream. This will
+ // return nullptr if the AVStream is invalid. Validity checks will verify
+ // things like: codec, channel layout, sample/pixel format, etc...
+ scoped_ptr<FFmpegDemuxerStream> demuxer_stream =
+ FFmpegDemuxerStream::Create(this, stream);
+ if (demuxer_stream.get()) {
+ streams_[i] = demuxer_stream.release();
+ } else {
+ // This AVStream does not successfully convert.
+ continue;
+ }
- // Record audio or video src= playback UMA stats for the stream's decoder
- // config.
+ // 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.
if (codec_type == AVMEDIA_TYPE_AUDIO) {
- RecordAudioCodecStats(streams_[i]->audio_decoder_config());
+ CHECK(!audio_stream);
+ audio_stream = stream;
+ audio_config = streams_[i]->audio_decoder_config();
+ RecordAudioCodecStats(audio_config);
} else if (codec_type == AVMEDIA_TYPE_VIDEO) {
- RecordVideoCodecStats(streams_[i]->video_decoder_config(),
- stream->codec->color_range);
+ CHECK(!video_stream);
+ video_stream = stream;
+ video_config = streams_[i]->video_decoder_config();
+ RecordVideoCodecStats(video_config, stream->codec->color_range);
}
max_duration = std::max(max_duration, streams_[i]->duration());
diff --git a/media/filters/ffmpeg_demuxer.h b/media/filters/ffmpeg_demuxer.h
index 9c20e4a..96c21d5 100644
--- a/media/filters/ffmpeg_demuxer.h
+++ b/media/filters/ffmpeg_demuxer.h
@@ -27,6 +27,7 @@
#include <vector>
#include "base/callback.h"
+#include "base/memory/scoped_ptr.h"
#include "base/memory/scoped_vector.h"
#include "base/threading/thread.h"
#include "media/base/audio_decoder_config.h"
@@ -55,9 +56,14 @@ typedef scoped_ptr<AVPacket, ScopedPtrAVFreePacket> ScopedAVPacket;
class FFmpegDemuxerStream : public DemuxerStream {
public:
- // Keeps a copy of |demuxer| and initializes itself using information inside
- // |stream|. Both parameters must outlive |this|.
- FFmpegDemuxerStream(FFmpegDemuxer* demuxer, AVStream* stream);
+ // Attempts to create FFmpegDemuxerStream form the given AVStream. Will return
+ // null if the AVStream cannot be translated into a valid decoder config.
+ //
+ // FFmpegDemuxerStream keeps a copy of |demuxer| and initializes itself using
+ // information inside |stream|. Both parameters must outlive |this|.
+ static scoped_ptr<FFmpegDemuxerStream> Create(FFmpegDemuxer* demuxer,
+ AVStream* stream);
+
~FFmpegDemuxerStream() override;
// Enqueues the given AVPacket. It is invalid to queue a |packet| after
@@ -123,6 +129,15 @@ class FFmpegDemuxerStream : public DemuxerStream {
private:
friend class FFmpegDemuxerTest;
+ // Use FFmpegDemuxerStream::Create to construct.
+ // Audio/Video streams must include their respective DecoderConfig. At most
+ // one DecoderConfig should be provided (leaving the other nullptr). Both
+ // configs should be null for text streams.
+ FFmpegDemuxerStream(FFmpegDemuxer* demuxer,
+ AVStream* stream,
+ scoped_ptr<AudioDecoderConfig> audio_config,
+ scoped_ptr<VideoDecoderConfig> video_config);
+
// Runs |read_cb_| if present with the front of |buffer_queue_|, calling
// NotifyCapacityAvailable() if capacity is still available.
void SatisfyPendingRead();
@@ -140,8 +155,8 @@ class FFmpegDemuxerStream : public DemuxerStream {
FFmpegDemuxer* demuxer_;
scoped_refptr<base::SingleThreadTaskRunner> task_runner_;
AVStream* stream_;
- AudioDecoderConfig audio_config_;
- VideoDecoderConfig video_config_;
+ scoped_ptr<AudioDecoderConfig> audio_config_;
+ scoped_ptr<VideoDecoderConfig> video_config_;
Type type_;
Liveness liveness_;
base::TimeDelta duration_;
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index e75a67f..2e988d2 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -296,8 +296,7 @@ TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
EXPECT_EQ(240, video_config.visible_rect().height());
EXPECT_EQ(320, video_config.natural_size().width());
EXPECT_EQ(240, video_config.natural_size().height());
- EXPECT_FALSE(video_config.extra_data());
- EXPECT_EQ(0u, video_config.extra_data_size());
+ EXPECT_TRUE(video_config.extra_data().empty());
// Audio stream should be present.
stream = demuxer_->GetStream(DemuxerStream::AUDIO);
@@ -310,8 +309,7 @@ TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
EXPECT_EQ(CHANNEL_LAYOUT_STEREO, audio_config.channel_layout());
EXPECT_EQ(44100, audio_config.samples_per_second());
EXPECT_EQ(kSampleFormatPlanarF32, audio_config.sample_format());
- EXPECT_TRUE(audio_config.extra_data());
- EXPECT_GT(audio_config.extra_data_size(), 0u);
+ EXPECT_FALSE(audio_config.extra_data().empty());
// Unknown stream should never be present.
EXPECT_FALSE(demuxer_->GetStream(DemuxerStream::UNKNOWN));
diff --git a/media/filters/ffmpeg_glue.cc b/media/filters/ffmpeg_glue.cc
index 31c6828..bfeced0 100644
--- a/media/filters/ffmpeg_glue.cc
+++ b/media/filters/ffmpeg_glue.cc
@@ -153,7 +153,7 @@ FFmpegGlue::FFmpegGlue(FFmpegURLProtocol* protocol)
}
bool FFmpegGlue::OpenContext() {
- DCHECK(!open_called_) << "OpenContext() should't be called twice.";
+ DCHECK(!open_called_) << "OpenContext() shouldn't be called twice.";
// If avformat_open_input() is called we have to take a slightly different
// destruction path to avoid double frees.
diff --git a/media/filters/ffmpeg_video_decoder_unittest.cc b/media/filters/ffmpeg_video_decoder_unittest.cc
index fb35538..44f6852 100644
--- a/media/filters/ffmpeg_video_decoder_unittest.cc
+++ b/media/filters/ffmpeg_video_decoder_unittest.cc
@@ -14,6 +14,7 @@
#include "media/base/decoder_buffer.h"
#include "media/base/gmock_callback_support.h"
#include "media/base/limits.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_data_util.h"
#include "media/base/test_helpers.h"
@@ -215,16 +216,12 @@ TEST_F(FFmpegVideoDecoderTest, Initialize_Normal) {
Initialize();
}
-TEST_F(FFmpegVideoDecoderTest, Initialize_EncryptedConfig) {
- InitializeWithConfigWithResult(TestVideoConfig::NormalEncrypted(), false);
-}
-
TEST_F(FFmpegVideoDecoderTest, Initialize_OpenDecoderFails) {
// Specify Theora w/o extra data so that avcodec_open2() fails.
VideoDecoderConfig config(kCodecTheora, VIDEO_CODEC_PROFILE_UNKNOWN,
- kVideoFormat, COLOR_SPACE_UNSPECIFIED,
- kCodedSize, kVisibleRect, kNaturalSize,
- NULL, 0, false);
+ kVideoFormat, COLOR_SPACE_UNSPECIFIED, kCodedSize,
+ kVisibleRect, kNaturalSize, EmptyExtraData(),
+ false);
InitializeWithConfigWithResult(config, false);
}
diff --git a/media/filters/frame_processor_unittest.cc b/media/filters/frame_processor_unittest.cc
index ed4e715..4440de0 100644
--- a/media/filters/frame_processor_unittest.cc
+++ b/media/filters/frame_processor_unittest.cc
@@ -4,6 +4,7 @@
#include <map>
#include <string>
+#include <vector>
#include "base/bind.h"
#include "base/message_loop/message_loop.h"
@@ -12,6 +13,7 @@
#include "base/strings/string_util.h"
#include "base/time/time.h"
#include "media/base/media_log.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/base/timestamp_constants.h"
@@ -282,13 +284,9 @@ class FrameProcessorTest : public testing::TestWithParam<bool> {
case DemuxerStream::AUDIO: {
ASSERT_FALSE(audio_);
audio_.reset(new ChunkDemuxerStream(DemuxerStream::AUDIO, true));
- AudioDecoderConfig decoder_config(kCodecVorbis,
- kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO,
- 1000,
- NULL,
- 0,
- false);
+ AudioDecoderConfig decoder_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 1000,
+ EmptyExtraData(), false);
frame_processor_->OnPossibleAudioConfigUpdate(decoder_config);
ASSERT_TRUE(audio_->UpdateAudioConfig(decoder_config, new MediaLog()));
break;
diff --git a/media/filters/opus_audio_decoder.cc b/media/filters/opus_audio_decoder.cc
index 57d173e..4095c4d 100644
--- a/media/filters/opus_audio_decoder.cc
+++ b/media/filters/opus_audio_decoder.cc
@@ -363,7 +363,9 @@ bool OpusAudioDecoder::ConfigureDecoder() {
// Parse the Opus Extra Data.
OpusExtraData opus_extra_data;
- if (!ParseOpusExtraData(config_.extra_data(), config_.extra_data_size(),
+ if (!ParseOpusExtraData(config_.extra_data().empty() ? nullptr :
+ &config_.extra_data()[0],
+ config_.extra_data().size(),
config_,
&opus_extra_data))
return false;
diff --git a/media/filters/source_buffer_stream_unittest.cc b/media/filters/source_buffer_stream_unittest.cc
index bf15f32..5d8dfd5 100644
--- a/media/filters/source_buffer_stream_unittest.cc
+++ b/media/filters/source_buffer_stream_unittest.cc
@@ -6,6 +6,7 @@
#include <stdint.h>
#include <string>
+#include <vector>
#include "base/bind.h"
#include "base/bind_helpers.h"
@@ -15,6 +16,7 @@
#include "base/strings/string_util.h"
#include "media/base/data_buffer.h"
#include "media/base/media_log.h"
+#include "media/base/media_util.h"
#include "media/base/mock_media_log.h"
#include "media/base/test_helpers.h"
#include "media/base/text_track_config.h"
@@ -101,8 +103,7 @@ class SourceBufferStreamTest : public testing::Test {
kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO,
1000,
- NULL,
- 0,
+ EmptyExtraData(),
false,
base::TimeDelta(),
0);
@@ -3603,7 +3604,7 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Video_Overlap_3) {
// Test all the valid same timestamp cases for audio.
TEST_F(SourceBufferStreamTest, SameTimestamp_Audio) {
AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
- 44100, NULL, 0, false);
+ 44100, EmptyExtraData(), false);
stream_.reset(new SourceBufferStream(config, media_log_, true));
Seek(0);
NewSegmentAppend("0K 0K 30K 30 60 60");
@@ -3614,7 +3615,7 @@ TEST_F(SourceBufferStreamTest, SameTimestamp_Audio_Invalid_1) {
EXPECT_MEDIA_LOG(ContainsSameTimestampAt30MillisecondsLog());
AudioDecoderConfig config(kCodecMP3, kSampleFormatF32, CHANNEL_LAYOUT_STEREO,
- 44100, NULL, 0, false);
+ 44100, EmptyExtraData(), false);
stream_.reset(new SourceBufferStream(config, media_log_, true));
Seek(0);
NewSegmentAppend_ExpectFailure("0K 30 30K 60");
@@ -4173,12 +4174,8 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_ConfigChange) {
SetAudioStream();
- AudioDecoderConfig new_config(kCodecVorbis,
- kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_MONO,
- 1000,
- NULL,
- 0,
+ AudioDecoderConfig new_config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_MONO, 1000, EmptyExtraData(),
false);
ASSERT_NE(new_config.channel_layout(), audio_config_.channel_layout());
@@ -4220,7 +4217,7 @@ TEST_F(SourceBufferStreamTest, Audio_SpliceFrame_NoMillisecondSplices) {
video_config_ = TestVideoConfig::Invalid();
audio_config_.Initialize(kCodecVorbis, kSampleFormatPlanarF32,
- CHANNEL_LAYOUT_STEREO, 4000, NULL, 0, false,
+ CHANNEL_LAYOUT_STEREO, 4000, EmptyExtraData(), false,
base::TimeDelta(), 0);
stream_.reset(new SourceBufferStream(audio_config_, media_log_, true));
// Equivalent to 0.5ms per frame.
diff --git a/media/formats/mp2t/es_adapter_video_unittest.cc b/media/formats/mp2t/es_adapter_video_unittest.cc
index 396b655..24feb85 100644
--- a/media/formats/mp2t/es_adapter_video_unittest.cc
+++ b/media/formats/mp2t/es_adapter_video_unittest.cc
@@ -10,6 +10,7 @@
#include "base/logging.h"
#include "base/strings/string_util.h"
#include "base/time/time.h"
+#include "media/base/media_util.h"
#include "media/base/stream_parser_buffer.h"
#include "media/base/timestamp_constants.h"
#include "media/base/video_decoder_config.h"
@@ -27,7 +28,7 @@ VideoDecoderConfig CreateFakeVideoConfig() {
gfx::Size natural_size(320, 240);
return VideoDecoderConfig(kCodecH264, H264PROFILE_MAIN, PIXEL_FORMAT_I420,
COLOR_SPACE_UNSPECIFIED, coded_size, visible_rect,
- natural_size, NULL, 0, false);
+ natural_size, EmptyExtraData(), false);
}
StreamParserBuffer::BufferQueue
diff --git a/media/formats/mp2t/es_parser_adts.cc b/media/formats/mp2t/es_parser_adts.cc
index 9c57de1..adf1dbe 100644
--- a/media/formats/mp2t/es_parser_adts.cc
+++ b/media/formats/mp2t/es_parser_adts.cc
@@ -4,6 +4,8 @@
#include "media/formats/mp2t/es_parser_adts.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/logging.h"
#include "base/strings/string_number_conversions.h"
@@ -219,10 +221,9 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) {
(frequency_index << 7) +
// channel_configuration is [0..7], per early out above.
(channel_configuration << 3));
- uint8 extra_data[2] = {
- static_cast<uint8>(extra_data_int >> 8),
- static_cast<uint8>(extra_data_int & 0xff)
- };
+ std::vector<uint8_t> extra_data;
+ extra_data.push_back(static_cast<uint8>(extra_data_int >> 8));
+ extra_data.push_back(static_cast<uint8>(extra_data_int & 0xff));
AudioDecoderConfig audio_decoder_config(
kCodecAAC,
@@ -230,7 +231,6 @@ bool EsParserAdts::UpdateAudioConfiguration(const uint8* adts_header) {
kADTSChannelLayoutTable[channel_configuration],
extended_samples_per_second,
extra_data,
- arraysize(extra_data),
false);
if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
diff --git a/media/formats/mp2t/es_parser_h264.cc b/media/formats/mp2t/es_parser_h264.cc
index cbdec71..8c59112 100644
--- a/media/formats/mp2t/es_parser_h264.cc
+++ b/media/formats/mp2t/es_parser_h264.cc
@@ -280,8 +280,8 @@ bool EsParserH264::UpdateVideoDecoderConfig(const H264SPS* sps) {
VideoDecoderConfig video_decoder_config(
kCodecH264, VIDEO_CODEC_PROFILE_UNKNOWN, PIXEL_FORMAT_YV12,
- COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size, NULL, 0,
- false);
+ COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size,
+ std::vector<uint8_t>(), false);
if (!video_decoder_config.Matches(last_video_decoder_config_)) {
DVLOG(1) << "Profile IDC: " << sps->profile_idc;
diff --git a/media/formats/mp2t/es_parser_mpeg1audio.cc b/media/formats/mp2t/es_parser_mpeg1audio.cc
index aee4cba..81abc2b 100644
--- a/media/formats/mp2t/es_parser_mpeg1audio.cc
+++ b/media/formats/mp2t/es_parser_mpeg1audio.cc
@@ -4,6 +4,8 @@
#include "media/formats/mp2t/es_parser_mpeg1audio.h"
+#include <vector>
+
#include "base/basictypes.h"
#include "base/bind.h"
#include "base/logging.h"
@@ -173,7 +175,7 @@ bool EsParserMpeg1Audio::UpdateAudioConfiguration(
kSampleFormatS16,
header.channel_layout,
header.sample_rate,
- NULL, 0,
+ std::vector<uint8_t>(),
false);
if (!audio_decoder_config.Matches(last_audio_decoder_config_)) {
diff --git a/media/formats/mp4/mp4_stream_parser.cc b/media/formats/mp4/mp4_stream_parser.cc
index 18698b3..78b7dcd 100644
--- a/media/formats/mp4/mp4_stream_parser.cc
+++ b/media/formats/mp4/mp4_stream_parser.cc
@@ -4,6 +4,8 @@
#include "media/formats/mp4/mp4_stream_parser.h"
+#include <vector>
+
#include "base/callback_helpers.h"
#include "base/logging.h"
#include "base/time/time.h"
@@ -266,10 +268,9 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
is_audio_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_audio_track_encrypted_: " << is_audio_track_encrypted_;
- audio_config.Initialize(
- codec, sample_format, channel_layout, sample_per_second,
- extra_data.size() ? &extra_data[0] : NULL, extra_data.size(),
- is_audio_track_encrypted_, base::TimeDelta(), 0);
+ audio_config.Initialize(codec, sample_format, channel_layout,
+ sample_per_second, extra_data,
+ is_audio_track_encrypted_, base::TimeDelta(), 0);
has_audio_ = true;
audio_track_id_ = track->header.track_id;
}
@@ -305,12 +306,12 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
is_video_track_encrypted_ = entry.sinf.info.track_encryption.is_encrypted;
DVLOG(1) << "is_video_track_encrypted_: " << is_video_track_encrypted_;
- video_config.Initialize(entry.video_codec, entry.video_codec_profile,
- PIXEL_FORMAT_YV12, COLOR_SPACE_HD_REC709,
- coded_size, visible_rect, natural_size,
- // No decoder-specific buffer needed for AVC;
- // SPS/PPS are embedded in the video stream
- NULL, 0, is_video_track_encrypted_);
+ video_config.Initialize(
+ entry.video_codec, entry.video_codec_profile, PIXEL_FORMAT_YV12,
+ COLOR_SPACE_HD_REC709, coded_size, visible_rect, natural_size,
+ // No decoder-specific buffer needed for AVC;
+ // SPS/PPS are embedded in the video stream
+ std::vector<uint8_t>(), is_video_track_encrypted_);
has_video_ = true;
video_track_id_ = track->header.track_id;
}
diff --git a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
index d9bf2b5..23032fa 100644
--- a/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
+++ b/media/formats/mpeg/mpeg_audio_stream_parser_base.cc
@@ -207,8 +207,7 @@ int MPEGAudioStreamParserBase::ParseFrame(const uint8* data,
kSampleFormatF32,
channel_layout,
sample_rate,
- NULL,
- 0,
+ std::vector<uint8_t>(),
false,
base::TimeDelta(),
codec_delay_);
diff --git a/media/formats/webm/webm_audio_client.cc b/media/formats/webm/webm_audio_client.cc
index bde7233..995746a4 100644
--- a/media/formats/webm/webm_audio_client.cc
+++ b/media/formats/webm/webm_audio_client.cc
@@ -66,13 +66,6 @@ bool WebMAudioClient::InitializeConfig(
sample_format = kSampleFormatF32;
}
- const uint8* extra_data = NULL;
- size_t extra_data_size = 0;
- if (codec_private.size() > 0) {
- extra_data = &codec_private[0];
- extra_data_size = codec_private.size();
- }
-
// Convert |codec_delay| from nanoseconds into frames.
int codec_delay_in_frames = 0;
if (codec_delay != -1) {
@@ -87,8 +80,7 @@ bool WebMAudioClient::InitializeConfig(
sample_format,
channel_layout,
samples_per_second,
- extra_data,
- extra_data_size,
+ codec_private,
is_encrypted,
base::TimeDelta::FromMicroseconds(
(seek_preroll != -1 ? seek_preroll : 0) / 1000),
diff --git a/media/formats/webm/webm_video_client.cc b/media/formats/webm/webm_video_client.cc
index 2d3f43b..29b7dca 100644
--- a/media/formats/webm/webm_video_client.cc
+++ b/media/formats/webm/webm_video_client.cc
@@ -88,16 +88,10 @@ bool WebMVideoClient::InitializeConfig(
return false;
}
gfx::Size natural_size = gfx::Size(display_width_, display_height_);
- const uint8* extra_data = NULL;
- size_t extra_data_size = 0;
- if (codec_private.size() > 0) {
- extra_data = &codec_private[0];
- extra_data_size = codec_private.size();
- }
config->Initialize(video_codec, profile, format, COLOR_SPACE_HD_REC709,
- coded_size, visible_rect, natural_size, extra_data,
- extra_data_size, is_encrypted);
+ coded_size, visible_rect, natural_size, codec_private,
+ is_encrypted);
return config->IsValidConfig();
}
diff --git a/media/media.gyp b/media/media.gyp
index 4f1ac5c..4430344 100644
--- a/media/media.gyp
+++ b/media/media.gyp
@@ -328,6 +328,8 @@
'base/media_resources.h',
'base/media_switches.cc',
'base/media_switches.h',
+ 'base/media_util.cc',
+ 'base/media_util.h',
'base/mime_util.cc',
'base/mime_util.h',
'base/moving_average.cc',
diff --git a/media/mojo/services/media_type_converters.cc b/media/mojo/services/media_type_converters.cc
index 6dd84fb..bcfab49 100644
--- a/media/mojo/services/media_type_converters.cc
+++ b/media/mojo/services/media_type_converters.cc
@@ -419,10 +419,9 @@ media::interfaces::AudioDecoderConfigPtr TypeConverter<
config->channel_layout =
static_cast<media::interfaces::ChannelLayout>(input.channel_layout());
config->samples_per_second = input.samples_per_second();
- if (input.extra_data()) {
- std::vector<uint8_t> data(input.extra_data(),
- input.extra_data() + input.extra_data_size());
- config->extra_data.Swap(&data);
+ if (!input.extra_data().empty()) {
+ std::vector<uint8_t> extra_data = input.extra_data();
+ config->extra_data.Swap(&extra_data);
}
config->seek_preroll_usec = input.seek_preroll().InMicroseconds();
config->codec_delay = input.codec_delay();
@@ -440,10 +439,7 @@ TypeConverter<media::AudioDecoderConfig,
static_cast<media::AudioCodec>(input->codec),
static_cast<media::SampleFormat>(input->sample_format),
static_cast<media::ChannelLayout>(input->channel_layout),
- input->samples_per_second,
- input->extra_data.size() ? &input->extra_data.front() : NULL,
- input->extra_data.size(),
- input->is_encrypted,
+ input->samples_per_second, input->extra_data, input->is_encrypted,
base::TimeDelta::FromMicroseconds(input->seek_preroll_usec),
input->codec_delay);
return config;
@@ -465,11 +461,7 @@ media::interfaces::VideoDecoderConfigPtr TypeConverter<
config->coded_size = Size::From(input.coded_size());
config->visible_rect = Rect::From(input.visible_rect());
config->natural_size = Size::From(input.natural_size());
- if (input.extra_data()) {
- std::vector<uint8_t> data(input.extra_data(),
- input.extra_data() + input.extra_data_size());
- config->extra_data.Swap(&data);
- }
+ config->extra_data = mojo::Array<uint8>::From(input.extra_data());
config->is_encrypted = input.is_encrypted();
return config.Pass();
}
@@ -486,9 +478,8 @@ TypeConverter<media::VideoDecoderConfig,
static_cast<media::VideoPixelFormat>(input->format),
static_cast<media::ColorSpace>(input->color_space),
input->coded_size.To<gfx::Size>(), input->visible_rect.To<gfx::Rect>(),
- input->natural_size.To<gfx::Size>(),
- input->extra_data.size() ? &input->extra_data.front() : NULL,
- input->extra_data.size(), input->is_encrypted);
+ input->natural_size.To<gfx::Size>(), input->extra_data,
+ input->is_encrypted);
return config;
}
diff --git a/media/mojo/services/media_type_converters_unittest.cc b/media/mojo/services/media_type_converters_unittest.cc
index 54cd665..38559f3 100644
--- a/media/mojo/services/media_type_converters_unittest.cc
+++ b/media/mojo/services/media_type_converters_unittest.cc
@@ -7,6 +7,7 @@
#include "media/base/audio_decoder_config.h"
#include "media/base/cdm_config.h"
#include "media/base/decoder_buffer.h"
+#include "media/base/media_util.h"
#include "testing/gtest/include/gtest/gtest.h"
namespace media {
@@ -121,22 +122,23 @@ TEST(MediaTypeConvertersTest, ConvertDecoderBuffer_EncryptedBuffer) {
// TODO(tim): Check other properties.
TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_Normal) {
- const uint8 kExtraData[] = "config extra data";
- const int kExtraDataSize = arraysize(kExtraData);
+ const uint8_t kExtraData[] = "config extra data";
+ const std::vector<uint8_t> kExtraDataVector(
+ &kExtraData[0], &kExtraData[0] + arraysize(kExtraData));
+
AudioDecoderConfig config;
config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
- reinterpret_cast<const uint8*>(&kExtraData), kExtraDataSize,
- false, base::TimeDelta(), 0);
+ kExtraDataVector, false, base::TimeDelta(), 0);
interfaces::AudioDecoderConfigPtr ptr(
interfaces::AudioDecoderConfig::From(config));
AudioDecoderConfig result(ptr.To<AudioDecoderConfig>());
EXPECT_TRUE(result.Matches(config));
}
-TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_NullExtraData) {
+TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_EmptyExtraData) {
AudioDecoderConfig config;
config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
- NULL, 0, false, base::TimeDelta(), 0);
+ EmptyExtraData(), false, base::TimeDelta(), 0);
interfaces::AudioDecoderConfigPtr ptr(
interfaces::AudioDecoderConfig::From(config));
AudioDecoderConfig result(ptr.To<AudioDecoderConfig>());
@@ -146,7 +148,7 @@ TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_NullExtraData) {
TEST(MediaTypeConvertersTest, ConvertAudioDecoderConfig_Encrypted) {
AudioDecoderConfig config;
config.Initialize(kCodecAAC, kSampleFormatU8, CHANNEL_LAYOUT_SURROUND, 48000,
- NULL, 0,
+ EmptyExtraData(),
true, // Is encrypted.
base::TimeDelta(), 0);
interfaces::AudioDecoderConfigPtr ptr(
diff --git a/media/renderers/audio_renderer_impl_unittest.cc b/media/renderers/audio_renderer_impl_unittest.cc
index 9e9bf87..2367c42 100644
--- a/media/renderers/audio_renderer_impl_unittest.cc
+++ b/media/renderers/audio_renderer_impl_unittest.cc
@@ -13,6 +13,7 @@
#include "media/base/audio_splicer.h"
#include "media/base/fake_audio_renderer_sink.h"
#include "media/base/gmock_callback_support.h"
+#include "media/base/media_util.h"
#include "media/base/mock_filters.h"
#include "media/base/test_helpers.h"
#include "media/renderers/audio_renderer_impl.h"
@@ -69,8 +70,7 @@ class AudioRendererImplTest : public ::testing::Test {
kSampleFormat,
kChannelLayout,
kInputSamplesPerSecond,
- NULL,
- 0,
+ EmptyExtraData(),
false);
demuxer_stream_.set_audio_decoder_config(audio_config);