diff options
author | wm4 <wm4@nowhere> | 2018-01-18 14:44:20 +0100 |
---|---|---|
committer | Kevin Mitchell <kevmitch@gmail.com> | 2018-01-30 03:10:27 -0800 |
commit | b9f804b566c4c528714e4ec5e63675ad7ba5fefd (patch) | |
tree | 49d6fcd42ce6597a67aa2af59b7f20beb21a2e14 /audio/aframe.c | |
parent | 76276c92104c31ee936ba5c76a76072f09978c5f (diff) | |
download | mpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.bz2 mpv-b9f804b566c4c528714e4ec5e63675ad7ba5fefd.tar.xz |
audio: rewrite filtering glue code
Use the new filtering code for audio too.
Diffstat (limited to 'audio/aframe.c')
-rw-r--r-- | audio/aframe.c | 130 |
1 files changed, 121 insertions, 9 deletions
diff --git a/audio/aframe.c b/audio/aframe.c index 1f053a6715..9115cf67fd 100644 --- a/audio/aframe.c +++ b/audio/aframe.c @@ -32,6 +32,11 @@ struct mp_aframe { // We support spdif formats, which are allocated as AV_SAMPLE_FMT_S16. int format; double pts; + double speed; +}; + +struct avframe_opaque { + double speed; }; static void free_frame(void *ptr) @@ -43,11 +48,11 @@ static void free_frame(void *ptr) struct mp_aframe *mp_aframe_create(void) { struct mp_aframe *frame = talloc_zero(NULL, struct mp_aframe); - frame->pts = MP_NOPTS_VALUE; frame->av_frame = av_frame_alloc(); if (!frame->av_frame) abort(); talloc_set_destructor(frame, free_frame); + mp_aframe_reset(frame); return frame; } @@ -61,6 +66,7 @@ struct mp_aframe *mp_aframe_new_ref(struct mp_aframe *frame) dst->chmap = frame->chmap; dst->format = frame->format; dst->pts = frame->pts; + dst->speed = frame->speed; if (mp_aframe_is_allocated(frame)) { if (av_frame_ref(dst->av_frame, frame->av_frame) < 0) @@ -80,6 +86,7 @@ void mp_aframe_reset(struct mp_aframe *frame) frame->chmap.num = 0; frame->format = 0; frame->pts = MP_NOPTS_VALUE; + frame->speed = 1.0; } // Remove all actual audio data and leave only the metadata. @@ -120,6 +127,11 @@ struct mp_aframe *mp_aframe_from_avframe(struct AVFrame *av_frame) mp_chmap_from_channels(&frame->chmap, av_frame->channels); #endif + if (av_frame->opaque_ref) { + struct avframe_opaque *op = (void *)av_frame->opaque_ref->data; + frame->speed = op->speed; + } + return frame; } @@ -137,6 +149,16 @@ struct AVFrame *mp_aframe_to_avframe(struct mp_aframe *frame) if (!mp_chmap_is_lavc(&frame->chmap)) return NULL; + if (!frame->av_frame->opaque_ref && frame->speed != 1.0) { + frame->av_frame->opaque_ref = + av_buffer_alloc(sizeof(struct avframe_opaque)); + if (!frame->av_frame->opaque_ref) + return NULL; + + struct avframe_opaque *op = (void *)frame->av_frame->opaque_ref->data; + op->speed = frame->speed; + } + return av_frame_clone(frame->av_frame); } @@ -183,6 +205,7 @@ void mp_aframe_config_copy(struct mp_aframe *dst, struct mp_aframe *src) void mp_aframe_copy_attributes(struct mp_aframe *dst, struct mp_aframe *src) { dst->pts = src->pts; + dst->speed = src->speed; int rate = dst->av_frame->sample_rate; @@ -316,6 +339,37 @@ void mp_aframe_set_pts(struct mp_aframe *frame, double pts) frame->pts = pts; } +// Set a speed factor. This is multiplied with the sample rate to get the +// "effective" samplerate (mp_aframe_get_effective_rate()), which will be used +// to do PTS calculations. If speed!=1.0, the PTS values always refer to the +// original PTS (before changing speed), and if you want reasonably continuous +// PTS between frames, you need to use the effective samplerate. +void mp_aframe_set_speed(struct mp_aframe *frame, double factor) +{ + frame->speed = factor; +} + +// Adjust current speed factor. +void mp_aframe_mul_speed(struct mp_aframe *frame, double factor) +{ + frame->speed *= factor; +} + +double mp_aframe_get_speed(struct mp_aframe *frame) +{ + return frame->speed; +} + +// Matters for speed changed frames (such as a frame which has been resampled +// to play at a different speed). +// Return the sample rate at which the frame would have to be played to result +// in the same duration as the original frame before the speed change. +// This is used for A/V sync. +double mp_aframe_get_effective_rate(struct mp_aframe *frame) +{ + return mp_aframe_get_rate(frame) / frame->speed; +} + // Return number of data pointers. int mp_aframe_get_planes(struct mp_aframe *frame) { @@ -339,6 +393,18 @@ int mp_aframe_get_total_plane_samples(struct mp_aframe *frame) ? 1 : mp_aframe_get_channels(frame)); } +char *mp_aframe_format_str_buf(char *buf, size_t buf_size, struct mp_aframe *fmt) +{ + char ch[128]; + mp_chmap_to_str_buf(ch, sizeof(ch), &fmt->chmap); + char *hr_ch = mp_chmap_to_str_hr(&fmt->chmap); + if (strcmp(hr_ch, ch) != 0) + mp_snprintf_cat(ch, sizeof(ch), " (%s)", hr_ch); + snprintf(buf, buf_size, "%dHz %s %dch %s", fmt->av_frame->sample_rate, + ch, fmt->chmap.num, af_fmt_to_str(fmt->format)); + return buf; +} + // Set data to the audio after the given number of samples (i.e. slice it). void mp_aframe_skip_samples(struct mp_aframe *f, int samples) { @@ -352,25 +418,25 @@ void mp_aframe_skip_samples(struct mp_aframe *f, int samples) f->av_frame->nb_samples -= samples; if (f->pts != MP_NOPTS_VALUE) - f->pts += samples / (double)mp_aframe_get_rate(f); + f->pts += samples / mp_aframe_get_effective_rate(f); } // Return the timestamp of the sample just after the end of this frame. double mp_aframe_end_pts(struct mp_aframe *f) { - int rate = mp_aframe_get_rate(f); - if (f->pts == MP_NOPTS_VALUE || rate < 1) + double rate = mp_aframe_get_effective_rate(f); + if (f->pts == MP_NOPTS_VALUE || rate <= 0) return MP_NOPTS_VALUE; - return f->pts + f->av_frame->nb_samples / (double)rate; + return f->pts + f->av_frame->nb_samples / rate; } // Return the duration in seconds of the frame (0 if invalid). double mp_aframe_duration(struct mp_aframe *f) { - int rate = mp_aframe_get_rate(f); - if (rate < 1) + double rate = mp_aframe_get_effective_rate(f); + if (rate <= 0) return 0; - return f->av_frame->nb_samples / (double)rate; + return f->av_frame->nb_samples / rate; } // Clip the given frame to the given timestamp range. Adjusts the frame size @@ -378,7 +444,7 @@ double mp_aframe_duration(struct mp_aframe *f) void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end) { double f_end = mp_aframe_end_pts(f); - int rate = mp_aframe_get_rate(f); + double rate = mp_aframe_get_effective_rate(f); if (f_end == MP_NOPTS_VALUE) return; if (end != MP_NOPTS_VALUE) { @@ -405,6 +471,52 @@ void mp_aframe_clip_timestamps(struct mp_aframe *f, double start, double end) } } +bool mp_aframe_copy_samples(struct mp_aframe *dst, int dst_offset, + struct mp_aframe *src, int src_offset, + int samples) +{ + if (!mp_aframe_config_equals(dst, src)) + return false; + + if (mp_aframe_get_size(dst) < dst_offset + samples || + mp_aframe_get_size(src) < src_offset + samples) + return false; + + uint8_t **s = mp_aframe_get_data_ro(src); + uint8_t **d = mp_aframe_get_data_rw(dst); + if (!s || !d) + return false; + + int planes = mp_aframe_get_planes(dst); + size_t sstride = mp_aframe_get_sstride(dst); + + for (int n = 0; n < planes; n++) { + memcpy(d[n] + dst_offset * sstride, s[n] + src_offset * sstride, + samples * sstride); + } + + return true; +} + +bool mp_aframe_set_silence(struct mp_aframe *f, int offset, int samples) +{ + if (mp_aframe_get_size(f) < offset + samples) + return false; + + int format = mp_aframe_get_format(f); + uint8_t **d = mp_aframe_get_data_rw(f); + if (!d) + return false; + + int planes = mp_aframe_get_planes(f); + size_t sstride = mp_aframe_get_sstride(f); + + for (int n = 0; n < planes; n++) + af_fill_silence(d[n] + offset * sstride, samples * sstride, format); + + return true; +} + struct mp_aframe_pool { AVBufferPool *avpool; int element_size; |