You've already forked FFmpeg
							
							
				mirror of
				https://github.com/FFmpeg/FFmpeg.git
				synced 2025-10-30 23:18:11 +02:00 
			
		
		
		
	avfilter: add loop filters
Signed-off-by: Paul B Mahol <onemda@gmail.com>
This commit is contained in:
		| @@ -4,6 +4,7 @@ releases are sorted from youngest to oldest. | ||||
| version <next>: | ||||
| - DXVA2-accelerated HEVC Main10 decoding | ||||
| - fieldhint filter | ||||
| - loop video filter and aloop audio filter | ||||
|  | ||||
|  | ||||
| version 3.0: | ||||
|   | ||||
| @@ -15,6 +15,9 @@ libavutil:     2015-08-28 | ||||
|  | ||||
| API changes, most recent first: | ||||
|  | ||||
| 2016-xx-xx - lavu 55.18.100 | ||||
|   xxxxxxx audio_fifo.h - Add av_audio_fifo_peek_at(). | ||||
|  | ||||
| 2016-xx-xx - lavu 55.18.0 | ||||
|   xxxxxxx buffer.h - Add av_buffer_pool_init2(). | ||||
|   xxxxxxx hwcontext.h - Add a new installed header hwcontext.h with a new API | ||||
|   | ||||
| @@ -8185,6 +8185,25 @@ The formula that generates the correction is: | ||||
| where @var{r_0} is halve of the image diagonal and @var{r_src} and @var{r_tgt} are the | ||||
| distances from the focal point in the source and target images, respectively. | ||||
|  | ||||
| @section loop, aloop | ||||
|  | ||||
| Loop video frames or audio samples. | ||||
|  | ||||
| Those filters accepts the following options: | ||||
|  | ||||
| @table @option | ||||
| @item loop | ||||
| Set the number of loops. | ||||
|  | ||||
| @item size | ||||
| Set maximal size in number of frames for @code{loop} filter or maximal number | ||||
| of samples in case of @code{aloop} filter. | ||||
|  | ||||
| @item start | ||||
| Set first frame of loop for @code{loop} filter or first sample of loop in case | ||||
| of @code{aloop} filter. | ||||
| @end table | ||||
|  | ||||
| @anchor{lut3d} | ||||
| @section lut3d | ||||
|  | ||||
|   | ||||
| @@ -38,6 +38,7 @@ OBJS-$(CONFIG_AGATE_FILTER)                  += af_agate.o | ||||
| OBJS-$(CONFIG_AINTERLEAVE_FILTER)            += f_interleave.o | ||||
| OBJS-$(CONFIG_ALIMITER_FILTER)               += af_alimiter.o | ||||
| OBJS-$(CONFIG_ALLPASS_FILTER)                += af_biquads.o | ||||
| OBJS-$(CONFIG_ALOOP_FILTER)                  += f_loop.o | ||||
| OBJS-$(CONFIG_AMERGE_FILTER)                 += af_amerge.o | ||||
| OBJS-$(CONFIG_AMETADATA_FILTER)              += f_metadata.o | ||||
| OBJS-$(CONFIG_AMIX_FILTER)                   += af_amix.o | ||||
| @@ -181,6 +182,7 @@ OBJS-$(CONFIG_INTERLACE_FILTER)              += vf_interlace.o | ||||
| OBJS-$(CONFIG_INTERLEAVE_FILTER)             += f_interleave.o | ||||
| OBJS-$(CONFIG_KERNDEINT_FILTER)              += vf_kerndeint.o | ||||
| OBJS-$(CONFIG_LENSCORRECTION_FILTER)         += vf_lenscorrection.o | ||||
| OBJS-$(CONFIG_LOOP_FILTER)                   += f_loop.o | ||||
| OBJS-$(CONFIG_LUT3D_FILTER)                  += vf_lut3d.o | ||||
| OBJS-$(CONFIG_LUT_FILTER)                    += vf_lut.o | ||||
| OBJS-$(CONFIG_LUTRGB_FILTER)                 += vf_lut.o | ||||
|   | ||||
| @@ -58,6 +58,7 @@ void avfilter_register_all(void) | ||||
|     REGISTER_FILTER(AINTERLEAVE,    ainterleave,    af); | ||||
|     REGISTER_FILTER(ALIMITER,       alimiter,       af); | ||||
|     REGISTER_FILTER(ALLPASS,        allpass,        af); | ||||
|     REGISTER_FILTER(ALOOP,          aloop,          af); | ||||
|     REGISTER_FILTER(AMERGE,         amerge,         af); | ||||
|     REGISTER_FILTER(AMETADATA,      ametadata,      af); | ||||
|     REGISTER_FILTER(AMIX,           amix,           af); | ||||
| @@ -202,6 +203,7 @@ void avfilter_register_all(void) | ||||
|     REGISTER_FILTER(INTERLEAVE,     interleave,     vf); | ||||
|     REGISTER_FILTER(KERNDEINT,      kerndeint,      vf); | ||||
|     REGISTER_FILTER(LENSCORRECTION, lenscorrection, vf); | ||||
|     REGISTER_FILTER(LOOP,           loop,           vf); | ||||
|     REGISTER_FILTER(LUT3D,          lut3d,          vf); | ||||
|     REGISTER_FILTER(LUT,            lut,            vf); | ||||
|     REGISTER_FILTER(LUTRGB,         lutrgb,         vf); | ||||
|   | ||||
							
								
								
									
										381
									
								
								libavfilter/f_loop.c
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										381
									
								
								libavfilter/f_loop.c
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,381 @@ | ||||
| /* | ||||
|  * Copyright (c) 2016 Paul B Mahol | ||||
|  * | ||||
|  * This file is part of FFmpeg. | ||||
|  * | ||||
|  * FFmpeg is free software; you can redistribute it and/or | ||||
|  * modify it under the terms of the GNU Lesser General Public | ||||
|  * License as published by the Free Software Foundation; either | ||||
|  * version 2.1 of the License, or (at your option) any later version. | ||||
|  * | ||||
|  * FFmpeg is distributed in the hope that it will be useful, | ||||
|  * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||||
|  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU | ||||
|  * Lesser General Public License for more details. | ||||
|  * | ||||
|  * You should have received a copy of the GNU Lesser General Public | ||||
|  * License along with FFmpeg; if not, write to the Free Software | ||||
|  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA | ||||
|  */ | ||||
|  | ||||
| #include "libavutil/audio_fifo.h" | ||||
| #include "libavutil/avassert.h" | ||||
| #include "libavutil/fifo.h" | ||||
| #include "libavutil/internal.h" | ||||
| #include "libavutil/opt.h" | ||||
| #include "avfilter.h" | ||||
| #include "audio.h" | ||||
| #include "formats.h" | ||||
| #include "internal.h" | ||||
| #include "video.h" | ||||
|  | ||||
| typedef struct LoopContext { | ||||
|     const AVClass *class; | ||||
|  | ||||
|     AVAudioFifo *fifo; | ||||
|     AVAudioFifo *left; | ||||
|     AVFrame **frames; | ||||
|     int nb_frames; | ||||
|     int current_frame; | ||||
|     int64_t start_pts; | ||||
|     int64_t duration; | ||||
|     int64_t current_sample; | ||||
|     int64_t nb_samples; | ||||
|     int64_t ignored_samples; | ||||
|  | ||||
|     int loop; | ||||
|     int64_t size; | ||||
|     int64_t start; | ||||
|     int64_t pts; | ||||
| } LoopContext; | ||||
|  | ||||
| #define AFLAGS AV_OPT_FLAG_AUDIO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||||
| #define VFLAGS AV_OPT_FLAG_VIDEO_PARAM|AV_OPT_FLAG_FILTERING_PARAM | ||||
| #define OFFSET(x) offsetof(LoopContext, x) | ||||
|  | ||||
| #if CONFIG_ALOOP_FILTER | ||||
|  | ||||
| static int aconfig_input(AVFilterLink *inlink) | ||||
| { | ||||
|     AVFilterContext *ctx = inlink->dst; | ||||
|     LoopContext *s  = ctx->priv; | ||||
|  | ||||
|     s->fifo = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192); | ||||
|     s->left = av_audio_fifo_alloc(inlink->format, inlink->channels, 8192); | ||||
|     if (!s->fifo || !s->left) | ||||
|         return AVERROR(ENOMEM); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static av_cold void auninit(AVFilterContext *ctx) | ||||
| { | ||||
|     LoopContext *s = ctx->priv; | ||||
|  | ||||
|     av_audio_fifo_free(s->fifo); | ||||
|     av_audio_fifo_free(s->left); | ||||
| } | ||||
|  | ||||
| static int push_samples(AVFilterContext *ctx, int nb_samples) | ||||
| { | ||||
|     AVFilterLink *outlink = ctx->outputs[0]; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     AVFrame *out; | ||||
|     int ret, i = 0; | ||||
|  | ||||
|     while (s->loop != 0 && i < nb_samples) { | ||||
|         out = ff_get_audio_buffer(outlink, FFMIN(nb_samples, s->nb_samples - s->current_sample)); | ||||
|         if (!out) | ||||
|             return AVERROR(ENOMEM); | ||||
|         ret = av_audio_fifo_peek_at(s->fifo, (void **)out->extended_data, out->nb_samples, s->current_sample); | ||||
|         if (ret < 0) | ||||
|             return ret; | ||||
|         out->pts = s->pts; | ||||
|         out->nb_samples = ret; | ||||
|         s->pts += out->nb_samples; | ||||
|         i += out->nb_samples; | ||||
|         s->current_sample += out->nb_samples; | ||||
|  | ||||
|         ret = ff_filter_frame(outlink, out); | ||||
|         if (ret < 0) | ||||
|             return ret; | ||||
|  | ||||
|         if (s->current_sample >= s->nb_samples) { | ||||
|             s->current_sample = 0; | ||||
|  | ||||
|             if (s->loop > 0) | ||||
|                 s->loop--; | ||||
|         } | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int afilter_frame(AVFilterLink *inlink, AVFrame *frame) | ||||
| { | ||||
|     AVFilterContext *ctx = inlink->dst; | ||||
|     AVFilterLink *outlink = ctx->outputs[0]; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int ret = 0; | ||||
|  | ||||
|     if (s->ignored_samples + frame->nb_samples > s->start && s->size > 0 && s->loop != 0) { | ||||
|         if (s->nb_samples < s->size) { | ||||
|             int written = FFMIN(frame->nb_samples, s->size - s->nb_samples); | ||||
|             int drain = 0; | ||||
|  | ||||
|             ret = av_audio_fifo_write(s->fifo, (void **)frame->extended_data, written); | ||||
|             if (ret < 0) | ||||
|                 return ret; | ||||
|             if (!s->nb_samples) { | ||||
|                 drain = FFMAX(0, s->start - s->ignored_samples); | ||||
|                 s->pts = frame->pts; | ||||
|                 av_audio_fifo_drain(s->fifo, drain); | ||||
|                 s->pts += s->start - s->ignored_samples; | ||||
|             } | ||||
|             s->nb_samples += ret - drain; | ||||
|             drain = frame->nb_samples - written; | ||||
|             if (s->nb_samples == s->size && drain > 0) { | ||||
|                 int ret2; | ||||
|  | ||||
|                 ret2 = av_audio_fifo_write(s->left, (void **)frame->extended_data, frame->nb_samples); | ||||
|                 if (ret2 < 0) | ||||
|                    return ret2; | ||||
|                 av_audio_fifo_drain(s->left, drain); | ||||
|             } | ||||
|             frame->nb_samples = ret; | ||||
|             s->pts += ret; | ||||
|             ret = ff_filter_frame(outlink, frame); | ||||
|         } else { | ||||
|             int nb_samples = frame->nb_samples; | ||||
|  | ||||
|             av_frame_free(&frame); | ||||
|             ret = push_samples(ctx, nb_samples); | ||||
|         } | ||||
|     } else { | ||||
|         s->ignored_samples += frame->nb_samples; | ||||
|         frame->pts = s->pts; | ||||
|         s->pts += frame->nb_samples; | ||||
|         ret = ff_filter_frame(outlink, frame); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int arequest_frame(AVFilterLink *outlink) | ||||
| { | ||||
|     AVFilterContext *ctx = outlink->src; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int ret = 0; | ||||
|  | ||||
|     if ((!s->size) || | ||||
|         (s->nb_samples < s->size) || | ||||
|         (s->nb_samples >= s->size && s->loop == 0)) { | ||||
|         int nb_samples = av_audio_fifo_size(s->left); | ||||
|  | ||||
|         if (s->loop == 0 && nb_samples > 0) { | ||||
|             AVFrame *out; | ||||
|  | ||||
|             out = ff_get_audio_buffer(outlink, nb_samples); | ||||
|             if (!out) | ||||
|                 return AVERROR(ENOMEM); | ||||
|             av_audio_fifo_read(s->left, (void **)out->extended_data, nb_samples); | ||||
|             out->pts = s->pts; | ||||
|             s->pts += nb_samples; | ||||
|             ret = ff_filter_frame(outlink, out); | ||||
|             if (ret < 0) | ||||
|                 return ret; | ||||
|         } | ||||
|         ret = ff_request_frame(ctx->inputs[0]); | ||||
|     } else { | ||||
|         ret = push_samples(ctx, 1024); | ||||
|     } | ||||
|  | ||||
|     if (ret == AVERROR_EOF && s->nb_samples > 0 && s->loop != 0) { | ||||
|         ret = push_samples(ctx, outlink->sample_rate); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static const AVOption aloop_options[] = { | ||||
|     { "loop",  "number of loops",               OFFSET(loop),  AV_OPT_TYPE_INT,   {.i64 = 0 }, -1, INT_MAX,   AFLAGS }, | ||||
|     { "size",  "max number of samples to loop", OFFSET(size),  AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT32_MAX, AFLAGS }, | ||||
|     { "start", "set the loop start sample",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT64_MAX, AFLAGS }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| AVFILTER_DEFINE_CLASS(aloop); | ||||
|  | ||||
| static const AVFilterPad ainputs[] = { | ||||
|     { | ||||
|         .name         = "default", | ||||
|         .type         = AVMEDIA_TYPE_AUDIO, | ||||
|         .filter_frame = afilter_frame, | ||||
|         .config_props = aconfig_input, | ||||
|     }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| static const AVFilterPad aoutputs[] = { | ||||
|     { | ||||
|         .name          = "default", | ||||
|         .type          = AVMEDIA_TYPE_AUDIO, | ||||
|         .request_frame = arequest_frame, | ||||
|     }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| AVFilter ff_af_aloop = { | ||||
|     .name          = "aloop", | ||||
|     .description   = NULL_IF_CONFIG_SMALL("Loop audio samples."), | ||||
|     .priv_size     = sizeof(LoopContext), | ||||
|     .priv_class    = &aloop_class, | ||||
|     .uninit        = auninit, | ||||
|     .query_formats = ff_query_formats_all, | ||||
|     .inputs        = ainputs, | ||||
|     .outputs       = aoutputs, | ||||
| }; | ||||
| #endif /* CONFIG_ALOOP_FILTER */ | ||||
|  | ||||
| #if CONFIG_LOOP_FILTER | ||||
|  | ||||
| static av_cold int init(AVFilterContext *ctx) | ||||
| { | ||||
|     LoopContext *s = ctx->priv; | ||||
|  | ||||
|     s->frames = av_calloc(s->size, sizeof(*s->frames)); | ||||
|     if (!s->frames) | ||||
|         return AVERROR(ENOMEM); | ||||
|  | ||||
|     return 0; | ||||
| } | ||||
|  | ||||
| static av_cold void uninit(AVFilterContext *ctx) | ||||
| { | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int i; | ||||
|  | ||||
|     for (i = 0; i < s->nb_frames; i++) | ||||
|         av_frame_free(&s->frames[i]); | ||||
|  | ||||
|     av_freep(&s->frames); | ||||
|     s->nb_frames = 0; | ||||
| } | ||||
|  | ||||
| static int push_frame(AVFilterContext *ctx) | ||||
| { | ||||
|     AVFilterLink *outlink = ctx->outputs[0]; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int64_t pts; | ||||
|     int ret; | ||||
|  | ||||
|     AVFrame *out = av_frame_clone(s->frames[s->current_frame]); | ||||
|  | ||||
|     if (!out) | ||||
|         return AVERROR(ENOMEM); | ||||
|     out->pts += s->duration - s->start_pts; | ||||
|     pts = out->pts + av_frame_get_pkt_duration(out); | ||||
|     ret = ff_filter_frame(outlink, out); | ||||
|     s->current_frame++; | ||||
|  | ||||
|     if (s->current_frame >= s->nb_frames) { | ||||
|         s->duration = pts; | ||||
|         s->current_frame = 0; | ||||
|  | ||||
|         if (s->loop > 0) | ||||
|             s->loop--; | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int filter_frame(AVFilterLink *inlink, AVFrame *frame) | ||||
| { | ||||
|     AVFilterContext *ctx = inlink->dst; | ||||
|     AVFilterLink *outlink = ctx->outputs[0]; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int ret = 0; | ||||
|  | ||||
|     if (inlink->frame_count >= s->start && s->size > 0 && s->loop != 0) { | ||||
|         if (s->nb_frames < s->size) { | ||||
|             if (!s->nb_frames) | ||||
|                 s->start_pts = frame->pts; | ||||
|             s->frames[s->nb_frames] = av_frame_clone(frame); | ||||
|             if (!s->frames[s->nb_frames]) { | ||||
|                 av_frame_free(&frame); | ||||
|                 return AVERROR(ENOMEM); | ||||
|             } | ||||
|             s->nb_frames++; | ||||
|             s->duration = frame->pts + av_frame_get_pkt_duration(frame); | ||||
|             ret = ff_filter_frame(outlink, frame); | ||||
|         } else { | ||||
|             av_frame_free(&frame); | ||||
|             ret = push_frame(ctx); | ||||
|         } | ||||
|     } else { | ||||
|         frame->pts += s->duration; | ||||
|         ret = ff_filter_frame(outlink, frame); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static int request_frame(AVFilterLink *outlink) | ||||
| { | ||||
|     AVFilterContext *ctx = outlink->src; | ||||
|     LoopContext *s = ctx->priv; | ||||
|     int ret = 0; | ||||
|  | ||||
|     if ((!s->size) || | ||||
|         (s->nb_frames < s->size) || | ||||
|         (s->nb_frames >= s->size && s->loop == 0)) { | ||||
|         ret = ff_request_frame(ctx->inputs[0]); | ||||
|     } else { | ||||
|         ret = push_frame(ctx); | ||||
|     } | ||||
|  | ||||
|     if (ret == AVERROR_EOF && s->nb_frames > 0 && s->loop != 0) { | ||||
|         ret = push_frame(ctx); | ||||
|     } | ||||
|  | ||||
|     return ret; | ||||
| } | ||||
|  | ||||
| static const AVOption loop_options[] = { | ||||
|     { "loop",  "number of loops",              OFFSET(loop),  AV_OPT_TYPE_INT,   {.i64 = 0 }, -1, INT_MAX,   VFLAGS }, | ||||
|     { "size",  "max number of frames to loop", OFFSET(size),  AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT16_MAX, VFLAGS }, | ||||
|     { "start", "set the loop start frame",     OFFSET(start), AV_OPT_TYPE_INT64, {.i64 = 0 },  0, INT64_MAX, VFLAGS }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| AVFILTER_DEFINE_CLASS(loop); | ||||
|  | ||||
| static const AVFilterPad inputs[] = { | ||||
|     { | ||||
|         .name         = "default", | ||||
|         .type         = AVMEDIA_TYPE_VIDEO, | ||||
|         .filter_frame = filter_frame, | ||||
|     }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| static const AVFilterPad outputs[] = { | ||||
|     { | ||||
|         .name          = "default", | ||||
|         .type          = AVMEDIA_TYPE_VIDEO, | ||||
|         .request_frame = request_frame, | ||||
|     }, | ||||
|     { NULL } | ||||
| }; | ||||
|  | ||||
| AVFilter ff_vf_loop = { | ||||
|     .name        = "loop", | ||||
|     .description = NULL_IF_CONFIG_SMALL("Loop video frames."), | ||||
|     .priv_size   = sizeof(LoopContext), | ||||
|     .priv_class  = &loop_class, | ||||
|     .init        = init, | ||||
|     .uninit      = uninit, | ||||
|     .inputs      = inputs, | ||||
|     .outputs     = outputs, | ||||
| }; | ||||
| #endif /* CONFIG_LOOP_FILTER */ | ||||
| @@ -30,7 +30,7 @@ | ||||
| #include "libavutil/version.h" | ||||
|  | ||||
| #define LIBAVFILTER_VERSION_MAJOR   6 | ||||
| #define LIBAVFILTER_VERSION_MINOR  32 | ||||
| #define LIBAVFILTER_VERSION_MINOR  33 | ||||
| #define LIBAVFILTER_VERSION_MICRO 100 | ||||
|  | ||||
| #define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \ | ||||
|   | ||||
| @@ -155,6 +155,30 @@ int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples) | ||||
|     return nb_samples; | ||||
| } | ||||
|  | ||||
| int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset) | ||||
| { | ||||
|     int i, ret, size; | ||||
|  | ||||
|     if (offset < 0 || offset >= af->nb_samples) | ||||
|         return AVERROR(EINVAL); | ||||
|     if (nb_samples < 0) | ||||
|         return AVERROR(EINVAL); | ||||
|     nb_samples = FFMIN(nb_samples, af->nb_samples); | ||||
|     if (!nb_samples) | ||||
|         return 0; | ||||
|     if (offset > af->nb_samples - nb_samples) | ||||
|         return AVERROR(EINVAL); | ||||
|  | ||||
|     offset *= af->sample_size; | ||||
|     size = nb_samples * af->sample_size; | ||||
|     for (i = 0; i < af->nb_buffers; i++) { | ||||
|         if ((ret = av_fifo_generic_peek_at(af->buf[i], data[i], offset, size, NULL)) < 0) | ||||
|             return AVERROR_BUG; | ||||
|     } | ||||
|  | ||||
|     return nb_samples; | ||||
| } | ||||
|  | ||||
| int av_audio_fifo_read(AVAudioFifo *af, void **data, int nb_samples) | ||||
| { | ||||
|     int i, ret, size; | ||||
|   | ||||
| @@ -110,6 +110,23 @@ int av_audio_fifo_write(AVAudioFifo *af, void **data, int nb_samples); | ||||
|  */ | ||||
| int av_audio_fifo_peek(AVAudioFifo *af, void **data, int nb_samples); | ||||
|  | ||||
| /** | ||||
|  * Peek data from an AVAudioFifo. | ||||
|  * | ||||
|  * @see enum AVSampleFormat | ||||
|  * The documentation for AVSampleFormat describes the data layout. | ||||
|  * | ||||
|  * @param af          AVAudioFifo to read from | ||||
|  * @param data        audio data plane pointers | ||||
|  * @param nb_samples  number of samples to peek | ||||
|  * @param offset      offset from current read position | ||||
|  * @return            number of samples actually peek, or negative AVERROR code | ||||
|  *                    on failure. The number of samples actually peek will not | ||||
|  *                    be greater than nb_samples, and will only be less than | ||||
|  *                    nb_samples if av_audio_fifo_size is less than nb_samples. | ||||
|  */ | ||||
| int av_audio_fifo_peek_at(AVAudioFifo *af, void **data, int nb_samples, int offset); | ||||
|  | ||||
| /** | ||||
|  * Read data from an AVAudioFifo. | ||||
|  * | ||||
|   | ||||
		Reference in New Issue
	
	Block a user