Chromium Code Reviews
chromiumcodereview-hr@appspot.gserviceaccount.com (chromiumcodereview-hr) | Please choose your nickname with Settings | Help | Chromium Project | Gerrit Changes | Sign out
(881)

Unified Diff: media/filters/ffmpeg_audio_decoder.cc

Issue 2788483003: Introduce AudioBufferMemoryPool to avoid thrashing on audio buffers. (Closed)
Patch Set: Add class comments. Created 3 years, 9 months ago
Use n/p to move between diff chunks; N/P to move between comments. Draft comments are only viewable by you.
Jump to:
View side-by-side diff with in-line comments
Download patch
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | no next file » | no next file with comments »
Expand Comments ('e') | Collapse Comments ('c') | Show Comments Hide Comments ('s')
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
« no previous file with comments | « media/filters/ffmpeg_audio_decoder.h ('k') | no next file » | no next file with comments »

Powered by Google App Engine
This is Rietveld 408576698