summaryrefslogtreecommitdiffstats
path: root/media
diff options
context:
space:
mode:
authordalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-04 20:20:15 +0000
committerdalecurtis@google.com <dalecurtis@google.com@0039d316-1c4b-4281-b951-d872f2087c98>2013-01-04 20:20:15 +0000
commitb5eca3cffa0afa077d24d98a1f7d9e4b44e5ad4e (patch)
tree585aaec1a953b456b45a67817b4a933f1a8b04f5 /media
parentcb9a7a1586961248f6acb16aa7c13a6a1bff5afd (diff)
downloadchromium_src-b5eca3cffa0afa077d24d98a1f7d9e4b44e5ad4e.zip
chromium_src-b5eca3cffa0afa077d24d98a1f7d9e4b44e5ad4e.tar.gz
chromium_src-b5eca3cffa0afa077d24d98a1f7d9e4b44e5ad4e.tar.bz2
Roll FFMpeg for M26. Fix ffmpeg float audio decoding.
FFmpeg now outputs float for some audio decoders. Unfortunately our pipeline doesn't support float between the FFmpegAudioDecoder and AudioRenderer at present. As such, we need to convert the data into an integer format first. As a byproduct of this, AMR support for ChromeOS is finally fixed and adding support for PCM float is trivial. In summary this patch adds: - A SampleFormat property to AudioDecoderConfig. - AVSampleFormat <-> SampleFormat converters in FFmpegCommon. - Fixes ChromeOS AMR playback. - Finally plumbs pcm_f32le support (enabled in FFmpeg long ago). - Add decoder support for float planar and float interleaved playback. BUG=109085, 158187, 167069 TEST=unittests, layout tests, and demos all pass under tooling without issue. Review URL: https://codereview.chromium.org/11280301 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@175180 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media')
-rw-r--r--media/base/audio_decoder_config.cc87
-rw-r--r--media/base/audio_decoder_config.h46
-rw-r--r--media/base/limits.h2
-rw-r--r--media/ffmpeg/ffmpeg_common.cc102
-rw-r--r--media/filters/audio_decoder_selector_unittest.cc6
-rw-r--r--media/filters/audio_file_reader.cc42
-rw-r--r--media/filters/audio_file_reader_unittest.cc24
-rw-r--r--media/filters/audio_renderer_impl_unittest.cc8
-rw-r--r--media/filters/chunk_demuxer_unittest.cc3
-rw-r--r--media/filters/decrypting_audio_decoder_unittest.cc22
-rw-r--r--media/filters/decrypting_demuxer_stream.cc2
-rw-r--r--media/filters/decrypting_demuxer_stream_unittest.cc15
-rw-r--r--media/filters/ffmpeg_audio_decoder.cc79
-rw-r--r--media/filters/ffmpeg_audio_decoder.h5
-rw-r--r--media/filters/ffmpeg_audio_decoder_unittest.cc8
-rw-r--r--media/filters/ffmpeg_demuxer_unittest.cc3
-rw-r--r--media/filters/pipeline_integration_test.cc6
-rw-r--r--media/mp4/mp4_stream_parser.cc14
-rw-r--r--media/webm/webm_stream_parser.cc5
19 files changed, 325 insertions, 154 deletions
diff --git a/media/base/audio_decoder_config.cc b/media/base/audio_decoder_config.cc
index ed2eeab..ee154a0 100644
--- a/media/base/audio_decoder_config.cc
+++ b/media/base/audio_decoder_config.cc
@@ -11,8 +11,30 @@
namespace media {
+static int SampleFormatToBitsPerChannel(SampleFormat sample_format) {
+ switch (sample_format) {
+ case kUnknownSampleFormat:
+ return 0;
+ case kSampleFormatU8:
+ return 8;
+ case kSampleFormatS16:
+ case kSampleFormatPlanarS16:
+ return 16;
+ case kSampleFormatS32:
+ case kSampleFormatF32:
+ case kSampleFormatPlanarF32:
+ return 32;
+ case kSampleFormatMax:
+ break;
+ }
+
+ NOTREACHED() << "Invalid sample format provided: " << sample_format;
+ return 0;
+}
+
AudioDecoderConfig::AudioDecoderConfig()
: codec_(kUnknownAudioCodec),
+ sample_format_(kUnknownSampleFormat),
bits_per_channel_(0),
channel_layout_(CHANNEL_LAYOUT_UNSUPPORTED),
samples_per_second_(0),
@@ -22,18 +44,18 @@ AudioDecoderConfig::AudioDecoderConfig()
}
AudioDecoderConfig::AudioDecoderConfig(AudioCodec codec,
- int bits_per_channel,
+ SampleFormat sample_format,
ChannelLayout channel_layout,
int samples_per_second,
const uint8* extra_data,
size_t extra_data_size,
bool is_encrypted) {
- Initialize(codec, bits_per_channel, channel_layout, samples_per_second,
+ Initialize(codec, sample_format, channel_layout, samples_per_second,
extra_data, extra_data_size, is_encrypted, true);
}
void AudioDecoderConfig::Initialize(AudioCodec codec,
- int bits_per_channel,
+ SampleFormat sample_format,
ChannelLayout channel_layout,
int samples_per_second,
const uint8* extra_data,
@@ -43,11 +65,9 @@ void AudioDecoderConfig::Initialize(AudioCodec codec,
CHECK((extra_data_size != 0) == (extra_data != NULL));
if (record_stats) {
- UMA_HISTOGRAM_ENUMERATION("Media.AudioCodec", codec, kAudioCodecMax + 1);
- // Fake enum histogram to get exact integral buckets. Expect to never see
- // any values over 32 and even that is huge.
- UMA_HISTOGRAM_ENUMERATION("Media.AudioBitsPerChannel", bits_per_channel,
- 40);
+ UMA_HISTOGRAM_ENUMERATION("Media.AudioCodec", codec, kAudioCodecMax);
+ UMA_HISTOGRAM_ENUMERATION("Media.AudioSampleFormat", sample_format,
+ kSampleFormatMax);
UMA_HISTOGRAM_ENUMERATION("Media.AudioChannelLayout", channel_layout,
CHANNEL_LAYOUT_MAX);
AudioSampleRate asr = media::AsAudioSampleRate(samples_per_second);
@@ -61,10 +81,11 @@ void AudioDecoderConfig::Initialize(AudioCodec codec,
}
codec_ = codec;
- bits_per_channel_ = bits_per_channel;
channel_layout_ = channel_layout;
samples_per_second_ = samples_per_second;
extra_data_size_ = extra_data_size;
+ sample_format_ = sample_format;
+ bits_per_channel_ = SampleFormatToBitsPerChannel(sample_format);
if (extra_data_size_ > 0) {
extra_data_.reset(new uint8[extra_data_size_]);
@@ -83,11 +104,12 @@ AudioDecoderConfig::~AudioDecoderConfig() {}
bool AudioDecoderConfig::IsValidConfig() const {
return codec_ != kUnknownAudioCodec &&
- channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED &&
- bits_per_channel_ > 0 &&
- bits_per_channel_ <= limits::kMaxBitsPerSample &&
- samples_per_second_ > 0 &&
- samples_per_second_ <= limits::kMaxSampleRate;
+ channel_layout_ != CHANNEL_LAYOUT_UNSUPPORTED &&
+ bits_per_channel_ > 0 &&
+ bits_per_channel_ <= limits::kMaxBitsPerSample &&
+ samples_per_second_ > 0 &&
+ samples_per_second_ <= limits::kMaxSampleRate &&
+ sample_format_ != kUnknownSampleFormat;
}
bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
@@ -98,12 +120,13 @@ bool AudioDecoderConfig::Matches(const AudioDecoderConfig& config) const {
(extra_data_size() == config.extra_data_size()) &&
(!extra_data() || !memcmp(extra_data(), config.extra_data(),
extra_data_size())) &&
- (is_encrypted() == config.is_encrypted()));
+ (is_encrypted() == config.is_encrypted()) &&
+ (sample_format() == config.sample_format()));
}
void AudioDecoderConfig::CopyFrom(const AudioDecoderConfig& audio_config) {
Initialize(audio_config.codec(),
- audio_config.bits_per_channel(),
+ audio_config.sample_format(),
audio_config.channel_layout(),
audio_config.samples_per_second(),
audio_config.extra_data(),
@@ -112,36 +135,4 @@ void AudioDecoderConfig::CopyFrom(const AudioDecoderConfig& audio_config) {
false);
}
-AudioCodec AudioDecoderConfig::codec() const {
- return codec_;
-}
-
-int AudioDecoderConfig::bits_per_channel() const {
- return bits_per_channel_;
-}
-
-ChannelLayout AudioDecoderConfig::channel_layout() const {
- return channel_layout_;
-}
-
-int AudioDecoderConfig::samples_per_second() const {
- return samples_per_second_;
-}
-
-int AudioDecoderConfig::bytes_per_frame() const {
- return bytes_per_frame_;
-}
-
-uint8* AudioDecoderConfig::extra_data() const {
- return extra_data_.get();
-}
-
-size_t AudioDecoderConfig::extra_data_size() const {
- return extra_data_size_;
-}
-
-bool AudioDecoderConfig::is_encrypted() const {
- return is_encrypted_;
-}
-
} // namespace media
diff --git a/media/base/audio_decoder_config.h b/media/base/audio_decoder_config.h
index 221e49c..fa29946 100644
--- a/media/base/audio_decoder_config.h
+++ b/media/base/audio_decoder_config.h
@@ -15,7 +15,7 @@ namespace media {
enum AudioCodec {
// These values are histogrammed over time; do not change their ordinal
// values. When deleting a codec replace it with a dummy value; when adding a
- // codec, do so at the bottom (and update kAudioCodecMax).
+ // codec, do so at the bottom before kAudioCodecMax.
kUnknownAudioCodec = 0,
kCodecAAC,
kCodecMP3,
@@ -34,7 +34,24 @@ enum AudioCodec {
// The only acceptable time to add a new codec is if there is production code
// that uses said codec in the same CL.
- kAudioCodecMax = kCodecOpus // Must equal the last "real" codec above.
+ // Must always be last!
+ kAudioCodecMax
+};
+
+enum SampleFormat {
+ // These values are histogrammed over time; do not change their ordinal
+ // values. When deleting a sample format replace it with a dummy value; when
+ // adding a sample format, do so at the bottom before kSampleFormatMax.
+ kUnknownSampleFormat = 0,
+ kSampleFormatU8, // Unsigned 8-bit w/ bias of 128.
+ kSampleFormatS16, // Signed 16-bit.
+ kSampleFormatS32, // Signed 32-bit.
+ kSampleFormatF32, // Float 32-bit.
+ kSampleFormatPlanarS16, // Signed 16-bit planar.
+ kSampleFormatPlanarF32, // Float 32-bit planar.
+
+ // Must always be last!
+ kSampleFormatMax
};
// TODO(dalecurtis): FFmpeg API uses |bytes_per_channel| instead of
@@ -48,7 +65,7 @@ class MEDIA_EXPORT AudioDecoderConfig {
// Constructs an initialized object. It is acceptable to pass in NULL for
// |extra_data|, otherwise the memory is copied.
- AudioDecoderConfig(AudioCodec codec, int bits_per_channel,
+ AudioDecoderConfig(AudioCodec codec, SampleFormat sample_format,
ChannelLayout channel_layout, int samples_per_second,
const uint8* extra_data, size_t extra_data_size,
bool is_encrypted);
@@ -56,11 +73,10 @@ class MEDIA_EXPORT AudioDecoderConfig {
~AudioDecoderConfig();
// Resets the internal state of this object.
- void Initialize(AudioCodec codec, int bits_per_channel,
+ void Initialize(AudioCodec codec, SampleFormat sample_format,
ChannelLayout channel_layout, int samples_per_second,
const uint8* extra_data, size_t extra_data_size,
- bool is_encrypted,
- bool record_stats);
+ bool is_encrypted, bool record_stats);
// Deep copies |audio_config|.
void CopyFrom(const AudioDecoderConfig& audio_config);
@@ -73,24 +89,26 @@ class MEDIA_EXPORT AudioDecoderConfig {
// Note: The contents of |extra_data_| are compared not the raw pointers.
bool Matches(const AudioDecoderConfig& config) const;
- AudioCodec codec() const;
- int bits_per_channel() const;
- ChannelLayout channel_layout() const;
- int samples_per_second() const;
- int bytes_per_frame() const;
+ AudioCodec codec() const { return codec_; }
+ int bits_per_channel() const { return bits_per_channel_; }
+ ChannelLayout channel_layout() const { return channel_layout_; }
+ int samples_per_second() const { return samples_per_second_; }
+ SampleFormat sample_format() const { return sample_format_; }
+ int bytes_per_frame() const { return bytes_per_frame_; }
// Optional byte data required to initialize audio decoders such as Vorbis
// codebooks.
- uint8* extra_data() const;
- size_t extra_data_size() const;
+ uint8* extra_data() const { return extra_data_.get(); }
+ size_t extra_data_size() const { return extra_data_size_; }
// Whether the audio stream is potentially encrypted.
// Note that in a potentially encrypted audio stream, individual buffers
// can be encrypted or not encrypted.
- bool is_encrypted() const;
+ bool is_encrypted() const { return is_encrypted_; }
private:
AudioCodec codec_;
+ SampleFormat sample_format_;
int bits_per_channel_;
ChannelLayout channel_layout_;
int samples_per_second_;
diff --git a/media/base/limits.h b/media/base/limits.h
index e441da7..66ceaf2 100644
--- a/media/base/limits.h
+++ b/media/base/limits.h
@@ -34,7 +34,7 @@ enum {
kMaxSampleRate = 192000,
kMinSampleRate = 3000,
kMaxChannels = 32,
- kMaxBitsPerSample = 64,
+ kMaxBitsPerSample = 32,
kMaxSamplesPerPacket = kMaxSampleRate,
kMaxPacketSizeInBytes =
(kMaxBitsPerSample / 8) * kMaxChannels * kMaxSamplesPerPacket,
diff --git a/media/ffmpeg/ffmpeg_common.cc b/media/ffmpeg/ffmpeg_common.cc
index 1fd5cd9..f87825e 100644
--- a/media/ffmpeg/ffmpeg_common.cc
+++ b/media/ffmpeg/ffmpeg_common.cc
@@ -68,6 +68,7 @@ AudioCodec CodecIDToAudioCodec(CodecID codec_id) {
case CODEC_ID_PCM_U8:
case CODEC_ID_PCM_S16LE:
case CODEC_ID_PCM_S24LE:
+ case CODEC_ID_PCM_F32LE:
return kCodecPCM;
case CODEC_ID_PCM_S16BE:
return kCodecPCM_S16BE;
@@ -92,22 +93,24 @@ AudioCodec CodecIDToAudioCodec(CodecID codec_id) {
}
static CodecID AudioCodecToCodecID(AudioCodec audio_codec,
- int bits_per_channel) {
+ SampleFormat sample_format) {
switch (audio_codec) {
case kCodecAAC:
return CODEC_ID_AAC;
case kCodecMP3:
return CODEC_ID_MP3;
case kCodecPCM:
- switch (bits_per_channel) {
- case 8:
+ switch (sample_format) {
+ case kSampleFormatU8:
return CODEC_ID_PCM_U8;
- case 16:
+ case kSampleFormatS16:
return CODEC_ID_PCM_S16LE;
- case 32:
+ case kSampleFormatS32:
return CODEC_ID_PCM_S24LE;
+ case kSampleFormatF32:
+ return CODEC_ID_PCM_F32LE;
default:
- DVLOG(1) << "Unsupported bits per channel: " << bits_per_channel;
+ DVLOG(1) << "Unsupported sample format: " << sample_format;
}
break;
case kCodecPCM_S16BE:
@@ -136,14 +139,10 @@ static CodecID AudioCodecToCodecID(AudioCodec audio_codec,
VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
switch (codec_id) {
- case CODEC_ID_VC1:
- return kCodecVC1;
case CODEC_ID_H264:
return kCodecH264;
case CODEC_ID_THEORA:
return kCodecTheora;
- case CODEC_ID_MPEG2VIDEO:
- return kCodecMPEG2;
case CODEC_ID_MPEG4:
return kCodecMPEG4;
case CODEC_ID_VP8:
@@ -156,14 +155,10 @@ VideoCodec CodecIDToVideoCodec(CodecID codec_id) {
static CodecID VideoCodecToCodecID(VideoCodec video_codec) {
switch (video_codec) {
- case kCodecVC1:
- return CODEC_ID_VC1;
case kCodecH264:
return CODEC_ID_H264;
case kCodecTheora:
return CODEC_ID_THEORA;
- case kCodecMPEG2:
- return CODEC_ID_MPEG2VIDEO;
case kCodecMPEG4:
return CODEC_ID_MPEG4;
case kCodecVP8:
@@ -222,6 +217,46 @@ static int VideoCodecProfileToProfileID(VideoCodecProfile profile) {
return FF_PROFILE_UNKNOWN;
}
+static SampleFormat AVSampleFormatToSampleFormat(AVSampleFormat sample_format) {
+ switch (sample_format) {
+ case AV_SAMPLE_FMT_U8:
+ return kSampleFormatU8;
+ case AV_SAMPLE_FMT_S16:
+ return kSampleFormatS16;
+ case AV_SAMPLE_FMT_S32:
+ return kSampleFormatS32;
+ case AV_SAMPLE_FMT_FLT:
+ return kSampleFormatF32;
+ case AV_SAMPLE_FMT_S16P:
+ return kSampleFormatPlanarS16;
+ case AV_SAMPLE_FMT_FLTP:
+ return kSampleFormatPlanarF32;
+ default:
+ DVLOG(1) << "Unknown AVSampleFormat: " << sample_format;
+ }
+ return kUnknownSampleFormat;
+}
+
+static AVSampleFormat SampleFormatToAVSampleFormat(SampleFormat sample_format) {
+ switch (sample_format) {
+ case kSampleFormatU8:
+ return AV_SAMPLE_FMT_U8;
+ case kSampleFormatS16:
+ return AV_SAMPLE_FMT_S16;
+ case kSampleFormatS32:
+ return AV_SAMPLE_FMT_S32;
+ case kSampleFormatF32:
+ return AV_SAMPLE_FMT_FLT;
+ case kSampleFormatPlanarS16:
+ return AV_SAMPLE_FMT_S16P;
+ case kSampleFormatPlanarF32:
+ return AV_SAMPLE_FMT_FLTP;
+ default:
+ DVLOG(1) << "Unknown SampleFormat: " << sample_format;
+ }
+ return AV_SAMPLE_FMT_NONE;
+}
+
void AVCodecContextToAudioDecoderConfig(
const AVCodecContext* codec_context,
AudioDecoderConfig* config) {
@@ -229,51 +264,38 @@ void AVCodecContextToAudioDecoderConfig(
AudioCodec codec = CodecIDToAudioCodec(codec_context->codec_id);
- AVSampleFormat sample_format = codec_context->sample_fmt;
+ SampleFormat sample_format =
+ AVSampleFormatToSampleFormat(codec_context->sample_fmt);
+
if (codec == kCodecOpus) {
// TODO(tomfinegan): |sample_fmt| in |codec_context| is -1... because
// libopusdec.c isn't built into ffmpegsumo...? Maybe it's not *that* big
// a deal since libopus will produce either float or S16 samples, and
// OpusAudioDecoder is the only provider of Opus support.
- sample_format = AV_SAMPLE_FMT_S16;
+ sample_format = kSampleFormatS16;
}
- int bytes_per_channel = av_get_bytes_per_sample(sample_format);
- ChannelLayout channel_layout =
- ChannelLayoutToChromeChannelLayout(codec_context->channel_layout,
- codec_context->channels);
- int samples_per_second = codec_context->sample_rate;
-
+ ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout(
+ codec_context->channel_layout, codec_context->channels);
config->Initialize(codec,
- bytes_per_channel << 3,
+ sample_format,
channel_layout,
- samples_per_second,
+ codec_context->sample_rate,
codec_context->extradata,
codec_context->extradata_size,
false, // Not encrypted.
true);
+ DCHECK_EQ(av_get_bytes_per_sample(codec_context->sample_fmt) * 8,
+ config->bits_per_channel());
}
void AudioDecoderConfigToAVCodecContext(const AudioDecoderConfig& config,
AVCodecContext* codec_context) {
codec_context->codec_type = AVMEDIA_TYPE_AUDIO;
codec_context->codec_id = AudioCodecToCodecID(config.codec(),
- config.bits_per_channel());
-
- switch (config.bits_per_channel()) {
- case 8:
- codec_context->sample_fmt = AV_SAMPLE_FMT_U8;
- break;
- case 16:
- codec_context->sample_fmt = AV_SAMPLE_FMT_S16;
- break;
- case 32:
- codec_context->sample_fmt = AV_SAMPLE_FMT_S32;
- break;
- default:
- DVLOG(1) << "Unsupported bits per channel: " << config.bits_per_channel();
- codec_context->sample_fmt = AV_SAMPLE_FMT_NONE;
- }
+ config.sample_format());
+ codec_context->sample_fmt = SampleFormatToAVSampleFormat(
+ config.sample_format());
// TODO(scherkus): should we set |channel_layout|? I'm not sure if FFmpeg uses
// said information to decode.
diff --git a/media/filters/audio_decoder_selector_unittest.cc b/media/filters/audio_decoder_selector_unittest.cc
index f8792cc..e4b2071 100644
--- a/media/filters/audio_decoder_selector_unittest.cc
+++ b/media/filters/audio_decoder_selector_unittest.cc
@@ -31,9 +31,11 @@ class AudioDecoderSelectorTest : public ::testing::Test {
AudioDecoderSelectorTest()
: clear_audio_config_(
- kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, false),
+ kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
+ NULL, 0, false),
encrypted_audio_config_(
- kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true),
+ kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
+ NULL, 0, true),
demuxer_stream_(new StrictMock<MockDemuxerStream>()),
decryptor_(new NiceMock<MockDecryptor>()),
decoder_1_(new StrictMock<MockAudioDecoder>()),
diff --git a/media/filters/audio_file_reader.cc b/media/filters/audio_file_reader.cc
index cf295b6..4a6bc12 100644
--- a/media/filters/audio_file_reader.cc
+++ b/media/filters/audio_file_reader.cc
@@ -79,14 +79,26 @@ bool AudioFileReader::Open() {
AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
if (codec) {
+ // MP3 decodes to S16P which we don't support, tell it to use S16 instead.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P)
+ codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
+
if ((result = avcodec_open2(codec_context_, codec, NULL)) < 0) {
DLOG(WARNING) << "AudioFileReader::Open() : could not open codec -"
- << " result: " << result;
+ << " result: " << result;
+ return false;
+ }
+
+ // Ensure avcodec_open2() respected our format request.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P) {
+ DLOG(ERROR) << "AudioFileReader::Open() : unable to configure a"
+ << " supported sample format - "
+ << codec_context_->sample_fmt;
return false;
}
} else {
DLOG(WARNING) << "AudioFileReader::Open() : could not find codec -"
- << " result: " << result;
+ << " result: " << result;
return false;
}
@@ -163,10 +175,28 @@ int AudioFileReader::Read(AudioBus* audio_bus) {
if (current_frame + frames_read > audio_bus->frames())
frames_read = audio_bus->frames() - current_frame;
- // Deinterleave each channel and convert to 32bit floating-point
- // with nominal range -1.0 -> +1.0.
- audio_bus->FromInterleavedPartial(
- av_frame->data[0], current_frame, frames_read, bytes_per_sample);
+ // Deinterleave each channel and convert to 32bit floating-point with
+ // nominal range -1.0 -> +1.0. If the output is already in float planar
+ // format, just copy it into the AudioBus.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
+ float* decoded_audio_data = reinterpret_cast<float*>(av_frame->data[0]);
+ int channels = audio_bus->channels();
+ for (int ch = 0; ch < channels; ++ch) {
+ float* bus_data = audio_bus->channel(ch) + current_frame;
+ for (int i = 0, offset = ch; i < frames_read;
+ ++i, offset += channels) {
+ bus_data[i] = decoded_audio_data[offset];
+ }
+ }
+ } else if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP) {
+ for (int ch = 0; ch < audio_bus->channels(); ++ch) {
+ memcpy(audio_bus->channel(ch) + current_frame,
+ av_frame->extended_data[ch], sizeof(float) * frames_read);
+ }
+ } else {
+ audio_bus->FromInterleavedPartial(
+ av_frame->data[0], current_frame, frames_read, bytes_per_sample);
+ }
current_frame += frames_read;
} while (packet_temp.size > 0);
diff --git a/media/filters/audio_file_reader_unittest.cc b/media/filters/audio_file_reader_unittest.cc
index dc0669f..1c12297 100644
--- a/media/filters/audio_file_reader_unittest.cc
+++ b/media/filters/audio_file_reader_unittest.cc
@@ -6,6 +6,7 @@
#include "base/md5.h"
#include "base/memory/scoped_ptr.h"
#include "base/sys_byteorder.h"
+#include "build/build_config.h"
#include "media/base/audio_bus.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
@@ -27,6 +28,8 @@ class AudioFileReaderTest : public testing::Test {
reader_.reset(new AudioFileReader(protocol_.get()));
}
+ // Reads and the entire file provided to Initialize(). If NULL is specified
+ // for |audio_hash| MD5 checks are skipped.
void ReadAndVerify(const char* audio_hash, int expected_frames) {
scoped_ptr<AudioBus> decoded_audio_data = AudioBus::Create(
reader_->channels(), reader_->number_of_frames());
@@ -34,6 +37,11 @@ class AudioFileReaderTest : public testing::Test {
ASSERT_LE(actual_frames, decoded_audio_data->frames());
ASSERT_EQ(expected_frames, actual_frames);
+ // TODO(dalecurtis): Audio decoded in float does not have a consistent hash
+ // across platforms. Fix this: http://crbug.com/168204
+ if (!audio_hash)
+ return;
+
base::MD5Context md5_context;
base::MD5Init(&md5_context);
@@ -51,7 +59,6 @@ class AudioFileReaderTest : public testing::Test {
base::MD5Digest digest;
base::MD5Final(&digest, &md5_context);
-
EXPECT_EQ(audio_hash, base::MD5DigestToBase16(digest));
}
@@ -84,12 +91,12 @@ TEST_F(AudioFileReaderTest, InvalidFile) {
}
TEST_F(AudioFileReaderTest, WithVideo) {
- RunTest("bear.ogv", "302e1773ba2f9a194c35a0f8f0b73f15", 2, 44100,
+ RunTest("bear.ogv", NULL, 2, 44100,
base::TimeDelta::FromMicroseconds(1011520), 44608, 44608);
}
TEST_F(AudioFileReaderTest, Vorbis) {
- RunTest("sfx.ogg", "2b84ad6d605abba1125c0dacc9c8dbdd", 1, 44100,
+ RunTest("sfx.ogg", NULL, 1, 44100,
base::TimeDelta::FromMicroseconds(350001), 15435, 15435);
}
@@ -97,23 +104,30 @@ TEST_F(AudioFileReaderTest, WaveU8) {
RunTest("sfx_u8.wav", "d7e255a8e634fffdf9f744c5803632f8", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12719, 12719);
}
+
TEST_F(AudioFileReaderTest, WaveS16LE) {
RunTest("sfx_s16le.wav", "2a5847207fdcba1c05e52f65ad010f66", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12719, 12719);
}
+
TEST_F(AudioFileReaderTest, WaveS24LE) {
RunTest("sfx_s24le.wav", "66296b4ec633290581f9abf3c21cd5e7", 1, 44100,
base::TimeDelta::FromMicroseconds(288414), 12719, 12719);
}
+TEST_F(AudioFileReaderTest, WaveF32LE) {
+ RunTest("sfx_f32le.wav", "66296b4ec633290581f9abf3c21cd5e7", 1, 44100,
+ base::TimeDelta::FromMicroseconds(288414), 12719, 12719);
+}
+
#if defined(GOOGLE_CHROME_BUILD) || defined(USE_PROPRIETARY_CODECS)
TEST_F(AudioFileReaderTest, MP3) {
- RunTest("sfx.mp3", "2a5847207fdcba1c05e52f65ad010f66", 1, 44100,
+ RunTest("sfx.mp3", NULL, 1, 44100,
base::TimeDelta::FromMicroseconds(313470), 13824, 12719);
}
TEST_F(AudioFileReaderTest, AAC) {
- RunTest("sfx.m4a", "d4d3207758d1e8cb0aa176ff77fa6932", 1, 44100,
+ RunTest("sfx.m4a", NULL, 1, 44100,
base::TimeDelta::FromMicroseconds(312001), 13759, 13312);
}
#endif
diff --git a/media/filters/audio_renderer_impl_unittest.cc b/media/filters/audio_renderer_impl_unittest.cc
index a17c6b0..58a27df 100644
--- a/media/filters/audio_renderer_impl_unittest.cc
+++ b/media/filters/audio_renderer_impl_unittest.cc
@@ -39,8 +39,8 @@ class AudioRendererImplTest : public ::testing::Test {
SetDecryptorReadyCB())),
demuxer_stream_(new MockDemuxerStream()),
decoder_(new MockAudioDecoder()),
- audio_config_(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO,
- 44100, NULL, 0, false) {
+ audio_config_(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, false) {
EXPECT_CALL(*demuxer_stream_, type())
.WillRepeatedly(Return(DemuxerStream::AUDIO));
EXPECT_CALL(*demuxer_stream_, audio_decoder_config())
@@ -69,11 +69,11 @@ class AudioRendererImplTest : public ::testing::Test {
void SetSupportedAudioDecoderProperties() {
ON_CALL(*decoder_, bits_per_channel())
- .WillByDefault(Return(16));
+ .WillByDefault(Return(audio_config_.bits_per_channel()));
ON_CALL(*decoder_, channel_layout())
.WillByDefault(Return(CHANNEL_LAYOUT_MONO));
ON_CALL(*decoder_, samples_per_second())
- .WillByDefault(Return(44100));
+ .WillByDefault(Return(audio_config_.samples_per_second()));
}
void SetUnsupportedAudioDecoderProperties() {
diff --git a/media/filters/chunk_demuxer_unittest.cc b/media/filters/chunk_demuxer_unittest.cc
index 21de615..f6d329a 100644
--- a/media/filters/chunk_demuxer_unittest.cc
+++ b/media/filters/chunk_demuxer_unittest.cc
@@ -805,11 +805,12 @@ TEST_F(ChunkDemuxerTest, TestInit) {
const AudioDecoderConfig& config = audio_stream->audio_decoder_config();
EXPECT_EQ(kCodecVorbis, config.codec());
- EXPECT_EQ(16, config.bits_per_channel());
+ 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_EQ(kSampleFormatPlanarF32, config.sample_format());
EXPECT_EQ(is_audio_encrypted,
audio_stream->audio_decoder_config().is_encrypted());
} else {
diff --git a/media/filters/decrypting_audio_decoder_unittest.cc b/media/filters/decrypting_audio_decoder_unittest.cc
index c8c0f0f..efc6815 100644
--- a/media/filters/decrypting_audio_decoder_unittest.cc
+++ b/media/filters/decrypting_audio_decoder_unittest.cc
@@ -108,13 +108,13 @@ class DecryptingAudioDecoderTest : public testing::Test {
EXPECT_CALL(*decryptor_, RegisterNewKeyCB(Decryptor::kAudio, _))
.WillOnce(SaveArg<1>(&key_added_cb_));
- AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
InitializeAndExpectStatus(config, PIPELINE_OK);
- EXPECT_EQ(16, decoder_->bits_per_channel());
- EXPECT_EQ(CHANNEL_LAYOUT_STEREO, decoder_->channel_layout());
- EXPECT_EQ(44100, decoder_->samples_per_second());
+ EXPECT_EQ(config.bits_per_channel(), decoder_->bits_per_channel());
+ EXPECT_EQ(config.channel_layout(), decoder_->channel_layout());
+ EXPECT_EQ(config.samples_per_second(), decoder_->samples_per_second());
}
void ReadAndExpectFrameReadyWith(
@@ -243,16 +243,16 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_Normal) {
// Ensure that DecryptingAudioDecoder only accepts encrypted audio.
TEST_F(DecryptingAudioDecoderTest, Initialize_UnencryptedAudioConfig) {
- AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, false);
+ AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, false);
InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
}
// Ensure decoder handles invalid audio configs without crashing.
TEST_F(DecryptingAudioDecoderTest, Initialize_InvalidAudioConfig) {
- AudioDecoderConfig config(kUnknownAudioCodec, 0, CHANNEL_LAYOUT_STEREO, 0,
- NULL, 0, true);
+ AudioDecoderConfig config(kUnknownAudioCodec, kUnknownSampleFormat,
+ CHANNEL_LAYOUT_STEREO, 0, NULL, 0, true);
InitializeAndExpectStatus(config, PIPELINE_ERROR_DECODE);
}
@@ -264,8 +264,8 @@ TEST_F(DecryptingAudioDecoderTest, Initialize_UnsupportedAudioConfig) {
EXPECT_CALL(*this, RequestDecryptorNotification(_))
.WillOnce(RunCallbackIfNotNull(decryptor_.get()));
- AudioDecoderConfig config(kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100,
- NULL, 0, true);
+ AudioDecoderConfig config(kCodecVorbis, kSampleFormatPlanarF32,
+ CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
InitializeAndExpectStatus(config, DECODER_ERROR_NOT_SUPPORTED);
}
diff --git a/media/filters/decrypting_demuxer_stream.cc b/media/filters/decrypting_demuxer_stream.cc
index 5720037..6941168 100644
--- a/media/filters/decrypting_demuxer_stream.cc
+++ b/media/filters/decrypting_demuxer_stream.cc
@@ -327,7 +327,7 @@ void DecryptingDemuxerStream::SetDecoderConfig(
stream->audio_decoder_config();
audio_config_.reset(new AudioDecoderConfig());
audio_config_->Initialize(input_audio_config.codec(),
- input_audio_config.bits_per_channel(),
+ input_audio_config.sample_format(),
input_audio_config.channel_layout(),
input_audio_config.samples_per_second(),
input_audio_config.extra_data(),
diff --git a/media/filters/decrypting_demuxer_stream_unittest.cc b/media/filters/decrypting_demuxer_stream_unittest.cc
index 55ecc01..3c87d8b 100644
--- a/media/filters/decrypting_demuxer_stream_unittest.cc
+++ b/media/filters/decrypting_demuxer_stream_unittest.cc
@@ -119,16 +119,20 @@ class DecryptingDemuxerStreamTest : public testing::Test {
.WillOnce(SaveArg<1>(&key_added_cb_));
AudioDecoderConfig input_config(
- kCodecVorbis, 16, CHANNEL_LAYOUT_STEREO, 44100, NULL, 0, true);
+ kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 44100,
+ NULL, 0, true);
InitializeAudioAndExpectStatus(input_config, PIPELINE_OK);
const AudioDecoderConfig& output_config =
demuxer_stream_->audio_decoder_config();
EXPECT_EQ(DemuxerStream::AUDIO, demuxer_stream_->type());
EXPECT_FALSE(output_config.is_encrypted());
- EXPECT_EQ(16, output_config.bits_per_channel());
- EXPECT_EQ(CHANNEL_LAYOUT_STEREO, output_config.channel_layout());
- EXPECT_EQ(44100, output_config.samples_per_second());
+ EXPECT_EQ(input_config.bits_per_channel(),
+ output_config.bits_per_channel());
+ EXPECT_EQ(input_config.channel_layout(), output_config.channel_layout());
+ EXPECT_EQ(input_config.sample_format(), output_config.sample_format());
+ EXPECT_EQ(input_config.samples_per_second(),
+ output_config.samples_per_second());
}
void ReadAndExpectBufferReadyWith(
@@ -410,7 +414,8 @@ TEST_F(DecryptingDemuxerStreamTest, DemuxerRead_ConfigChanged) {
Initialize();
AudioDecoderConfig new_config(
- kCodecVorbis, 32, CHANNEL_LAYOUT_STEREO, 88200, NULL, 0, true);
+ kCodecVorbis, kSampleFormatPlanarF32, CHANNEL_LAYOUT_STEREO, 88200, NULL,
+ 0, true);
EXPECT_CALL(*input_audio_stream_, audio_decoder_config())
.WillRepeatedly(ReturnRef(new_config));
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc
index 5384d63..3f1e81a 100644
--- a/media/filters/ffmpeg_audio_decoder.cc
+++ b/media/filters/ffmpeg_audio_decoder.cc
@@ -8,6 +8,7 @@
#include "base/callback_helpers.h"
#include "base/location.h"
#include "base/message_loop_proxy.h"
+#include "media/base/audio_bus.h"
#include "media/base/audio_decoder_config.h"
#include "media/base/audio_timestamp_helper.h"
#include "media/base/data_buffer.h"
@@ -283,6 +284,10 @@ bool FFmpegAudioDecoder::ConfigureDecoder() {
codec_context_ = avcodec_alloc_context3(NULL);
AudioDecoderConfigToAVCodecContext(config, codec_context_);
+ // MP3 decodes to S16P which we don't support, tell it to use S16 instead.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P)
+ codec_context_->request_sample_fmt = AV_SAMPLE_FMT_S16;
+
AVCodec* codec = avcodec_find_decoder(codec_context_->codec_id);
if (!codec || avcodec_open2(codec_context_, codec, NULL) < 0) {
DLOG(ERROR) << "Could not initialize audio decoder: "
@@ -290,6 +295,26 @@ bool FFmpegAudioDecoder::ConfigureDecoder() {
return false;
}
+ // Ensure avcodec_open2() respected our format request.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_S16P) {
+ DLOG(ERROR) << "Unable to configure a supported sample format: "
+ << codec_context_->sample_fmt;
+ return false;
+ }
+
+ // Some codecs will only output float data, so we need to convert to integer
+ // before returning the decoded buffer.
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP ||
+ codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
+ // Preallocate the AudioBus for float conversions. We can treat interleaved
+ // float data as a single planar channel since our output is expected in an
+ // interleaved format anyways.
+ int channels = codec_context_->channels;
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT)
+ channels = 1;
+ converter_bus_ = AudioBus::CreateWrapper(channels);
+ }
+
// Success!
av_frame_ = avcodec_alloc_frame();
bits_per_channel_ = config.bits_per_channel();
@@ -297,6 +322,7 @@ bool FFmpegAudioDecoder::ConfigureDecoder() {
samples_per_second_ = config.samples_per_second();
output_timestamp_helper_.reset(new AudioTimestampHelper(
config.bytes_per_frame(), config.samples_per_second()));
+ bytes_per_frame_ = config.bytes_per_frame();
return true;
}
@@ -374,7 +400,6 @@ void FFmpegAudioDecoder::RunDecodeLoop(
}
}
- const uint8* decoded_audio_data = NULL;
int decoded_audio_size = 0;
if (frame_decoded) {
int output_sample_rate = av_frame_->sample_rate;
@@ -388,24 +413,64 @@ void FFmpegAudioDecoder::RunDecodeLoop(
break;
}
- decoded_audio_data = av_frame_->data[0];
decoded_audio_size = av_samples_get_buffer_size(
NULL, codec_context_->channels, av_frame_->nb_samples,
codec_context_->sample_fmt, 1);
+ // If we're decoding into float, adjust audio size.
+ if (converter_bus_ && bits_per_channel_ / 8 != sizeof(float)) {
+ DCHECK(codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT ||
+ codec_context_->sample_fmt == AV_SAMPLE_FMT_FLTP);
+ decoded_audio_size *=
+ static_cast<float>(bits_per_channel_ / 8) / sizeof(float);
+ }
}
- scoped_refptr<DataBuffer> output;
-
+ int start_sample = 0;
if (decoded_audio_size > 0 && output_bytes_to_drop_ > 0) {
+ DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0)
+ << "Decoder didn't output full frames";
+
int dropped_size = std::min(decoded_audio_size, output_bytes_to_drop_);
- decoded_audio_data += dropped_size;
+ start_sample = dropped_size / bytes_per_frame_;
decoded_audio_size -= dropped_size;
output_bytes_to_drop_ -= dropped_size;
}
+ scoped_refptr<DataBuffer> output;
if (decoded_audio_size > 0) {
- // Copy the audio samples into an output buffer.
- output = new DataBuffer(decoded_audio_data, decoded_audio_size);
+ DCHECK_EQ(decoded_audio_size % bytes_per_frame_, 0)
+ << "Decoder didn't output full frames";
+
+ // Convert float data using an AudioBus.
+ if (converter_bus_) {
+ // Setup the AudioBus as a wrapper of the AVFrame data and then use
+ // AudioBus::ToInterleaved() to convert the data as necessary.
+ int skip_frames = start_sample;
+ int total_frames = av_frame_->nb_samples - start_sample;
+ if (codec_context_->sample_fmt == AV_SAMPLE_FMT_FLT) {
+ DCHECK_EQ(converter_bus_->channels(), 1);
+ total_frames *= codec_context_->channels;
+ skip_frames *= codec_context_->channels;
+ }
+ converter_bus_->set_frames(total_frames);
+ DCHECK_EQ(decoded_audio_size,
+ converter_bus_->frames() * bytes_per_frame_);
+
+ for (int i = 0; i < converter_bus_->channels(); ++i) {
+ converter_bus_->SetChannelData(i, reinterpret_cast<float*>(
+ av_frame_->extended_data[i]) + skip_frames);
+ }
+
+ output = new DataBuffer(decoded_audio_size);
+ output->SetDataSize(decoded_audio_size);
+ converter_bus_->ToInterleaved(
+ converter_bus_->frames(), bits_per_channel_ / 8,
+ output->GetWritableData());
+ } else {
+ output = new DataBuffer(
+ av_frame_->extended_data[0] + start_sample * bytes_per_frame_,
+ decoded_audio_size);
+ }
output->SetTimestamp(output_timestamp_helper_->GetTimestamp());
output->SetDuration(
output_timestamp_helper_->GetDuration(decoded_audio_size));
diff --git a/media/filters/ffmpeg_audio_decoder.h b/media/filters/ffmpeg_audio_decoder.h
index ce096ee..ebaa563 100644
--- a/media/filters/ffmpeg_audio_decoder.h
+++ b/media/filters/ffmpeg_audio_decoder.h
@@ -20,6 +20,7 @@ class MessageLoopProxy;
namespace media {
+class AudioBus;
class AudioTimestampHelper;
class DataBuffer;
class DecoderBuffer;
@@ -91,6 +92,10 @@ class MEDIA_EXPORT FFmpegAudioDecoder : public AudioDecoder {
// them up and hand them out as we receive Read() calls.
std::list<QueuedAudioBuffer> queued_audio_;
+ // We may need to convert the audio data coming out of FFmpeg from planar
+ // float to integer.
+ scoped_ptr<AudioBus> converter_bus_;
+
DISALLOW_IMPLICIT_CONSTRUCTORS(FFmpegAudioDecoder);
};
diff --git a/media/filters/ffmpeg_audio_decoder_unittest.cc b/media/filters/ffmpeg_audio_decoder_unittest.cc
index ead293d..6c3a2e0 100644
--- a/media/filters/ffmpeg_audio_decoder_unittest.cc
+++ b/media/filters/ffmpeg_audio_decoder_unittest.cc
@@ -54,7 +54,7 @@ class FFmpegAudioDecoderTest : public testing::Test {
encoded_audio_.push_back(DecoderBuffer::CreateEOSBuffer());
config_.Initialize(kCodecVorbis,
- 16,
+ kSampleFormatPlanarF32,
CHANNEL_LAYOUT_STEREO,
44100,
vorbis_extradata_->GetData(),
@@ -128,9 +128,9 @@ class FFmpegAudioDecoderTest : public testing::Test {
TEST_F(FFmpegAudioDecoderTest, Initialize) {
Initialize();
- EXPECT_EQ(16, decoder_->bits_per_channel());
- EXPECT_EQ(CHANNEL_LAYOUT_STEREO, decoder_->channel_layout());
- EXPECT_EQ(44100, decoder_->samples_per_second());
+ EXPECT_EQ(config_.bits_per_channel(), decoder_->bits_per_channel());
+ EXPECT_EQ(config_.channel_layout(), decoder_->channel_layout());
+ EXPECT_EQ(config_.samples_per_second(), decoder_->samples_per_second());
}
TEST_F(FFmpegAudioDecoderTest, ProduceAudioSamples) {
diff --git a/media/filters/ffmpeg_demuxer_unittest.cc b/media/filters/ffmpeg_demuxer_unittest.cc
index bdb7547..c1efa8e 100644
--- a/media/filters/ffmpeg_demuxer_unittest.cc
+++ b/media/filters/ffmpeg_demuxer_unittest.cc
@@ -243,9 +243,10 @@ TEST_F(FFmpegDemuxerTest, Initialize_Successful) {
const AudioDecoderConfig& audio_config = stream->audio_decoder_config();
EXPECT_EQ(kCodecVorbis, audio_config.codec());
- EXPECT_EQ(16, audio_config.bits_per_channel());
+ EXPECT_EQ(32, audio_config.bits_per_channel());
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);
diff --git a/media/filters/pipeline_integration_test.cc b/media/filters/pipeline_integration_test.cc
index e196d58..dddc065 100644
--- a/media/filters/pipeline_integration_test.cc
+++ b/media/filters/pipeline_integration_test.cc
@@ -6,6 +6,7 @@
#include "base/bind.h"
#include "base/string_util.h"
+#include "build/build_config.h"
#include "media/base/decoder_buffer.h"
#include "media/base/test_data_util.h"
#include "media/crypto/aes_decryptor.h"
@@ -298,7 +299,10 @@ TEST_F(PipelineIntegrationTest, BasicPlaybackHashed) {
ASSERT_TRUE(WaitUntilOnEnded());
EXPECT_EQ(GetVideoHash(), "f0be120a90a811506777c99a2cdf7cc1");
- EXPECT_EQ(GetAudioHash(), "5699a4415b620e45b9d0aae531c9df76");
+
+ // TODO(dalecurtis): Audio decoded in float does not have a consistent hash
+ // across platforms. Fix this: http://crbug.com/168204
+ // EXPECT_EQ(GetAudioHash(), "");
}
TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource) {
diff --git a/media/mp4/mp4_stream_parser.cc b/media/mp4/mp4_stream_parser.cc
index 69a35f2..38fc7d2 100644
--- a/media/mp4/mp4_stream_parser.cc
+++ b/media/mp4/mp4_stream_parser.cc
@@ -205,8 +205,20 @@ bool MP4StreamParser::ParseMoov(BoxReader* reader) {
return false;
}
+ SampleFormat sample_format;
+ if (entry.samplesize == 8) {
+ sample_format = kSampleFormatU8;
+ } else if (entry.samplesize == 16) {
+ sample_format = kSampleFormatS16;
+ } else if (entry.samplesize == 32) {
+ sample_format = kSampleFormatS32;
+ } else {
+ LOG(ERROR) << "Unsupported sample size.";
+ return false;
+ }
+
bool is_encrypted = entry.sinf.info.track_encryption.is_encrypted;
- audio_config.Initialize(kCodecAAC, entry.samplesize,
+ audio_config.Initialize(kCodecAAC, sample_format,
aac.channel_layout(),
aac.GetOutputSamplesPerSecond(has_sbr_),
NULL, 0, is_encrypted, false);
diff --git a/media/webm/webm_stream_parser.cc b/media/webm/webm_stream_parser.cc
index 770fee9..bfa44ae 100644
--- a/media/webm/webm_stream_parser.cc
+++ b/media/webm/webm_stream_parser.cc
@@ -352,12 +352,13 @@ int WebMStreamParser::ParseInfoAndTracks(const uint8* data, int size) {
config_helper.audio_config();
audio_config.Initialize(original_audio_config.codec(),
- original_audio_config.bits_per_channel(),
+ original_audio_config.sample_format(),
original_audio_config.channel_layout(),
original_audio_config.samples_per_second(),
original_audio_config.extra_data(),
original_audio_config.extra_data_size(),
- is_audio_encrypted, false);
+ is_audio_encrypted,
+ false);
FireNeedKey(tracks_parser.audio_encryption_key_id());
} else {