summaryrefslogtreecommitdiffstats
path: root/audio
diff options
context:
space:
mode:
Diffstat (limited to 'audio')
-rw-r--r--audio/audio.c72
-rw-r--r--audio/audio.h1
-rw-r--r--audio/filter/af_lavfi.c23
3 files changed, 76 insertions, 20 deletions
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)