|
|
|
@ -95,6 +95,8 @@ static int filter_frame(AVFilterLink *inlink, AVFrame *in) |
|
|
|
|
return 0; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
#if CONFIG_REVERSE_FILTER |
|
|
|
|
|
|
|
|
|
static int request_frame(AVFilterLink *outlink) |
|
|
|
|
{ |
|
|
|
|
AVFilterContext *ctx = outlink->src; |
|
|
|
@ -141,3 +143,117 @@ AVFilter ff_vf_reverse = { |
|
|
|
|
.inputs = reverse_inputs, |
|
|
|
|
.outputs = reverse_outputs, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#endif /* CONFIG_REVERSE_FILTER */ |
|
|
|
|
|
|
|
|
|
#if CONFIG_AREVERSE_FILTER |
|
|
|
|
|
|
|
|
|
static int query_formats(AVFilterContext *ctx) |
|
|
|
|
{ |
|
|
|
|
AVFilterFormats *formats; |
|
|
|
|
AVFilterChannelLayouts *layouts; |
|
|
|
|
int ret; |
|
|
|
|
|
|
|
|
|
layouts = ff_all_channel_layouts(); |
|
|
|
|
if (!layouts) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
ret = ff_set_common_channel_layouts(ctx, layouts); |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
ret = ff_set_common_formats(ctx, ff_planar_sample_fmts()); |
|
|
|
|
if (ret < 0) |
|
|
|
|
return ret; |
|
|
|
|
|
|
|
|
|
formats = ff_all_samplerates(); |
|
|
|
|
if (!formats) |
|
|
|
|
return AVERROR(ENOMEM); |
|
|
|
|
return ff_set_common_samplerates(ctx, formats); |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static int areverse_request_frame(AVFilterLink *outlink) |
|
|
|
|
{ |
|
|
|
|
AVFilterContext *ctx = outlink->src; |
|
|
|
|
ReverseContext *s = ctx->priv; |
|
|
|
|
int ret, p, i, j; |
|
|
|
|
|
|
|
|
|
ret = ff_request_frame(ctx->inputs[0]); |
|
|
|
|
|
|
|
|
|
if (ret == AVERROR_EOF && s->nb_frames > 0) { |
|
|
|
|
AVFrame *out = s->frames[s->nb_frames - 1]; |
|
|
|
|
out->pts = s->pts[s->flush_idx++]; |
|
|
|
|
|
|
|
|
|
for (p = 0; p < outlink->channels; p++) { |
|
|
|
|
switch (outlink->format) { |
|
|
|
|
case AV_SAMPLE_FMT_U8P: { |
|
|
|
|
uint8_t *dst = (uint8_t *)out->extended_data[p]; |
|
|
|
|
for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) |
|
|
|
|
FFSWAP(uint8_t, dst[i], dst[j]); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_S16P: { |
|
|
|
|
int16_t *dst = (int16_t *)out->extended_data[p]; |
|
|
|
|
for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) |
|
|
|
|
FFSWAP(int16_t, dst[i], dst[j]); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_S32P: { |
|
|
|
|
int32_t *dst = (int32_t *)out->extended_data[p]; |
|
|
|
|
for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) |
|
|
|
|
FFSWAP(int32_t, dst[i], dst[j]); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_FLTP: { |
|
|
|
|
float *dst = (float *)out->extended_data[p]; |
|
|
|
|
for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) |
|
|
|
|
FFSWAP(float, dst[i], dst[j]); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
case AV_SAMPLE_FMT_DBLP: { |
|
|
|
|
double *dst = (double *)out->extended_data[p]; |
|
|
|
|
for (i = 0, j = out->nb_samples - 1; i < j; i++, j--) |
|
|
|
|
FFSWAP(double, dst[i], dst[j]); |
|
|
|
|
} |
|
|
|
|
break; |
|
|
|
|
} |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
ret = ff_filter_frame(outlink, out); |
|
|
|
|
s->nb_frames--; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
return ret; |
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
static const AVFilterPad areverse_inputs[] = { |
|
|
|
|
{ |
|
|
|
|
.name = "default", |
|
|
|
|
.type = AVMEDIA_TYPE_AUDIO, |
|
|
|
|
.filter_frame = filter_frame, |
|
|
|
|
.needs_writable = 1, |
|
|
|
|
}, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
static const AVFilterPad areverse_outputs[] = { |
|
|
|
|
{ |
|
|
|
|
.name = "default", |
|
|
|
|
.type = AVMEDIA_TYPE_AUDIO, |
|
|
|
|
.request_frame = areverse_request_frame, |
|
|
|
|
.config_props = config_output, |
|
|
|
|
}, |
|
|
|
|
{ NULL } |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
AVFilter ff_af_areverse = { |
|
|
|
|
.name = "areverse", |
|
|
|
|
.description = NULL_IF_CONFIG_SMALL("Reverse an audio clip."), |
|
|
|
|
.query_formats = query_formats, |
|
|
|
|
.priv_size = sizeof(ReverseContext), |
|
|
|
|
.init = init, |
|
|
|
|
.uninit = uninit, |
|
|
|
|
.inputs = areverse_inputs, |
|
|
|
|
.outputs = areverse_outputs, |
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
#endif /* CONFIG_AREVERSE_FILTER */ |
|
|
|
|