diff options
Diffstat (limited to 'audio/audio.c')
-rw-r--r-- | audio/audio.c | 108 |
1 files changed, 108 insertions, 0 deletions
diff --git a/audio/audio.c b/audio/audio.c index 157649c3f8..ae85a4bf08 100644 --- a/audio/audio.c +++ b/audio/audio.c @@ -22,6 +22,7 @@ #include <libavutil/buffer.h> #include <libavutil/frame.h> +#include <libavutil/mem.h> #include <libavutil/version.h> #include "mpv_talloc.h" @@ -251,8 +252,43 @@ void mp_audio_skip_samples(struct mp_audio *data, int samples) data->planes[n] = (uint8_t *)data->planes[n] + samples * data->sstride; data->samples -= samples; + + if (data->pts != MP_NOPTS_VALUE) + data->pts += samples / (double)data->rate; } +// Clip the given frame to the given timestamp range. Adjusts the frame size +// and timestamp. +void mp_audio_clip_timestamps(struct mp_audio *f, double start, double end) +{ + if (f->pts == MP_NOPTS_VALUE || f->rate < 1) + return; + double f_end = f->pts + f->samples / (double)f->rate; + if (end != MP_NOPTS_VALUE) { + if (f_end >= end) { + if (f->pts >= end) { + f->samples = 0; + } else { + int new = (end - f->pts) * f->rate; + f->samples = MPCLAMP(new, 0, f->samples); + } + } + } + if (start != MP_NOPTS_VALUE) { + if (f->pts < start) { + if (f_end <= start) { + f->samples = 0; + f->pts = f_end; + } else { + int skip = (start - f->pts) * f->rate; + skip = MPCLAMP(skip, 0, f->samples); + mp_audio_skip_samples(f, skip); + } + } + } +} + + // Return false if the frame data is shared, true otherwise. // Will return true for non-refcounted frames. bool mp_audio_is_writeable(struct mp_audio *data) @@ -350,6 +386,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; |