From 354c1fc06d5c2381dc59a39f02aa61a3c252b283 Mon Sep 17 00:00:00 2001 From: wm4 Date: Fri, 29 Jan 2016 22:43:00 +0100 Subject: audio: move mp_audio->AVFrame conversion to a function This also makes it refcounted, i.e. the new AVFrame will reference the mp_audio buffers, instead of potentially forcing the consumer of the AVFrame to copy the data. All the extra code is for handling the >8 channels case, which requires very messy dealing with the extended_ fields (not our fault). --- audio/audio.c | 72 +++++++++++++++++++++++++++++++++++++++++++++++++ audio/audio.h | 1 + audio/filter/af_lavfi.c | 23 +++------------- 3 files changed, 76 insertions(+), 20 deletions(-) (limited to 'audio') diff --git a/audio/audio.c b/audio/audio.c index 157649c3f8..7441299b3c 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -350,6 +350,78 @@ fail: return NULL; } +// Returns NULL on failure. The input is always unreffed. +struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame) +{ + struct AVFrame *avframe = av_frame_alloc(); + if (!avframe) + goto fail; + + avframe->nb_samples = frame->samples; + avframe->format = af_to_avformat(frame->format); + if (avframe->format == AV_SAMPLE_FMT_NONE) + goto fail; + + avframe->channel_layout = mp_chmap_to_lavc(&frame->channels); + if (!avframe->channel_layout) + goto fail; +#if LIBAVUTIL_VERSION_MICRO >= 100 + // FFmpeg being a stupid POS (but I respect it) + avframe->channels = frame->channels.num; +#endif + avframe->sample_rate = frame->rate; + + if (frame->num_planes > AV_NUM_DATA_POINTERS) { + avframe->extended_data = + av_mallocz_array(frame->num_planes, sizeof(avframe->extended_data[0])); + int extbufs = frame->num_planes - AV_NUM_DATA_POINTERS; + avframe->extended_buf = + av_mallocz_array(extbufs, sizeof(avframe->extended_buf[0])); + if (!avframe->extended_data || !avframe->extended_buf) + goto fail; + avframe->nb_extended_buf = extbufs; + } + + for (int p = 0; p < frame->num_planes; p++) + avframe->extended_data[p] = frame->planes[p]; + avframe->linesize[0] = frame->samples * frame->sstride; + + for (int p = 0; p < AV_NUM_DATA_POINTERS; p++) + avframe->data[p] = avframe->extended_data[p]; + + for (int p = 0; p < frame->num_planes; p++) { + if (!frame->allocated[p]) + break; + AVBufferRef *nref = av_buffer_ref(frame->allocated[p]); + if (!nref) + goto fail; + if (p < AV_NUM_DATA_POINTERS) { + avframe->buf[p] = nref; + } else { + avframe->extended_buf[p - AV_NUM_DATA_POINTERS] = nref; + } + } + + // Force refcounted frame. + if (!avframe->buf[0]) { + AVFrame *tmp = av_frame_alloc(); + if (!tmp) + goto fail; + if (av_frame_ref(tmp, avframe) < 0) + goto fail; + av_frame_free(&avframe); + avframe = tmp; + } + + talloc_free(frame); + return avframe; + +fail: + av_frame_free(&avframe); + talloc_free(frame); + return NULL; +} + struct mp_audio_pool { AVBufferPool *avpool; int element_size; diff --git a/audio/audio.h b/audio/audio.h index c74d0f778c..a4cce55af7 100644 --- a/audio/audio.h +++ b/audio/audio.h @@ -78,6 +78,7 @@ int mp_audio_make_writeable(struct mp_audio *data); struct AVFrame; struct mp_audio *mp_audio_from_avframe(struct AVFrame *avframe); +struct AVFrame *mp_audio_to_avframe_and_unref(struct mp_audio *frame); struct mp_audio_pool; struct mp_audio_pool *mp_audio_pool_create(void *ta_parent); diff --git a/audio/filter/af_lavfi.c b/audio/filter/af_lavfi.c index 1e05e734a1..bc4a687487 100644 --- a/audio/filter/af_lavfi.c +++ b/audio/filter/af_lavfi.c @@ -266,32 +266,15 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data) if (!p->graph) goto error; - AVFilterLink *l_in = p->in->outputs[0]; - if (data) { - frame = av_frame_alloc(); + frame = mp_audio_to_avframe_and_unref(data); + data = NULL; if (!frame) goto error; - frame->nb_samples = data->samples; - frame->format = l_in->format; - // Timebase is 1/sample_rate frame->pts = p->samples_in; - - frame->channel_layout = l_in->channel_layout; - frame->sample_rate = l_in->sample_rate; -#if LIBAVFILTER_VERSION_MICRO >= 100 - // FFmpeg being a stupid POS - frame->channels = l_in->channels; -#endif - - frame->extended_data = frame->data; - for (int n = 0; n < data->num_planes; n++) - frame->data[n] = data->planes[n]; - frame->linesize[0] = frame->nb_samples * data->sstride; - - p->samples_in += data->samples; + p->samples_in += frame->nb_samples; } if (av_buffersrc_add_frame(p->in, frame) < 0) -- cgit v1.2.3