Always use 48kHz for OPUS decoding.

Per the specification OPUS should always use 48kHz for decoding.

BUG=392827
TEST=new unittests

Review URL: https://codereview.chromium.org/390543002

git-svn-id: svn://svn.chromium.org/chrome/trunk/src@282989 0039d316-1c4b-4281-b951-d872f2087c98
parent 2b2d95c0
...@@ -285,11 +285,19 @@ void AVCodecContextToAudioDecoderConfig( ...@@ -285,11 +285,19 @@ void AVCodecContextToAudioDecoderConfig(
ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout( ChannelLayout channel_layout = ChannelLayoutToChromeChannelLayout(
codec_context->channel_layout, codec_context->channels); codec_context->channel_layout, codec_context->channels);
int sample_rate = codec_context->sample_rate;
if (codec == kCodecOpus) { if (codec == kCodecOpus) {
// |codec_context->sample_fmt| is not set by FFmpeg because Opus decoding is // |codec_context->sample_fmt| is not set by FFmpeg because Opus decoding is
// not enabled in FFmpeg. It doesn't matter what value is set here, so long // not enabled in FFmpeg. It doesn't matter what value is set here, so long
// as it's valid, the true sample format is selected inside the decoder. // as it's valid, the true sample format is selected inside the decoder.
sample_format = kSampleFormatF32; sample_format = kSampleFormatF32;
// Always use 48kHz for OPUS. Technically we should match to the highest
// supported hardware sample rate among [8, 12, 16, 24, 48] kHz, but we
// don't know the hardware sample rate at this point and those rates are
// rarely used for output. See the "Input Sample Rate" section of the spec:
// http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
sample_rate = 48000;
} }
base::TimeDelta seek_preroll; base::TimeDelta seek_preroll;
...@@ -301,7 +309,7 @@ void AVCodecContextToAudioDecoderConfig( ...@@ -301,7 +309,7 @@ void AVCodecContextToAudioDecoderConfig(
config->Initialize(codec, config->Initialize(codec,
sample_format, sample_format,
channel_layout, channel_layout,
codec_context->sample_rate, sample_rate,
codec_context->extradata, codec_context->extradata,
codec_context->extradata_size, codec_context->extradata_size,
is_encrypted, is_encrypted,
......
...@@ -2,64 +2,37 @@ ...@@ -2,64 +2,37 @@
// Use of this source code is governed by a BSD-style license that can be // Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file. // found in the LICENSE file.
#include "base/files/file_path.h"
#include "base/logging.h" #include "base/logging.h"
#include "base/path_service.h"
#include "media/base/media.h"
#include "media/ffmpeg/ffmpeg_common.h" #include "media/ffmpeg/ffmpeg_common.h"
#include "media/filters/ffmpeg_glue.h"
#include "testing/gtest/include/gtest/gtest.h" #include "testing/gtest/include/gtest/gtest.h"
using base::TimeDelta;
namespace media { namespace media {
static AVIndexEntry kIndexEntries[] = {
// pos, timestamp, flags, size, min_distance
{ 0, 0, AVINDEX_KEYFRAME, 0, 0 },
{ 2000, 1000, AVINDEX_KEYFRAME, 0, 0 },
{ 3000, 2000, 0, 0, 0 },
{ 5000, 3000, AVINDEX_KEYFRAME, 0, 0 },
{ 6000, 4000, 0, 0, 0 },
{ 8000, 5000, AVINDEX_KEYFRAME, 0, 0 },
{ 9000, 6000, AVINDEX_KEYFRAME, 0, 0 },
{ 11500, 7000, AVINDEX_KEYFRAME, 0, 0 },
};
static const AVRational kTimeBase = { 1, 1000 };
class FFmpegCommonTest : public testing::Test { class FFmpegCommonTest : public testing::Test {
public: public:
FFmpegCommonTest(); FFmpegCommonTest() { FFmpegGlue::InitializeFFmpeg(); }
virtual ~FFmpegCommonTest(); virtual ~FFmpegCommonTest() {};
protected:
AVStream stream_;
DISALLOW_COPY_AND_ASSIGN(FFmpegCommonTest);
}; };
static bool InitFFmpeg() { TEST_F(FFmpegCommonTest, OpusAudioDecoderConfig) {
static bool initialized = false; AVCodecContext context = {0};
if (initialized) { context.codec_type = AVMEDIA_TYPE_AUDIO;
return true; context.codec_id = AV_CODEC_ID_OPUS;
} context.channel_layout = CHANNEL_LAYOUT_STEREO;
base::FilePath path; context.channels = 2;
PathService::Get(base::DIR_MODULE, &path); context.sample_fmt = AV_SAMPLE_FMT_FLT;
return media::InitializeMediaLibrary(path);
}
FFmpegCommonTest::FFmpegCommonTest() { // During conversion this sample rate should be changed to 48kHz.
CHECK(InitFFmpeg()); context.sample_rate = 44100;
stream_.time_base = kTimeBase;
stream_.index_entries = kIndexEntries;
stream_.index_entries_allocated_size = sizeof(kIndexEntries);
stream_.nb_index_entries = arraysize(kIndexEntries);
}
FFmpegCommonTest::~FFmpegCommonTest() {} AudioDecoderConfig decoder_config;
AVCodecContextToAudioDecoderConfig(&context, false, &decoder_config, false);
EXPECT_EQ(48000, decoder_config.samples_per_second());
}
TEST_F(FFmpegCommonTest, TimeBaseConversions) { TEST_F(FFmpegCommonTest, TimeBaseConversions) {
int64 test_data[][5] = { const int64 test_data[][5] = {
{1, 2, 1, 500000, 1 }, {1, 2, 1, 500000, 1 },
{1, 3, 1, 333333, 1 }, {1, 3, 1, 333333, 1 },
{1, 3, 2, 666667, 2 }, {1, 3, 2, 666667, 2 },
...@@ -72,7 +45,8 @@ TEST_F(FFmpegCommonTest, TimeBaseConversions) { ...@@ -72,7 +45,8 @@ TEST_F(FFmpegCommonTest, TimeBaseConversions) {
time_base.num = static_cast<int>(test_data[i][0]); time_base.num = static_cast<int>(test_data[i][0]);
time_base.den = static_cast<int>(test_data[i][1]); time_base.den = static_cast<int>(test_data[i][1]);
TimeDelta time_delta = ConvertFromTimeBase(time_base, test_data[i][2]); base::TimeDelta time_delta =
ConvertFromTimeBase(time_base, test_data[i][2]);
EXPECT_EQ(time_delta.InMicroseconds(), test_data[i][3]); EXPECT_EQ(time_delta.InMicroseconds(), test_data[i][3]);
EXPECT_EQ(ConvertToTimeBase(time_base, time_delta), test_data[i][4]); EXPECT_EQ(ConvertToTimeBase(time_base, time_delta), test_data[i][4]);
...@@ -150,5 +124,4 @@ TEST_F(FFmpegCommonTest, UTCDateToTime_Invalid) { ...@@ -150,5 +124,4 @@ TEST_F(FFmpegCommonTest, UTCDateToTime_Invalid) {
} }
} }
} // namespace media } // namespace media
...@@ -1513,4 +1513,32 @@ TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) { ...@@ -1513,4 +1513,32 @@ TEST_F(PipelineIntegrationTest, BasicPlayback_OddVideoSize) {
ASSERT_TRUE(WaitUntilOnEnded()); ASSERT_TRUE(WaitUntilOnEnded());
} }
// Verify that OPUS audio in a webm which reports a 44.1kHz sample rate plays
// correctly at 48kHz
TEST_F(PipelineIntegrationTest, BasicPlayback_Opus441kHz) {
ASSERT_TRUE(Start(GetTestDataFilePath("sfx-opus-441.webm"), PIPELINE_OK));
Play();
ASSERT_TRUE(WaitUntilOnEnded());
EXPECT_EQ(48000,
demuxer_->GetStream(DemuxerStream::AUDIO)
->audio_decoder_config()
.samples_per_second());
}
// Same as above but using MediaSource.
TEST_F(PipelineIntegrationTest, BasicPlayback_MediaSource_Opus441kHz) {
MockMediaSource source(
"sfx-opus-441.webm", kOpusAudioOnlyWebM, kAppendWholeFile);
StartPipelineWithMediaSource(&source);
source.EndOfStream();
Play();
ASSERT_TRUE(WaitUntilOnEnded());
source.Abort();
Stop();
EXPECT_EQ(48000,
demuxer_->GetStream(DemuxerStream::AUDIO)
->audio_decoder_config()
.samples_per_second());
}
} // namespace media } // namespace media
...@@ -58,6 +58,11 @@ bool WebMAudioClient::InitializeConfig( ...@@ -58,6 +58,11 @@ bool WebMAudioClient::InitializeConfig(
if (output_samples_per_second_ > 0) if (output_samples_per_second_ > 0)
samples_per_second = output_samples_per_second_; samples_per_second = output_samples_per_second_;
// Always use 48kHz for OPUS. See the "Input Sample Rate" section of the
// spec: http://tools.ietf.org/html/draft-terriberry-oggopus-01#page-11
if (audio_codec == kCodecOpus)
samples_per_second = 48000;
const uint8* extra_data = NULL; const uint8* extra_data = NULL;
size_t extra_data_size = 0; size_t extra_data_size = 0;
if (codec_private.size() > 0) { if (codec_private.size() > 0) {
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment