Index: media/filters/ffmpeg_audio_decoder.cc |
diff --git a/media/filters/ffmpeg_audio_decoder.cc b/media/filters/ffmpeg_audio_decoder.cc |
index acccf2e595d9bf02d0b08ec128a0e0c81614d034..b5c44319c5f88a97fb3998ee7e3c23e936b06c89 100644 |
--- a/media/filters/ffmpeg_audio_decoder.cc |
+++ b/media/filters/ffmpeg_audio_decoder.cc |
@@ -42,6 +42,16 @@ static inline int DetermineChannels(AVFrame* frame) { |
#endif |
} |
+// Called by FFmpeg's allocation routine to allocate a buffer. Uses |
+// AVCodecContext.opaque to get the object reference in order to call |
+// GetAudioBuffer() to do the actual allocation. |
+static int GetAudioBufferImpl(struct AVCodecContext* s, |
+ AVFrame* frame, |
+ int flags) { |
+ FFmpegAudioDecoder* decoder = static_cast<FFmpegAudioDecoder*>(s->opaque); |
+ return decoder->GetAudioBuffer(s, frame, flags); |
+} |
+ |
// Called by FFmpeg's allocation routine to free a buffer. |opaque| is the |
// AudioBuffer allocated, so unref it. |
static void ReleaseAudioBufferImpl(void* opaque, uint8_t* data) { |
@@ -49,101 +59,14 @@ static void ReleaseAudioBufferImpl(void* opaque, uint8_t* data) { |
static_cast<AudioBuffer*>(opaque)->Release(); |
} |
-// Called by FFmpeg's allocation routine to allocate a buffer. Uses |
-// AVCodecContext.opaque to get the object reference in order to call |
-// GetAudioBuffer() to do the actual allocation. |
-static int GetAudioBuffer(struct AVCodecContext* s, AVFrame* frame, int flags) { |
- DCHECK(s->codec->capabilities & CODEC_CAP_DR1); |
- DCHECK_EQ(s->codec_type, AVMEDIA_TYPE_AUDIO); |
- |
- // Since this routine is called by FFmpeg when a buffer is required for audio |
- // data, use the values supplied by FFmpeg (ignoring the current settings). |
- // FFmpegDecode() gets to determine if the buffer is useable or not. |
- AVSampleFormat format = static_cast<AVSampleFormat>(frame->format); |
- SampleFormat sample_format = |
- AVSampleFormatToSampleFormat(format, s->codec_id); |
- int channels = DetermineChannels(frame); |
- if (channels <= 0 || channels >= limits::kMaxChannels) { |
- DLOG(ERROR) << "Requested number of channels (" << channels |
- << ") exceeds limit."; |
- return AVERROR(EINVAL); |
- } |
- |
- int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format); |
- if (frame->nb_samples <= 0) |
- return AVERROR(EINVAL); |
- |
- if (s->channels != channels) { |
- DLOG(ERROR) << "AVCodecContext and AVFrame disagree on channel count."; |
- return AVERROR(EINVAL); |
- } |
- |
- if (s->sample_rate != frame->sample_rate) { |
- DLOG(ERROR) << "AVCodecContext and AVFrame disagree on sample rate." |
- << s->sample_rate << " vs " << frame->sample_rate; |
- return AVERROR(EINVAL); |
- } |
- |
- // Determine how big the buffer should be and allocate it. FFmpeg may adjust |
- // how big each channel data is in order to meet the alignment policy, so |
- // we need to take this into consideration. |
- int buffer_size_in_bytes = av_samples_get_buffer_size( |
- &frame->linesize[0], channels, frame->nb_samples, format, |
- 0 /* align, use ffmpeg default */); |
- // Check for errors from av_samples_get_buffer_size(). |
- if (buffer_size_in_bytes < 0) |
- return buffer_size_in_bytes; |
- int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; |
- DCHECK_GE(frames_required, frame->nb_samples); |
- |
- ChannelLayout channel_layout = |
- ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); |
- |
- if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { |
- DLOG(ERROR) << "Unsupported channel layout."; |
- return AVERROR(EINVAL); |
- } |
- |
- scoped_refptr<AudioBuffer> buffer = AudioBuffer::CreateBuffer( |
- sample_format, channel_layout, channels, s->sample_rate, frames_required); |
- |
- // Initialize the data[] and extended_data[] fields to point into the memory |
- // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved |
- // audio and equal to |channels| for planar audio. |
- int number_of_planes = buffer->channel_data().size(); |
- if (number_of_planes <= AV_NUM_DATA_POINTERS) { |
- DCHECK_EQ(frame->extended_data, frame->data); |
- for (int i = 0; i < number_of_planes; ++i) |
- frame->data[i] = buffer->channel_data()[i]; |
- } else { |
- // There are more channels than can fit into data[], so allocate |
- // extended_data[] and fill appropriately. |
- frame->extended_data = static_cast<uint8_t**>( |
- av_malloc(number_of_planes * sizeof(*frame->extended_data))); |
- int i = 0; |
- for (; i < AV_NUM_DATA_POINTERS; ++i) |
- frame->extended_data[i] = frame->data[i] = buffer->channel_data()[i]; |
- for (; i < number_of_planes; ++i) |
- frame->extended_data[i] = buffer->channel_data()[i]; |
- } |
- |
- // Now create an AVBufferRef for the data just allocated. It will own the |
- // reference to the AudioBuffer object. |
- AudioBuffer* opaque = buffer.get(); |
- opaque->AddRef(); |
- frame->buf[0] = av_buffer_create( |
- frame->data[0], buffer_size_in_bytes, ReleaseAudioBufferImpl, opaque, 0); |
- return 0; |
-} |
- |
FFmpegAudioDecoder::FFmpegAudioDecoder( |
const scoped_refptr<base::SingleThreadTaskRunner>& task_runner, |
const scoped_refptr<MediaLog>& media_log) |
: task_runner_(task_runner), |
state_(kUninitialized), |
av_sample_format_(0), |
- media_log_(media_log) { |
-} |
+ media_log_(media_log), |
+ pool_(new AudioBufferMemoryPool()) {} |
FFmpegAudioDecoder::~FFmpegAudioDecoder() { |
DCHECK(task_runner_->BelongsToCurrentThread()); |
@@ -402,7 +325,7 @@ bool FFmpegAudioDecoder::ConfigureDecoder() { |
AudioDecoderConfigToAVCodecContext(config_, codec_context_.get()); |
codec_context_->opaque = this; |
- codec_context_->get_buffer2 = GetAudioBuffer; |
+ codec_context_->get_buffer2 = GetAudioBufferImpl; |
codec_context_->refcounted_frames = 1; |
if (config_.codec() == kCodecOpus) |
@@ -446,4 +369,91 @@ void FFmpegAudioDecoder::ResetTimestampState() { |
discard_helper_->Reset(codec_delay); |
} |
+int FFmpegAudioDecoder::GetAudioBuffer(struct AVCodecContext* s, |
+ AVFrame* frame, |
+ int flags) { |
+ DCHECK(s->codec->capabilities & CODEC_CAP_DR1); |
+ DCHECK_EQ(s->codec_type, AVMEDIA_TYPE_AUDIO); |
+ |
+ // Since this routine is called by FFmpeg when a buffer is required for audio |
+ // data, use the values supplied by FFmpeg (ignoring the current settings). |
+ // FFmpegDecode() gets to determine if the buffer is useable or not. |
+ AVSampleFormat format = static_cast<AVSampleFormat>(frame->format); |
+ SampleFormat sample_format = |
+ AVSampleFormatToSampleFormat(format, s->codec_id); |
+ int channels = DetermineChannels(frame); |
+ if (channels <= 0 || channels >= limits::kMaxChannels) { |
+ DLOG(ERROR) << "Requested number of channels (" << channels |
+ << ") exceeds limit."; |
+ return AVERROR(EINVAL); |
+ } |
+ |
+ int bytes_per_channel = SampleFormatToBytesPerChannel(sample_format); |
+ if (frame->nb_samples <= 0) |
+ return AVERROR(EINVAL); |
+ |
+ if (s->channels != channels) { |
+ DLOG(ERROR) << "AVCodecContext and AVFrame disagree on channel count."; |
+ return AVERROR(EINVAL); |
+ } |
+ |
+ if (s->sample_rate != frame->sample_rate) { |
+ DLOG(ERROR) << "AVCodecContext and AVFrame disagree on sample rate." |
+ << s->sample_rate << " vs " << frame->sample_rate; |
+ return AVERROR(EINVAL); |
+ } |
+ |
+ // Determine how big the buffer should be and allocate it. FFmpeg may adjust |
+ // how big each channel data is in order to meet the alignment policy, so |
+ // we need to take this into consideration. |
+ int buffer_size_in_bytes = av_samples_get_buffer_size( |
+ &frame->linesize[0], channels, frame->nb_samples, format, |
+ 0 /* align, use ffmpeg default */); |
+ // Check for errors from av_samples_get_buffer_size(). |
+ if (buffer_size_in_bytes < 0) |
+ return buffer_size_in_bytes; |
+ int frames_required = buffer_size_in_bytes / bytes_per_channel / channels; |
+ DCHECK_GE(frames_required, frame->nb_samples); |
+ |
+ ChannelLayout channel_layout = |
+ ChannelLayoutToChromeChannelLayout(s->channel_layout, s->channels); |
+ |
+ if (channel_layout == CHANNEL_LAYOUT_UNSUPPORTED) { |
+ DLOG(ERROR) << "Unsupported channel layout."; |
+ return AVERROR(EINVAL); |
+ } |
+ |
+ scoped_refptr<AudioBuffer> buffer = |
+ AudioBuffer::CreateBuffer(sample_format, channel_layout, channels, |
+ s->sample_rate, frames_required, pool_); |
+ |
+ // Initialize the data[] and extended_data[] fields to point into the memory |
+ // allocated for AudioBuffer. |number_of_planes| will be 1 for interleaved |
+ // audio and equal to |channels| for planar audio. |
+ int number_of_planes = buffer->channel_data().size(); |
+ if (number_of_planes <= AV_NUM_DATA_POINTERS) { |
+ DCHECK_EQ(frame->extended_data, frame->data); |
+ for (int i = 0; i < number_of_planes; ++i) |
+ frame->data[i] = buffer->channel_data()[i]; |
+ } else { |
+ // There are more channels than can fit into data[], so allocate |
+ // extended_data[] and fill appropriately. |
+ frame->extended_data = static_cast<uint8_t**>( |
+ av_malloc(number_of_planes * sizeof(*frame->extended_data))); |
+ int i = 0; |
+ for (; i < AV_NUM_DATA_POINTERS; ++i) |
+ frame->extended_data[i] = frame->data[i] = buffer->channel_data()[i]; |
+ for (; i < number_of_planes; ++i) |
+ frame->extended_data[i] = buffer->channel_data()[i]; |
+ } |
+ |
+ // Now create an AVBufferRef for the data just allocated. It will own the |
+ // reference to the AudioBuffer object. |
+ AudioBuffer* opaque = buffer.get(); |
+ opaque->AddRef(); |
+ frame->buf[0] = av_buffer_create(frame->data[0], buffer_size_in_bytes, |
+ ReleaseAudioBufferImpl, opaque, 0); |
+ return 0; |
+} |
+ |
} // namespace media |