mirror of
https://github.com/mpv-player/mpv
synced 2024-07-11 23:47:56 +02:00
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).
This commit is contained in:
parent
946ee29a7d
commit
354c1fc06d
@ -350,6 +350,78 @@ fail:
|
|||||||
return NULL;
|
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 {
|
struct mp_audio_pool {
|
||||||
AVBufferPool *avpool;
|
AVBufferPool *avpool;
|
||||||
int element_size;
|
int element_size;
|
||||||
|
@ -78,6 +78,7 @@ int mp_audio_make_writeable(struct mp_audio *data);
|
|||||||
|
|
||||||
struct AVFrame;
|
struct AVFrame;
|
||||||
struct mp_audio *mp_audio_from_avframe(struct AVFrame *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;
|
||||||
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
|
struct mp_audio_pool *mp_audio_pool_create(void *ta_parent);
|
||||||
|
@ -266,32 +266,15 @@ static int filter_frame(struct af_instance *af, struct mp_audio *data)
|
|||||||
if (!p->graph)
|
if (!p->graph)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
AVFilterLink *l_in = p->in->outputs[0];
|
|
||||||
|
|
||||||
if (data) {
|
if (data) {
|
||||||
frame = av_frame_alloc();
|
frame = mp_audio_to_avframe_and_unref(data);
|
||||||
|
data = NULL;
|
||||||
if (!frame)
|
if (!frame)
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
frame->nb_samples = data->samples;
|
|
||||||
frame->format = l_in->format;
|
|
||||||
|
|
||||||
// Timebase is 1/sample_rate
|
// Timebase is 1/sample_rate
|
||||||
frame->pts = p->samples_in;
|
frame->pts = p->samples_in;
|
||||||
|
p->samples_in += frame->nb_samples;
|
||||||
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;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
if (av_buffersrc_add_frame(p->in, frame) < 0)
|
if (av_buffersrc_add_frame(p->in, frame) < 0)
|
||||||
|
Loading…
Reference in New Issue
Block a user