Merge remote-tracking branch 'qatar/master'

* qatar/master:
  x86: Only use optimizations with cmov if the CPU supports the instruction
  x86: Add CPU flag for the i686 cmov instruction
  x86: remove unused inline asm macros from dsputil_mmx.h
  x86: move some inline asm macros to the only places they are used
  lavfi: Add the af_channelmap audio channel mapping filter.
  lavfi: add join audio filter.
  lavfi: allow audio filters to request a given number of samples.
  lavfi: support automatically inserting the fifo filter when needed.
  lavfi/audio: eliminate ff_default_filter_samples().

Conflicts:
	Changelog
	libavcodec/x86/h264dsp_mmx.c
	libavfilter/Makefile
	libavfilter/allfilters.c
	libavfilter/avfilter.h
	libavfilter/avfiltergraph.c
	libavfilter/version.h
	libavutil/x86/cpu.c

Merged-by: Michael Niedermayer <michaelni@gmx.at>
This commit is contained in:
Michael Niedermayer 2012-06-24 02:09:53 +02:00
commit 1c60088885
44 changed files with 1314 additions and 279 deletions

View File

@ -12,6 +12,8 @@ version next:
- RTMPT protocol support
- iLBC encoding/decoding via libilbc
- Microsoft Screen 1 decoder
- join audio filter
- audio channel mapping filter
- showwaves filter
- LucasArts SMUSH playback support

View File

@ -4,7 +4,7 @@ since the last major version increase.
The last version increases were:
libavcodec: 2012-01-27
libavdevice: 2011-04-18
libavfilter: 2011-04-18
libavfilter: 2012-06-22
libavformat: 2012-01-27
libavresample: 2012-04-24
libpostproc: 2011-04-18

View File

@ -649,6 +649,76 @@ front_center.wav -map '[LFE]' lfe.wav -map '[SL]' side_left.wav -map '[SR]'
side_right.wav
@end example
@section channelmap
Remap input channels to new locations.
This filter accepts the following named parameters:
@table @option
@item channel_layout
Channel layout of the output stream.
@item map
Map channels from input to output. The argument is a comma-separated list of
mappings, each in the @code{@var{in_channel}-@var{out_channel}} or
@var{in_channel} form. @var{in_channel} can be either the name of the input
channel (e.g. FL for front left) or its index in the input channel layout.
@var{out_channel} is the name of the output channel or its index in the output
channel layout. If @var{out_channel} is not given then it is implicitly an
index, starting with zero and increasing by one for each mapping.
@end table
If no mapping is present, the filter will implicitly map input channels to
output channels preserving index.
For example, assuming a 5.1+downmix input MOV file
@example
ffmpeg -i in.mov -filter 'channelmap=map=DL-FL\,DR-FR' out.wav
@end example
will create an output WAV file tagged as stereo from the downmix channels of
the input.
To fix a 5.1 WAV improperly encoded in AAC's native channel order
@example
ffmpeg -i in.wav -filter 'channelmap=1\,2\,0\,5\,3\,4:channel_layout=5.1' out.wav
@end example
@section join
Join multiple input streams into one multi-channel stream.
The filter accepts the following named parameters:
@table @option
@item inputs
Number of input streams. Defaults to 2.
@item channel_layout
Desired output channel layout. Defaults to stereo.
@item map
Map channels from inputs to output. The argument is a comma-separated list of
mappings, each in the @code{@var{input_idx}.@var{in_channel}-@var{out_channel}}
form. @var{input_idx} is the 0-based index of the input stream. @var{in_channel}
can be either the name of the input channel (e.g. FR for front left) or its
index in the specified input stream. @var{out_channel} is the name of the output
channel.
@end table
The filter will attempt to guess the mappings when those are not specified
explicitly. It does so by first trying to find an unused matching input channel
and if that fails it picks the first unused input channel.
E.g. to join 3 inputs (with properly set channel layouts)
@example
ffmpeg -i INPUT1 -i INPUT2 -i INPUT3 -filter_complex join=inputs=3 OUTPUT
@end example
To build a 5.1 output from 6 single-channel streams:
@example
ffmpeg -i fl -i fr -i fc -i sl -i sr -i lfe -filter_complex
'join=inputs=6:channel_layout=5.1:map=0.0-FL\,1.0-FR\,2.0-FC\,3.0-SL\,4.0-SR\,5.0-LFE'
out
@end example
@section resample
Convert the audio sample format, sample rate and channel layout. This filter is
not meant to be used directly.

View File

@ -29,6 +29,12 @@
#include "libavcodec/cavsdsp.h"
#include "dsputil_mmx.h"
/* in/out: mma=mma+mmb, mmb=mmb-mma */
#define SUMSUB_BA( a, b ) \
"paddw "#b", "#a" \n\t"\
"paddw "#b", "#b" \n\t"\
"psubw "#a", "#b" \n\t"
/*****************************************************************************
*
* inverse transform

View File

@ -631,6 +631,34 @@ static void add_hfyu_median_prediction_cmov(uint8_t *dst, const uint8_t *top,
}
#endif
static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){
__asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ...
"movd (%1), %%mm0 \n\t"
"add %3, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"movd (%1,%3,1), %%mm2 \n\t"
"movd (%1,%3,2), %%mm3 \n\t"
"punpcklbw %%mm1, %%mm0 \n\t"
"punpcklbw %%mm3, %%mm2 \n\t"
"movq %%mm0, %%mm1 \n\t"
"punpcklwd %%mm2, %%mm0 \n\t"
"punpckhwd %%mm2, %%mm1 \n\t"
"movd %%mm0, (%0) \n\t"
"add %2, %0 \n\t"
"punpckhdq %%mm0, %%mm0 \n\t"
"movd %%mm0, (%0) \n\t"
"movd %%mm1, (%0,%2,1) \n\t"
"punpckhdq %%mm1, %%mm1 \n\t"
"movd %%mm1, (%0,%2,2) \n\t"
: "+&r" (dst),
"+&r" (src)
: "r" (dst_stride),
"r" (src_stride)
: "memory"
);
}
#define H263_LOOP_FILTER \
"pxor %%mm7, %%mm7 \n\t" \
"movq %0, %%mm0 \n\t" \
@ -2902,7 +2930,8 @@ static void dsputil_init_3dnow(DSPContext *c, AVCodecContext *avctx,
c->vorbis_inverse_coupling = vorbis_inverse_coupling_3dnow;
#if HAVE_7REGS
c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov;
if (mm_flags & AV_CPU_FLAG_CMOV)
c->add_hfyu_median_prediction = add_hfyu_median_prediction_cmov;
#endif
}

View File

@ -66,24 +66,6 @@ extern const xmm_reg ff_pb_FE;
extern const double ff_pd_1[2];
extern const double ff_pd_2[2];
#define LOAD4(stride,in,a,b,c,d)\
"movq 0*"#stride"+"#in", "#a"\n\t"\
"movq 1*"#stride"+"#in", "#b"\n\t"\
"movq 2*"#stride"+"#in", "#c"\n\t"\
"movq 3*"#stride"+"#in", "#d"\n\t"
#define STORE4(stride,out,a,b,c,d)\
"movq "#a", 0*"#stride"+"#out"\n\t"\
"movq "#b", 1*"#stride"+"#out"\n\t"\
"movq "#c", 2*"#stride"+"#out"\n\t"\
"movq "#d", 3*"#stride"+"#out"\n\t"
/* in/out: mma=mma+mmb, mmb=mmb-mma */
#define SUMSUB_BA( a, b ) \
"paddw "#b", "#a" \n\t"\
"paddw "#b", "#b" \n\t"\
"psubw "#a", "#b" \n\t"
#define SBUTTERFLY(a,b,t,n,m)\
"mov" #m " " #a ", " #t " \n\t" /* abcd */\
"punpckl" #n " " #b ", " #a " \n\t" /* aebf */\
@ -95,90 +77,6 @@ extern const double ff_pd_2[2];
SBUTTERFLY(a,c,d,dq,q) /* a=aeim d=bfjn */\
SBUTTERFLY(t,b,c,dq,q) /* t=cgko c=dhlp */
static inline void transpose4x4(uint8_t *dst, uint8_t *src, x86_reg dst_stride, x86_reg src_stride){
__asm__ volatile( //FIXME could save 1 instruction if done as 8x4 ...
"movd (%1), %%mm0 \n\t"
"add %3, %1 \n\t"
"movd (%1), %%mm1 \n\t"
"movd (%1,%3,1), %%mm2 \n\t"
"movd (%1,%3,2), %%mm3 \n\t"
"punpcklbw %%mm1, %%mm0 \n\t"
"punpcklbw %%mm3, %%mm2 \n\t"
"movq %%mm0, %%mm1 \n\t"
"punpcklwd %%mm2, %%mm0 \n\t"
"punpckhwd %%mm2, %%mm1 \n\t"
"movd %%mm0, (%0) \n\t"
"add %2, %0 \n\t"
"punpckhdq %%mm0, %%mm0 \n\t"
"movd %%mm0, (%0) \n\t"
"movd %%mm1, (%0,%2,1) \n\t"
"punpckhdq %%mm1, %%mm1 \n\t"
"movd %%mm1, (%0,%2,2) \n\t"
: "+&r" (dst),
"+&r" (src)
: "r" (dst_stride),
"r" (src_stride)
: "memory"
);
}
// e,f,g,h can be memory
// out: a,d,t,c
#define TRANSPOSE8x4(a,b,c,d,e,f,g,h,t)\
"punpcklbw " #e ", " #a " \n\t" /* a0 e0 a1 e1 a2 e2 a3 e3 */\
"punpcklbw " #f ", " #b " \n\t" /* b0 f0 b1 f1 b2 f2 b3 f3 */\
"punpcklbw " #g ", " #c " \n\t" /* c0 g0 c1 g1 c2 g2 d3 g3 */\
"punpcklbw " #h ", " #d " \n\t" /* d0 h0 d1 h1 d2 h2 d3 h3 */\
SBUTTERFLY(a, b, t, bw, q) /* a= a0 b0 e0 f0 a1 b1 e1 f1 */\
/* t= a2 b2 e2 f2 a3 b3 e3 f3 */\
SBUTTERFLY(c, d, b, bw, q) /* c= c0 d0 g0 h0 c1 d1 g1 h1 */\
/* b= c2 d2 g2 h2 c3 d3 g3 h3 */\
SBUTTERFLY(a, c, d, wd, q) /* a= a0 b0 c0 d0 e0 f0 g0 h0 */\
/* d= a1 b1 c1 d1 e1 f1 g1 h1 */\
SBUTTERFLY(t, b, c, wd, q) /* t= a2 b2 c2 d2 e2 f2 g2 h2 */\
/* c= a3 b3 c3 d3 e3 f3 g3 h3 */
#if ARCH_X86_64
// permutes 01234567 -> 05736421
#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
SBUTTERFLY(a,b,%%xmm8,wd,dqa)\
SBUTTERFLY(c,d,b,wd,dqa)\
SBUTTERFLY(e,f,d,wd,dqa)\
SBUTTERFLY(g,h,f,wd,dqa)\
SBUTTERFLY(a,c,h,dq,dqa)\
SBUTTERFLY(%%xmm8,b,c,dq,dqa)\
SBUTTERFLY(e,g,b,dq,dqa)\
SBUTTERFLY(d,f,g,dq,dqa)\
SBUTTERFLY(a,e,f,qdq,dqa)\
SBUTTERFLY(%%xmm8,d,e,qdq,dqa)\
SBUTTERFLY(h,b,d,qdq,dqa)\
SBUTTERFLY(c,g,b,qdq,dqa)\
"movdqa %%xmm8, "#g" \n\t"
#else
#define TRANSPOSE8(a,b,c,d,e,f,g,h,t)\
"movdqa "#h", "#t" \n\t"\
SBUTTERFLY(a,b,h,wd,dqa)\
"movdqa "#h", 16"#t" \n\t"\
"movdqa "#t", "#h" \n\t"\
SBUTTERFLY(c,d,b,wd,dqa)\
SBUTTERFLY(e,f,d,wd,dqa)\
SBUTTERFLY(g,h,f,wd,dqa)\
SBUTTERFLY(a,c,h,dq,dqa)\
"movdqa "#h", "#t" \n\t"\
"movdqa 16"#t", "#h" \n\t"\
SBUTTERFLY(h,b,c,dq,dqa)\
SBUTTERFLY(e,g,b,dq,dqa)\
SBUTTERFLY(d,f,g,dq,dqa)\
SBUTTERFLY(a,e,f,qdq,dqa)\
SBUTTERFLY(h,d,e,qdq,dqa)\
"movdqa "#h", 16"#t" \n\t"\
"movdqa "#t", "#h" \n\t"\
SBUTTERFLY(h,b,d,qdq,dqa)\
SBUTTERFLY(c,g,b,qdq,dqa)\
"movdqa 16"#t", "#g" \n\t"
#endif
#define MOVQ_WONE(regd) \
__asm__ volatile ( \
"pcmpeqd %%" #regd ", %%" #regd " \n\t" \

View File

@ -362,7 +362,7 @@ void ff_h264dsp_init_x86(H264DSPContext *c, const int bit_depth, const int chrom
c->h264_idct_add8 = ff_h264_idct_add8_8_mmx;
c->h264_idct_add16intra = ff_h264_idct_add16intra_8_mmx;
if (mm_flags & AV_CPU_FLAG_CMOV)
c->h264_luma_dc_dequant_idct= ff_h264_luma_dc_dequant_idct_mmx;
c->h264_luma_dc_dequant_idct = ff_h264_luma_dc_dequant_idct_mmx;
if (mm_flags & AV_CPU_FLAG_MMX2) {
c->h264_idct_dc_add = ff_h264_idct_dc_add_8_mmx2;

View File

@ -59,8 +59,10 @@ OBJS-$(CONFIG_ASPLIT_FILTER) += split.o
OBJS-$(CONFIG_ASTREAMSYNC_FILTER) += af_astreamsync.o
OBJS-$(CONFIG_ASYNCTS_FILTER) += af_asyncts.o
OBJS-$(CONFIG_ATEMPO_FILTER) += af_atempo.o
OBJS-$(CONFIG_CHANNELMAP_FILTER) += af_channelmap.o
OBJS-$(CONFIG_CHANNELSPLIT_FILTER) += af_channelsplit.o
OBJS-$(CONFIG_EARWAX_FILTER) += af_earwax.o
OBJS-$(CONFIG_JOIN_FILTER) += af_join.o
OBJS-$(CONFIG_PAN_FILTER) += af_pan.o
OBJS-$(CONFIG_RESAMPLE_FILTER) += af_resample.o
OBJS-$(CONFIG_SILENCEDETECT_FILTER) += af_silencedetect.o

View File

@ -75,14 +75,14 @@ static int query_formats(AVFilterContext *ctx)
AVFilterLink *outlink = ctx->outputs[0];
AVFilterChannelLayouts *layouts;
ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
&inlink->out_formats);
if (aconvert->out_sample_fmt != AV_SAMPLE_FMT_NONE) {
formats = NULL;
ff_add_format(&formats, aconvert->out_sample_fmt);
ff_formats_ref(formats, &outlink->in_formats);
} else
ff_formats_ref(avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO),
ff_formats_ref(ff_all_formats(AVMEDIA_TYPE_AUDIO),
&outlink->in_formats);
ff_channel_layouts_ref(ff_all_channel_layouts(),

View File

@ -134,8 +134,7 @@ AVFilter avfilter_af_aformat = {
.priv_size = sizeof(AFormatContext),
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_samples = ff_null_filter_samples },
.type = AVMEDIA_TYPE_AUDIO, },
{ .name = NULL}},
.outputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO},

View File

@ -169,7 +169,7 @@ static int request_frame(AVFilterLink *outlink)
for (i = 0; i < am->nb_inputs; i++)
if (!am->in[i].nb_samples)
if ((ret = avfilter_request_frame(ctx->inputs[i])) < 0)
if ((ret = ff_request_frame(ctx->inputs[i])) < 0)
return ret;
return 0;
}

View File

@ -34,8 +34,7 @@ AVFilter avfilter_af_anull = {
.inputs = (const AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.get_audio_buffer = ff_null_get_audio_buffer,
.filter_samples = ff_null_filter_samples },
.get_audio_buffer = ff_null_get_audio_buffer, },
{ .name = NULL}},
.outputs = (const AVFilterPad[]) {{ .name = "default",

View File

@ -112,7 +112,7 @@ static int query_formats(AVFilterContext *ctx)
if(out_format != AV_SAMPLE_FMT_NONE) {
out_formats = ff_make_format_list((int[]){ out_format, -1 });
} else
out_formats = avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO);
out_formats = ff_all_formats(AVMEDIA_TYPE_AUDIO);
ff_formats_ref(out_formats, &outlink->in_formats);
if(out_layout) {
@ -211,7 +211,7 @@ static int request_frame(AVFilterLink *outlink)
aresample->req_fullfilled = 0;
do{
ret = avfilter_request_frame(ctx->inputs[0]);
ret = ff_request_frame(ctx->inputs[0]);
}while(!aresample->req_fullfilled && ret>=0);
if (ret == AVERROR_EOF) {

View File

@ -164,7 +164,7 @@ static int request_frame(AVFilterLink *outlink)
asns->req_fullfilled = 0;
do {
ret = avfilter_request_frame(inlink);
ret = ff_request_frame(inlink);
} while (!asns->req_fullfilled && ret >= 0);
if (ret == AVERROR_EOF)

View File

@ -157,7 +157,7 @@ static int request_frame(AVFilterLink *outlink)
send_next(ctx);
} else {
as->eof |= 1 << as->next_out;
avfilter_request_frame(ctx->inputs[as->next_out]);
ff_request_frame(ctx->inputs[as->next_out]);
if (as->eof & (1 << as->next_out))
as->next_out = !as->next_out;
}

View File

@ -1083,7 +1083,7 @@ static int request_frame(AVFilterLink *outlink)
atempo->request_fulfilled = 0;
do {
ret = avfilter_request_frame(ctx->inputs[0]);
ret = ff_request_frame(ctx->inputs[0]);
}
while (!atempo->request_fulfilled && ret >= 0);

402
libavfilter/af_channelmap.c Normal file
View File

@ -0,0 +1,402 @@
/*
* Copyright (c) 2012 Google, Inc.
*
* 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
*/
/**
* @file
* audio channel mapping filter
*/
#include <ctype.h>
#include "libavutil/audioconvert.h"
#include "libavutil/avstring.h"
#include "libavutil/mathematics.h"
#include "libavutil/opt.h"
#include "libavutil/samplefmt.h"
#include "audio.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
struct ChannelMap {
uint64_t in_channel;
uint64_t out_channel;
int in_channel_idx;
int out_channel_idx;
};
enum MappingMode {
MAP_NONE,
MAP_ONE_INT,
MAP_ONE_STR,
MAP_PAIR_INT_INT,
MAP_PAIR_INT_STR,
MAP_PAIR_STR_INT,
MAP_PAIR_STR_STR
};
#define MAX_CH 64
typedef struct ChannelMapContext {
const AVClass *class;
AVFilterChannelLayouts *channel_layouts;
char *mapping_str;
char *channel_layout_str;
uint64_t output_layout;
struct ChannelMap map[MAX_CH];
int nch;
enum MappingMode mode;
} ChannelMapContext;
#define OFFSET(x) offsetof(ChannelMapContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
static const AVOption options[] = {
{ "map", "A comma-separated list of input channel numbers in output order.",
OFFSET(mapping_str), AV_OPT_TYPE_STRING, .flags = A },
{ "channel_layout", "Output channel layout.",
OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, .flags = A },
{ NULL },
};
static const AVClass channelmap_class = {
.class_name = "channel map filter",
.item_name = av_default_item_name,
.option = options,
.version = LIBAVUTIL_VERSION_INT,
};
static char* split(char *message, char delim) {
char *next = strchr(message, delim);
if (next)
*next++ = '\0';
return next;
}
static int get_channel_idx(char **map, int *ch, char delim, int max_ch)
{
char *next = split(*map, delim);
int len;
int n = 0;
if (!next && delim == '-')
return AVERROR(EINVAL);
len = strlen(*map);
sscanf(*map, "%d%n", ch, &n);
if (n != len)
return AVERROR(EINVAL);
if (*ch < 0 || *ch > max_ch)
return AVERROR(EINVAL);
*map = next;
return 0;
}
static int get_channel(char **map, uint64_t *ch, char delim)
{
char *next = split(*map, delim);
if (!next && delim == '-')
return AVERROR(EINVAL);
*ch = av_get_channel_layout(*map);
if (av_get_channel_layout_nb_channels(*ch) != 1)
return AVERROR(EINVAL);
*map = next;
return 0;
}
static av_cold int channelmap_init(AVFilterContext *ctx, const char *args,
void *opaque)
{
ChannelMapContext *s = ctx->priv;
int ret;
char *mapping;
enum mode;
int map_entries = 0;
char buf[256];
enum MappingMode mode;
uint64_t out_ch_mask = 0;
int i;
if (!args) {
av_log(ctx, AV_LOG_ERROR, "No parameters supplied.\n");
return AVERROR(EINVAL);
}
s->class = &channelmap_class;
av_opt_set_defaults(s);
if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
return ret;
}
mapping = s->mapping_str;
if (!mapping) {
mode = MAP_NONE;
} else {
char *dash = strchr(mapping, '-');
if (!dash) { // short mapping
if (isdigit(*mapping))
mode = MAP_ONE_INT;
else
mode = MAP_ONE_STR;
} else if (isdigit(*mapping)) {
if (isdigit(*(dash+1)))
mode = MAP_PAIR_INT_INT;
else
mode = MAP_PAIR_INT_STR;
} else {
if (isdigit(*(dash+1)))
mode = MAP_PAIR_STR_INT;
else
mode = MAP_PAIR_STR_STR;
}
}
if (mode != MAP_NONE) {
char *comma = mapping;
map_entries = 1;
while ((comma = strchr(comma, ','))) {
if (*++comma) // Allow trailing comma
map_entries++;
}
}
if (map_entries > MAX_CH) {
av_log(ctx, AV_LOG_ERROR, "Too many channels mapped: '%d'.\n", map_entries);
ret = AVERROR(EINVAL);
goto fail;
}
for (i = 0; i < map_entries; i++) {
int in_ch_idx = -1, out_ch_idx = -1;
uint64_t in_ch = 0, out_ch = 0;
static const char err[] = "Failed to parse channel map\n";
switch (mode) {
case MAP_ONE_INT:
if (get_channel_idx(&mapping, &in_ch_idx, ',', MAX_CH) < 0) {
ret = AVERROR(EINVAL);
av_log(ctx, AV_LOG_ERROR, err);
goto fail;
}
s->map[i].in_channel_idx = in_ch_idx;
s->map[i].out_channel_idx = i;
break;
case MAP_ONE_STR:
if (!get_channel(&mapping, &in_ch, ',')) {
av_log(ctx, AV_LOG_ERROR, err);
ret = AVERROR(EINVAL);
goto fail;
}
s->map[i].in_channel = in_ch;
s->map[i].out_channel_idx = i;
break;
case MAP_PAIR_INT_INT:
if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
av_log(ctx, AV_LOG_ERROR, err);
ret = AVERROR(EINVAL);
goto fail;
}
s->map[i].in_channel_idx = in_ch_idx;
s->map[i].out_channel_idx = out_ch_idx;
break;
case MAP_PAIR_INT_STR:
if (get_channel_idx(&mapping, &in_ch_idx, '-', MAX_CH) < 0 ||
get_channel(&mapping, &out_ch, ',') < 0 ||
out_ch & out_ch_mask) {
av_log(ctx, AV_LOG_ERROR, err);
ret = AVERROR(EINVAL);
goto fail;
}
s->map[i].in_channel_idx = in_ch_idx;
s->map[i].out_channel = out_ch;
out_ch_mask |= out_ch;
break;
case MAP_PAIR_STR_INT:
if (get_channel(&mapping, &in_ch, '-') < 0 ||
get_channel_idx(&mapping, &out_ch_idx, ',', MAX_CH) < 0) {
av_log(ctx, AV_LOG_ERROR, err);
ret = AVERROR(EINVAL);
goto fail;
}
s->map[i].in_channel = in_ch;
s->map[i].out_channel_idx = out_ch_idx;
break;
case MAP_PAIR_STR_STR:
if (get_channel(&mapping, &in_ch, '-') < 0 ||
get_channel(&mapping, &out_ch, ',') < 0 ||
out_ch & out_ch_mask) {
av_log(ctx, AV_LOG_ERROR, err);
ret = AVERROR(EINVAL);
goto fail;
}
s->map[i].in_channel = in_ch;
s->map[i].out_channel = out_ch;
out_ch_mask |= out_ch;
break;
}
}
s->mode = mode;
s->nch = map_entries;
s->output_layout = out_ch_mask ? out_ch_mask :
av_get_default_channel_layout(map_entries);
if (s->channel_layout_str) {
uint64_t fmt;
if ((fmt = av_get_channel_layout(s->channel_layout_str)) == 0) {
av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout: '%s'.\n",
s->channel_layout_str);
ret = AVERROR(EINVAL);
goto fail;
}
if (mode == MAP_NONE) {
int i;
s->nch = av_get_channel_layout_nb_channels(fmt);
for (i = 0; i < s->nch; i++) {
s->map[i].in_channel_idx = i;
s->map[i].out_channel_idx = i;
}
} else if (out_ch_mask && out_ch_mask != fmt) {
av_get_channel_layout_string(buf, sizeof(buf), 0, out_ch_mask);
av_log(ctx, AV_LOG_ERROR,
"Output channel layout '%s' does not match the list of channel mapped: '%s'.\n",
s->channel_layout_str, buf);
ret = AVERROR(EINVAL);
goto fail;
} else if (s->nch != av_get_channel_layout_nb_channels(fmt)) {
av_log(ctx, AV_LOG_ERROR,
"Output channel layout %s does not match the number of channels mapped %d.\n",
s->channel_layout_str, s->nch);
ret = AVERROR(EINVAL);
goto fail;
}
s->output_layout = fmt;
}
ff_add_channel_layout(&s->channel_layouts, s->output_layout);
if (mode == MAP_PAIR_INT_STR || mode == MAP_PAIR_STR_STR) {
for (i = 0; i < s->nch; i++) {
s->map[i].out_channel_idx = av_get_channel_layout_channel_index(
s->output_layout, s->map[i].out_channel);
}
}
fail:
av_opt_free(s);
return ret;
}
static int channelmap_query_formats(AVFilterContext *ctx)
{
ChannelMapContext *s = ctx->priv;
ff_set_common_formats(ctx, ff_planar_sample_fmts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
ff_channel_layouts_ref(ff_all_channel_layouts(), &ctx->inputs[0]->out_channel_layouts);
ff_channel_layouts_ref(s->channel_layouts, &ctx->outputs[0]->in_channel_layouts);
return 0;
}
static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf)
{
AVFilterContext *ctx = inlink->dst;
AVFilterLink *outlink = ctx->outputs[0];
const ChannelMapContext *s = ctx->priv;
const int nch_in = av_get_channel_layout_nb_channels(inlink->channel_layout);
const int nch_out = s->nch;
int ch;
uint8_t *source_planes[MAX_CH];
memcpy(source_planes, buf->extended_data,
nch_in * sizeof(source_planes[0]));
if (nch_out > nch_in) {
if (nch_out > FF_ARRAY_ELEMS(buf->data)) {
uint8_t **new_extended_data =
av_mallocz(nch_out * sizeof(*buf->extended_data));
if (!new_extended_data)
return;
if (buf->extended_data == buf->data) {
buf->extended_data = new_extended_data;
} else {
buf->extended_data = new_extended_data;
av_free(buf->extended_data);
}
} else if (buf->extended_data != buf->data) {
av_free(buf->extended_data);
buf->extended_data = buf->data;
}
}
for (ch = 0; ch < nch_out; ch++) {
buf->extended_data[s->map[ch].out_channel_idx] =
source_planes[s->map[ch].in_channel_idx];
}
if (buf->data != buf->extended_data)
memcpy(buf->data, buf->extended_data,
FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0]));
ff_filter_samples(outlink, buf);
}
static int channelmap_config_input(AVFilterLink *inlink)
{
AVFilterContext *ctx = inlink->dst;
ChannelMapContext *s = ctx->priv;
int i, err = 0;
const char *channel_name;
char layout_name[256];
if (s->mode == MAP_PAIR_STR_INT || s->mode == MAP_PAIR_STR_STR) {
for (i = 0; i < s->nch; i++) {
s->map[i].in_channel_idx = av_get_channel_layout_channel_index(
inlink->channel_layout, s->map[i].in_channel);
if (s->map[i].in_channel_idx < 0) {
channel_name = av_get_channel_name(s->map[i].in_channel);
av_get_channel_layout_string(layout_name, sizeof(layout_name),
0, inlink->channel_layout);
av_log(ctx, AV_LOG_ERROR,
"input channel '%s' not available from input layout '%s'\n",
channel_name, layout_name);
err = AVERROR(EINVAL);
}
}
}
return err;
}
AVFilter avfilter_af_channelmap = {
.name = "channelmap",
.description = NULL_IF_CONFIG_SMALL("Remap audio channels."),
.init = channelmap_init,
.query_formats = channelmap_query_formats,
.priv_size = sizeof(ChannelMapContext),
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_samples = channelmap_filter_samples,
.config_props = channelmap_config_input },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO },
{ .name = NULL }},
};

500
libavfilter/af_join.c Normal file
View File

@ -0,0 +1,500 @@
/*
*
* This file is part of Libav.
*
* Libav 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.
*
* Libav 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 Libav; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
*/
/**
* @file
* Audio join filter
*
* Join multiple audio inputs as different channels in
* a single output
*/
#include "libavutil/audioconvert.h"
#include "libavutil/avassert.h"
#include "libavutil/opt.h"
#include "audio.h"
#include "avfilter.h"
#include "formats.h"
#include "internal.h"
typedef struct ChannelMap {
int input; ///< input stream index
int in_channel_idx; ///< index of in_channel in the input stream data
uint64_t in_channel; ///< layout describing the input channel
uint64_t out_channel; ///< layout describing the output channel
} ChannelMap;
typedef struct JoinContext {
const AVClass *class;
int inputs;
char *map;
char *channel_layout_str;
uint64_t channel_layout;
int nb_channels;
ChannelMap *channels;
/**
* Temporary storage for input frames, until we get one on each input.
*/
AVFilterBufferRef **input_frames;
/**
* Temporary storage for data pointers, for assembling the output buffer.
*/
uint8_t **data;
} JoinContext;
/**
* To avoid copying the data from input buffers, this filter creates
* a custom output buffer that stores references to all inputs and
* unrefs them on free.
*/
typedef struct JoinBufferPriv {
AVFilterBufferRef **in_buffers;
int nb_in_buffers;
} JoinBufferPriv;
#define OFFSET(x) offsetof(JoinContext, x)
#define A AV_OPT_FLAG_AUDIO_PARAM
static const AVOption join_options[] = {
{ "inputs", "Number of input streams.", OFFSET(inputs), AV_OPT_TYPE_INT, { 2 }, 1, INT_MAX, A },
{ "channel_layout", "Channel layout of the "
"output stream.", OFFSET(channel_layout_str), AV_OPT_TYPE_STRING, {.str = "stereo"}, 0, 0, A },
{ "map", "A comma-separated list of channels maps in the format "
"'input_stream.input_channel-output_channel.",
OFFSET(map), AV_OPT_TYPE_STRING, .flags = A },
{ NULL },
};
static const AVClass join_class = {
.class_name = "join filter",
.item_name = av_default_item_name,
.option = join_options,
.version = LIBAVUTIL_VERSION_INT,
};
static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
{
AVFilterContext *ctx = link->dst;
JoinContext *s = ctx->priv;
int i;
for (i = 0; i < ctx->nb_inputs; i++)
if (link == ctx->inputs[i])
break;
av_assert0(i < ctx->nb_inputs);
av_assert0(!s->input_frames[i]);
s->input_frames[i] = buf;
}
static int parse_maps(AVFilterContext *ctx)
{
JoinContext *s = ctx->priv;
char *cur = s->map;
while (cur && *cur) {
char *sep, *next, *p;
uint64_t in_channel = 0, out_channel = 0;
int input_idx, out_ch_idx, in_ch_idx;
next = strchr(cur, ',');
if (next)
*next++ = 0;
/* split the map into input and output parts */
if (!(sep = strchr(cur, '-'))) {
av_log(ctx, AV_LOG_ERROR, "Missing separator '-' in channel "
"map '%s'\n", cur);
return AVERROR(EINVAL);
}
*sep++ = 0;
#define PARSE_CHANNEL(str, var, inout) \
if (!(var = av_get_channel_layout(str))) { \
av_log(ctx, AV_LOG_ERROR, "Invalid " inout " channel: %s.\n", str);\
return AVERROR(EINVAL); \
} \
if (av_get_channel_layout_nb_channels(var) != 1) { \
av_log(ctx, AV_LOG_ERROR, "Channel map describes more than one " \
inout " channel.\n"); \
return AVERROR(EINVAL); \
}
/* parse output channel */
PARSE_CHANNEL(sep, out_channel, "output");
if (!(out_channel & s->channel_layout)) {
av_log(ctx, AV_LOG_ERROR, "Output channel '%s' is not present in "
"requested channel layout.\n", sep);
return AVERROR(EINVAL);
}
out_ch_idx = av_get_channel_layout_channel_index(s->channel_layout,
out_channel);
if (s->channels[out_ch_idx].input >= 0) {
av_log(ctx, AV_LOG_ERROR, "Multiple maps for output channel "
"'%s'.\n", sep);
return AVERROR(EINVAL);
}
/* parse input channel */
input_idx = strtol(cur, &cur, 0);
if (input_idx < 0 || input_idx >= s->inputs) {
av_log(ctx, AV_LOG_ERROR, "Invalid input stream index: %d.\n",
input_idx);
return AVERROR(EINVAL);
}
if (*cur)
cur++;
in_ch_idx = strtol(cur, &p, 0);
if (p == cur) {
/* channel specifier is not a number,
* try to parse as channel name */
PARSE_CHANNEL(cur, in_channel, "input");
}
s->channels[out_ch_idx].input = input_idx;
if (in_channel)
s->channels[out_ch_idx].in_channel = in_channel;
else
s->channels[out_ch_idx].in_channel_idx = in_ch_idx;
cur = next;
}
return 0;
}
static int join_init(AVFilterContext *ctx, const char *args, void *opaque)
{
JoinContext *s = ctx->priv;
int ret, i;
s->class = &join_class;
av_opt_set_defaults(s);
if ((ret = av_set_options_string(s, args, "=", ":")) < 0) {
av_log(ctx, AV_LOG_ERROR, "Error parsing options string '%s'.\n", args);
return ret;
}
if (!(s->channel_layout = av_get_channel_layout(s->channel_layout_str))) {
av_log(ctx, AV_LOG_ERROR, "Error parsing channel layout '%s'.\n",
s->channel_layout_str);
ret = AVERROR(EINVAL);
goto fail;
}
s->nb_channels = av_get_channel_layout_nb_channels(s->channel_layout);
s->channels = av_mallocz(sizeof(*s->channels) * s->nb_channels);
s->data = av_mallocz(sizeof(*s->data) * s->nb_channels);
s->input_frames = av_mallocz(sizeof(*s->input_frames) * s->inputs);
if (!s->channels || !s->data || !s->input_frames) {
ret = AVERROR(ENOMEM);
goto fail;
}
for (i = 0; i < s->nb_channels; i++) {
s->channels[i].out_channel = av_channel_layout_extract_channel(s->channel_layout, i);
s->channels[i].input = -1;
}
if ((ret = parse_maps(ctx)) < 0)
goto fail;
for (i = 0; i < s->inputs; i++) {
char name[32];
AVFilterPad pad = { 0 };
snprintf(name, sizeof(name), "input%d", i);
pad.type = AVMEDIA_TYPE_AUDIO;
pad.name = av_strdup(name);
pad.filter_samples = filter_samples;
pad.needs_fifo = 1;
ff_insert_inpad(ctx, i, &pad);
}
fail:
av_opt_free(s);
return ret;
}
static void join_uninit(AVFilterContext *ctx)
{
JoinContext *s = ctx->priv;
int i;
for (i = 0; i < ctx->nb_inputs; i++) {
av_freep(&ctx->input_pads[i].name);
avfilter_unref_buffer(s->input_frames[i]);
}
av_freep(&s->channels);
av_freep(&s->data);
av_freep(&s->input_frames);
}
static int join_query_formats(AVFilterContext *ctx)
{
JoinContext *s = ctx->priv;
AVFilterChannelLayouts *layouts = NULL;
int i;
ff_add_channel_layout(&layouts, s->channel_layout);
ff_channel_layouts_ref(layouts, &ctx->outputs[0]->in_channel_layouts);
for (i = 0; i < ctx->nb_inputs; i++)
ff_channel_layouts_ref(ff_all_channel_layouts(),
&ctx->inputs[i]->out_channel_layouts);
ff_set_common_formats (ctx, ff_planar_sample_fmts());
ff_set_common_samplerates(ctx, ff_all_samplerates());
return 0;
}
static void guess_map_matching(AVFilterContext *ctx, ChannelMap *ch,
uint64_t *inputs)
{
int i;
for (i = 0; i < ctx->nb_inputs; i++) {
AVFilterLink *link = ctx->inputs[i];
if (ch->out_channel & link->channel_layout &&
!(ch->out_channel & inputs[i])) {
ch->input = i;
ch->in_channel = ch->out_channel;
inputs[i] |= ch->out_channel;
return;
}
}
}
static void guess_map_any(AVFilterContext *ctx, ChannelMap *ch,
uint64_t *inputs)
{
int i;
for (i = 0; i < ctx->nb_inputs; i++) {
AVFilterLink *link = ctx->inputs[i];
if ((inputs[i] & link->channel_layout) != link->channel_layout) {
uint64_t unused = link->channel_layout & ~inputs[i];
ch->input = i;
ch->in_channel = av_channel_layout_extract_channel(unused, 0);
inputs[i] |= ch->in_channel;
return;
}
}
}
static int join_config_output(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
JoinContext *s = ctx->priv;
uint64_t *inputs; // nth element tracks which channels are used from nth input
int i, ret = 0;
/* initialize inputs to user-specified mappings */
if (!(inputs = av_mallocz(sizeof(*inputs) * ctx->nb_inputs)))
return AVERROR(ENOMEM);
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
AVFilterLink *inlink;
if (ch->input < 0)
continue;
inlink = ctx->inputs[ch->input];
if (!ch->in_channel)
ch->in_channel = av_channel_layout_extract_channel(inlink->channel_layout,
ch->in_channel_idx);
if (!(ch->in_channel & inlink->channel_layout)) {
av_log(ctx, AV_LOG_ERROR, "Requested channel %s is not present in "
"input stream #%d.\n", av_get_channel_name(ch->in_channel),
ch->input);
ret = AVERROR(EINVAL);
goto fail;
}
inputs[ch->input] |= ch->in_channel;
}
/* guess channel maps when not explicitly defined */
/* first try unused matching channels */
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
if (ch->input < 0)
guess_map_matching(ctx, ch, inputs);
}
/* if the above failed, try to find _any_ unused input channel */
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
if (ch->input < 0)
guess_map_any(ctx, ch, inputs);
if (ch->input < 0) {
av_log(ctx, AV_LOG_ERROR, "Could not find input channel for "
"output channel '%s'.\n",
av_get_channel_name(ch->out_channel));
goto fail;
}
ch->in_channel_idx = av_get_channel_layout_channel_index(ctx->inputs[ch->input]->channel_layout,
ch->in_channel);
}
/* print mappings */
av_log(ctx, AV_LOG_VERBOSE, "mappings: ");
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
av_log(ctx, AV_LOG_VERBOSE, "%d.%s => %s ", ch->input,
av_get_channel_name(ch->in_channel),
av_get_channel_name(ch->out_channel));
}
av_log(ctx, AV_LOG_VERBOSE, "\n");
for (i = 0; i < ctx->nb_inputs; i++) {
if (!inputs[i])
av_log(ctx, AV_LOG_WARNING, "No channels are used from input "
"stream %d.\n", i);
}
fail:
av_freep(&inputs);
return ret;
}
static void join_free_buffer(AVFilterBuffer *buf)
{
JoinBufferPriv *priv = buf->priv;
if (priv) {
int i;
for (i = 0; i < priv->nb_in_buffers; i++)
avfilter_unref_buffer(priv->in_buffers[i]);
av_freep(&priv->in_buffers);
av_freep(&buf->priv);
}
if (buf->extended_data != buf->data)
av_freep(&buf->extended_data);
av_freep(&buf);
}
static int join_request_frame(AVFilterLink *outlink)
{
AVFilterContext *ctx = outlink->src;
JoinContext *s = ctx->priv;
AVFilterBufferRef *buf;
JoinBufferPriv *priv;
int linesize = INT_MAX;
int perms = ~0;
int nb_samples;
int i, j, ret;
/* get a frame on each input */
for (i = 0; i < ctx->nb_inputs; i++) {
AVFilterLink *inlink = ctx->inputs[i];
if (!s->input_frames[i] &&
(ret = ff_request_frame(inlink)) < 0)
return ret;
/* request the same number of samples on all inputs */
if (i == 0) {
nb_samples = s->input_frames[0]->audio->nb_samples;
for (j = 1; !i && j < ctx->nb_inputs; j++)
ctx->inputs[j]->request_samples = nb_samples;
}
}
for (i = 0; i < s->nb_channels; i++) {
ChannelMap *ch = &s->channels[i];
AVFilterBufferRef *cur_buf = s->input_frames[ch->input];
s->data[i] = cur_buf->extended_data[ch->in_channel_idx];
linesize = FFMIN(linesize, cur_buf->linesize[0]);
perms &= cur_buf->perms;
}
buf = avfilter_get_audio_buffer_ref_from_arrays(s->data, linesize, perms,
nb_samples, outlink->format,
outlink->channel_layout);
if (!buf)
return AVERROR(ENOMEM);
buf->buf->free = join_free_buffer;
buf->pts = s->input_frames[0]->pts;
if (!(priv = av_mallocz(sizeof(*priv))))
goto fail;
if (!(priv->in_buffers = av_mallocz(sizeof(*priv->in_buffers) * ctx->nb_inputs)))
goto fail;
for (i = 0; i < ctx->nb_inputs; i++)
priv->in_buffers[i] = s->input_frames[i];
priv->nb_in_buffers = ctx->nb_inputs;
buf->buf->priv = priv;
ff_filter_samples(outlink, buf);
memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs);
return 0;
fail:
avfilter_unref_buffer(buf);
if (priv)
av_freep(&priv->in_buffers);
av_freep(&priv);
return AVERROR(ENOMEM);
}
AVFilter avfilter_af_join = {
.name = "join",
.description = NULL_IF_CONFIG_SMALL("Join multiple audio streams into "
"multi-channel output"),
.priv_size = sizeof(JoinContext),
.init = join_init,
.uninit = join_uninit,
.query_formats = join_query_formats,
.inputs = (const AVFilterPad[]){{ NULL }},
.outputs = (const AVFilterPad[]){{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.config_props = join_config_output,
.request_frame = join_request_frame, },
{ NULL }},
};

View File

@ -217,7 +217,7 @@ static int query_formats(AVFilterContext *ctx)
pan->pure_gains = are_gains_pure(pan);
/* libswr supports any sample and packing formats */
ff_set_common_formats(ctx, avfilter_make_all_formats(AVMEDIA_TYPE_AUDIO));
ff_set_common_formats(ctx, ff_all_formats(AVMEDIA_TYPE_AUDIO));
formats = ff_all_samplerates();
if (!formats)

View File

@ -47,8 +47,10 @@ void avfilter_register_all(void)
REGISTER_FILTER (ASTREAMSYNC, astreamsync, af);
REGISTER_FILTER (ASYNCTS, asyncts, af);
REGISTER_FILTER (ATEMPO, atempo, af);
REGISTER_FILTER (CHANNELMAP, channelmap, af);
REGISTER_FILTER (CHANNELSPLIT,channelsplit,af);
REGISTER_FILTER (EARWAX, earwax, af);
REGISTER_FILTER (JOIN, join, af);
REGISTER_FILTER (PAN, pan, af);
REGISTER_FILTER (SILENCEDETECT, silencedetect, af);
REGISTER_FILTER (VOLUME, volume, af);

View File

@ -150,32 +150,12 @@ fail:
return NULL;
}
void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
static void default_filter_samples(AVFilterLink *link,
AVFilterBufferRef *samplesref)
{
ff_filter_samples(link->dst->outputs[0], samplesref);
}
/* FIXME: samplesref is same as link->cur_buf. Need to consider removing the redundant parameter. */
void ff_default_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref)
{
AVFilterLink *outlink = NULL;
if (inlink->dst->nb_outputs)
outlink = inlink->dst->outputs[0];
if (outlink) {
outlink->out_buf = ff_default_get_audio_buffer(inlink, AV_PERM_WRITE,
samplesref->audio->nb_samples);
outlink->out_buf->pts = samplesref->pts;
outlink->out_buf->audio->sample_rate = samplesref->audio->sample_rate;
ff_filter_samples(outlink, avfilter_ref_buffer(outlink->out_buf, ~0));
avfilter_unref_buffer(outlink->out_buf);
outlink->out_buf = NULL;
}
avfilter_unref_buffer(samplesref);
inlink->cur_buf = NULL;
}
void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
{
void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *);
@ -186,7 +166,7 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref)
FF_TPRINTF_START(NULL, filter_samples); ff_tlog_link(NULL, link, 1);
if (!(filter_samples = dst->filter_samples))
filter_samples = ff_default_filter_samples;
filter_samples = default_filter_samples;
/* prepare to copy the samples if the buffer has insufficient permissions */
if ((dst->min_perms & samplesref->perms) != dst->min_perms ||

View File

@ -63,12 +63,6 @@ AVFilterBufferRef *ff_null_get_audio_buffer(AVFilterLink *link, int perms,
AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms,
int nb_samples);
/** default handler for filter_samples() for audio inputs */
void ff_default_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
/** filter_samples() handler for filters which simply pass audio along */
void ff_null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref);
/**
* Send a buffer of audio samples to the next filter.
*

View File

@ -170,7 +170,7 @@ static int request_frame(AVFilterLink *outlink)
showwaves->req_fullfilled = 0;
do {
ret = avfilter_request_frame(inlink);
ret = ff_request_frame(inlink);
} while (!showwaves->req_fullfilled && ret >= 0);
if (ret == AVERROR_EOF && showwaves->outpicref)

View File

@ -211,7 +211,6 @@ AVFilterBufferRef *avfilter_ref_buffer(AVFilterBufferRef *ref, int pmask);
*/
void avfilter_unref_buffer(AVFilterBufferRef *ref);
#if FF_API_FILTERS_PUBLIC
/**
* Remove a reference to a buffer and set the pointer to NULL.
* If this is the last reference to the buffer, the buffer itself
@ -221,6 +220,7 @@ void avfilter_unref_buffer(AVFilterBufferRef *ref);
*/
void avfilter_unref_bufferp(AVFilterBufferRef **ref);
#if FF_API_FILTERS_PUBLIC
/**
* A list of supported formats for one end of a filter link. This is used
* during the format negotiation process to try to pick the best format to
@ -291,7 +291,7 @@ AVFilterFormats *avfilter_make_format_list(const int *fmts);
*
* @return a non negative value in case of success, or a negative
* value corresponding to an AVERROR code in case of error
* @deprecated Use avfilter_make_all_formats() instead.
* @deprecated Use ff_all_formats() instead.
*/
attribute_deprecated
int avfilter_add_format(AVFilterFormats **avff, int64_t fmt);
@ -479,7 +479,7 @@ struct AVFilterPad {
* Frame request callback. A call to this should result in at least one
* frame being output over the given link. This should return zero on
* success, and another value on error.
* See avfilter_request_frame() for the error codes with a specific
* See ff_request_frame() for the error codes with a specific
* meaning.
*
* Output pads only.
@ -504,6 +504,14 @@ struct AVFilterPad {
* and another value on error.
*/
int (*config_props)(AVFilterLink *link);
/**
* The filter expects a fifo to be inserted on its input link,
* typically because it has a delay.
*
* input pads only.
*/
int needs_fifo;
};
#endif
@ -529,6 +537,10 @@ const char *avfilter_pad_get_name(AVFilterPad *pads, int pad_idx);
*/
enum AVMediaType avfilter_pad_get_type(AVFilterPad *pads, int pad_idx);
/** default handler for end_frame() for video inputs */
attribute_deprecated
void avfilter_default_end_frame(AVFilterLink *link);
#if FF_API_FILTERS_PUBLIC
/** default handler for start_frame() for video inputs */
attribute_deprecated
@ -538,10 +550,6 @@ void avfilter_default_start_frame(AVFilterLink *link, AVFilterBufferRef *picref)
attribute_deprecated
void avfilter_default_draw_slice(AVFilterLink *link, int y, int h, int slice_dir);
/** default handler for end_frame() for video inputs */
attribute_deprecated
void avfilter_default_end_frame(AVFilterLink *link);
/** default handler for get_video_buffer() for video inputs */
attribute_deprecated
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link,
@ -756,6 +764,15 @@ struct AVFilterLink {
struct AVFilterChannelLayouts *in_channel_layouts;
struct AVFilterChannelLayouts *out_channel_layouts;
/**
* Audio only, the destination filter sets this to a non-zero value to
* request that buffers with the given number of samples should be sent to
* it. AVFilterPad.needs_fifo must also be set on the corresponding input
* pad.
* Last buffer before EOF will be padded with silence.
*/
int request_samples;
struct AVFilterPool *pool;
/**
@ -785,7 +802,6 @@ struct AVFilterLink {
* It is similar to the r_frae_rate field in AVStream.
*/
AVRational frame_rate;
};
/**

View File

@ -187,7 +187,7 @@ static int filter_query_formats(AVFilterContext *ctx)
if ((ret = ctx->filter->query_formats(ctx)) < 0)
return ret;
formats = avfilter_make_all_formats(type);
formats = ff_all_formats(type);
if (!formats)
return AVERROR(ENOMEM);
ff_set_common_formats(ctx, formats);
@ -815,12 +815,52 @@ static int ff_avfilter_graph_config_pointers(AVFilterGraph *graph,
return 0;
}
static int graph_insert_fifos(AVFilterGraph *graph, AVClass *log_ctx)
{
AVFilterContext *f;
int i, j, ret;
int fifo_count = 0;
for (i = 0; i < graph->filter_count; i++) {
f = graph->filters[i];
for (j = 0; j < f->nb_inputs; j++) {
AVFilterLink *link = f->inputs[j];
AVFilterContext *fifo_ctx;
AVFilter *fifo;
char name[32];
if (!link->dstpad->needs_fifo)
continue;
fifo = f->inputs[j]->type == AVMEDIA_TYPE_VIDEO ?
avfilter_get_by_name("fifo") :
avfilter_get_by_name("afifo");
snprintf(name, sizeof(name), "auto-inserted fifo %d", fifo_count++);
ret = avfilter_graph_create_filter(&fifo_ctx, fifo, name, NULL,
NULL, graph);
if (ret < 0)
return ret;
ret = avfilter_insert_filter(link, fifo_ctx, 0, 0);
if (ret < 0)
return ret;
}
}
return 0;
}
int avfilter_graph_config(AVFilterGraph *graphctx, void *log_ctx)
{
int ret;
if ((ret = graph_check_validity(graphctx, log_ctx)))
return ret;
if ((ret = graph_insert_fifos(graphctx, log_ctx)) < 0)
return ret;
if ((ret = graph_config_formats(graphctx, log_ctx)))
return ret;
if ((ret = graph_config_links(graphctx, log_ctx)))
@ -939,7 +979,7 @@ int avfilter_graph_request_oldest(AVFilterGraph *graph)
{
while (graph->sink_links_count) {
AVFilterLink *oldest = graph->sink_links[0];
int r = avfilter_request_frame(oldest);
int r = ff_request_frame(oldest);
if (r != AVERROR_EOF)
return r;
/* EOF: remove the link from the heap */

View File

@ -257,7 +257,7 @@ char *avfilter_graph_dump(AVFilterGraph *graph, const char *options);
* of a filtergraph, only a convenience function to help drain a filtergraph
* in a balanced way under normal circumstances.
*
* @return the return value of avfilter_request_frame,
* @return the return value of ff_request_frame,
* or AVERROR_EOF of all links returned AVERROR_EOF.
*/
int avfilter_graph_request_oldest(AVFilterGraph *graph);

View File

@ -25,7 +25,7 @@
#include "libavutil/audio_fifo.h"
#include "libavutil/audioconvert.h"
#include "libavutil/fifo.h"
#include "libavutil/avassert.h"
#include "libavutil/mathematics.h"
#include "audio.h"
@ -34,86 +34,45 @@
#include "internal.h"
typedef struct {
AVFifoBuffer *fifo; ///< FIFO buffer of frame references
AVFilterBufferRef *cur_buf; ///< last buffer delivered on the sink
AVAudioFifo *audio_fifo; ///< FIFO for audio samples
int64_t next_pts; ///< interpolating audio pts
} BufferSinkContext;
#define FIFO_INIT_SIZE 8
static av_cold void uninit(AVFilterContext *ctx)
{
BufferSinkContext *sink = ctx->priv;
while (sink->fifo && av_fifo_size(sink->fifo)) {
AVFilterBufferRef *buf;
av_fifo_generic_read(sink->fifo, &buf, sizeof(buf), NULL);
avfilter_unref_buffer(buf);
}
av_fifo_free(sink->fifo);
if (sink->audio_fifo)
av_audio_fifo_free(sink->audio_fifo);
}
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf)
{
BufferSinkContext *sink = ctx->priv;
BufferSinkContext *s = link->dst->priv;
if (!(sink->fifo = av_fifo_alloc(FIFO_INIT_SIZE*sizeof(AVFilterBufferRef*)))) {
av_log(ctx, AV_LOG_ERROR, "Failed to allocate fifo\n");
return AVERROR(ENOMEM);
}
return 0;
}
static void write_buf(AVFilterContext *ctx, AVFilterBufferRef *buf)
{
BufferSinkContext *sink = ctx->priv;
if (av_fifo_space(sink->fifo) < sizeof(AVFilterBufferRef *) &&
(av_fifo_realloc2(sink->fifo, av_fifo_size(sink->fifo) * 2) < 0)) {
av_log(ctx, AV_LOG_ERROR, "Error reallocating the FIFO.\n");
return;
}
av_fifo_generic_write(sink->fifo, &buf, sizeof(buf), NULL);
}
static void end_frame(AVFilterLink *link)
{
write_buf(link->dst, link->cur_buf);
// av_assert0(!s->cur_buf);
s->cur_buf = buf;
link->cur_buf = NULL;
}
static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf)
{
write_buf(link->dst, buf);
}
};
int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf)
{
BufferSinkContext *sink = ctx->priv;
BufferSinkContext *s = ctx->priv;
AVFilterLink *link = ctx->inputs[0];
int ret;
if (!buf) {
if (av_fifo_size(sink->fifo))
return av_fifo_size(sink->fifo)/sizeof(*buf);
else
return ff_poll_frame(ctx->inputs[0]);
}
if (!buf)
return ff_poll_frame(ctx->inputs[0]);
if (!av_fifo_size(sink->fifo) &&
(ret = ff_request_frame(link)) < 0)
if ((ret = ff_request_frame(link)) < 0)
return ret;
if (!av_fifo_size(sink->fifo))
if (!s->cur_buf)
return AVERROR(EINVAL);
av_fifo_generic_read(sink->fifo, buf, sizeof(*buf), NULL);
*buf = s->cur_buf;
s->cur_buf = NULL;
return 0;
}
@ -182,13 +141,13 @@ AVFilter avfilter_vsink_buffer = {
.name = "buffersink_old",
.description = NULL_IF_CONFIG_SMALL("Buffer video frames, and make them available to the end of the filter graph."),
.priv_size = sizeof(BufferSinkContext),
.init = init,
.uninit = uninit,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_VIDEO,
.end_frame = end_frame,
.min_perms = AV_PERM_READ, },
.start_frame = start_frame,
.min_perms = AV_PERM_READ,
.needs_fifo = 1 },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};
@ -197,13 +156,13 @@ AVFilter avfilter_asink_abuffer = {
.name = "abuffersink_old",
.description = NULL_IF_CONFIG_SMALL("Buffer audio frames, and make them available to the end of the filter graph."),
.priv_size = sizeof(BufferSinkContext),
.init = init,
.uninit = uninit,
.inputs = (AVFilterPad[]) {{ .name = "default",
.type = AVMEDIA_TYPE_AUDIO,
.filter_samples = filter_samples,
.min_perms = AV_PERM_READ, },
.filter_samples = start_frame,
.min_perms = AV_PERM_READ,
.needs_fifo = 1 },
{ .name = NULL }},
.outputs = (AVFilterPad[]) {{ .name = NULL }},
};

View File

@ -47,27 +47,6 @@ static void set_common_formats(AVFilterContext *ctx, AVFilterFormats *fmts,
}
}
void avfilter_set_common_pixel_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{
set_common_formats(ctx, formats, AVMEDIA_TYPE_VIDEO,
offsetof(AVFilterLink, in_formats),
offsetof(AVFilterLink, out_formats));
}
void avfilter_set_common_sample_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{
set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
offsetof(AVFilterLink, in_formats),
offsetof(AVFilterLink, out_formats));
}
void avfilter_set_common_channel_layouts(AVFilterContext *ctx, AVFilterFormats *formats)
{
set_common_formats(ctx, formats, AVMEDIA_TYPE_AUDIO,
offsetof(AVFilterLink, in_channel_layouts),
offsetof(AVFilterLink, out_channel_layouts));
}
#if FF_API_PACKING
void avfilter_set_common_packing_formats(AVFilterContext *ctx, AVFilterFormats *formats)
{

View File

@ -23,6 +23,11 @@
* FIFO buffering filter
*/
#include "libavutil/avassert.h"
#include "libavutil/audioconvert.h"
#include "libavutil/mathematics.h"
#include "libavutil/samplefmt.h"
#include "audio.h"
#include "avfilter.h"
#include "internal.h"
@ -36,6 +41,13 @@ typedef struct Buf {
typedef struct {
Buf root;
Buf *last; ///< last buffered frame
/**
* When a specific number of output samples is requested, the partial
* buffer is stored here
*/
AVFilterBufferRef *buf_out;
int allocated_samples; ///< number of samples buf_out was allocated for
} FifoContext;
static av_cold int init(AVFilterContext *ctx, const char *args, void *opaque)
@ -57,6 +69,8 @@ static av_cold void uninit(AVFilterContext *ctx)
avfilter_unref_buffer(buf->buf);
av_free(buf);
}
avfilter_unref_buffer(fifo->buf_out);
}
static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
@ -68,14 +82,143 @@ static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf)
fifo->last->buf = buf;
}
static void queue_pop(FifoContext *s)
{
Buf *tmp = s->root.next->next;
if (s->last == s->root.next)
s->last = &s->root;
av_freep(&s->root.next);
s->root.next = tmp;
}
static void end_frame(AVFilterLink *inlink) { }
static void draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir) { }
/**
* Move data pointers and pts offset samples forward.
*/
static void buffer_offset(AVFilterLink *link, AVFilterBufferRef *buf,
int offset)
{
int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
int planar = av_sample_fmt_is_planar(link->format);
int planes = planar ? nb_channels : 1;
int block_align = av_get_bytes_per_sample(link->format) * (planar ? 1 : nb_channels);
int i;
av_assert0(buf->audio->nb_samples > offset);
for (i = 0; i < planes; i++)
buf->extended_data[i] += block_align*offset;
if (buf->data != buf->extended_data)
memcpy(buf->data, buf->extended_data,
FFMIN(planes, FF_ARRAY_ELEMS(buf->data)) * sizeof(*buf->data));
buf->linesize[0] -= block_align*offset;
buf->audio->nb_samples -= offset;
if (buf->pts != AV_NOPTS_VALUE) {
buf->pts += av_rescale_q(offset, (AVRational){1, link->sample_rate},
link->time_base);
}
}
static int calc_ptr_alignment(AVFilterBufferRef *buf)
{
int planes = av_sample_fmt_is_planar(buf->format) ?
av_get_channel_layout_nb_channels(buf->audio->channel_layout) : 1;
int min_align = 128;
int p;
for (p = 0; p < planes; p++) {
int cur_align = 128;
while ((intptr_t)buf->extended_data[p] % cur_align)
cur_align >>= 1;
if (cur_align < min_align)
min_align = cur_align;
}
return min_align;
}
static int return_audio_frame(AVFilterContext *ctx)
{
AVFilterLink *link = ctx->outputs[0];
FifoContext *s = ctx->priv;
AVFilterBufferRef *head = s->root.next->buf;
AVFilterBufferRef *buf_out;
int ret;
if (!s->buf_out &&
head->audio->nb_samples >= link->request_samples &&
calc_ptr_alignment(head) >= 32) {
if (head->audio->nb_samples == link->request_samples) {
buf_out = head;
queue_pop(s);
} else {
buf_out = avfilter_ref_buffer(head, AV_PERM_READ);
buf_out->audio->nb_samples = link->request_samples;
buffer_offset(link, head, link->request_samples);
}
} else {
int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout);
if (!s->buf_out) {
s->buf_out = ff_get_audio_buffer(link, AV_PERM_WRITE,
link->request_samples);
if (!s->buf_out)
return AVERROR(ENOMEM);
s->buf_out->audio->nb_samples = 0;
s->buf_out->pts = head->pts;
s->allocated_samples = link->request_samples;
} else if (link->request_samples != s->allocated_samples) {
av_log(ctx, AV_LOG_ERROR, "request_samples changed before the "
"buffer was returned.\n");
return AVERROR(EINVAL);
}
while (s->buf_out->audio->nb_samples < s->allocated_samples) {
int len = FFMIN(s->allocated_samples - s->buf_out->audio->nb_samples,
head->audio->nb_samples);
av_samples_copy(s->buf_out->extended_data, head->extended_data,
s->buf_out->audio->nb_samples, 0, len, nb_channels,
link->format);
s->buf_out->audio->nb_samples += len;
if (len == head->audio->nb_samples) {
avfilter_unref_buffer(head);
queue_pop(s);
if (!s->root.next &&
(ret = ff_request_frame(ctx->inputs[0])) < 0) {
if (ret == AVERROR_EOF) {
av_samples_set_silence(s->buf_out->extended_data,
s->buf_out->audio->nb_samples,
s->allocated_samples -
s->buf_out->audio->nb_samples,
nb_channels, link->format);
s->buf_out->audio->nb_samples = s->allocated_samples;
break;
}
return ret;
}
head = s->root.next->buf;
} else {
buffer_offset(link, head, len);
}
}
buf_out = s->buf_out;
s->buf_out = NULL;
}
ff_filter_samples(link, buf_out);
return 0;
}
static int request_frame(AVFilterLink *outlink)
{
FifoContext *fifo = outlink->src->priv;
Buf *tmp;
int ret;
if (!fifo->root.next) {
@ -90,20 +233,20 @@ static int request_frame(AVFilterLink *outlink)
ff_start_frame(outlink, fifo->root.next->buf);
ff_draw_slice (outlink, 0, outlink->h, 1);
ff_end_frame (outlink);
queue_pop(fifo);
break;
case AVMEDIA_TYPE_AUDIO:
ff_filter_samples(outlink, fifo->root.next->buf);
if (outlink->request_samples) {
return return_audio_frame(outlink->src);
} else {
ff_filter_samples(outlink, fifo->root.next->buf);
queue_pop(fifo);
}
break;
default:
return AVERROR(EINVAL);
}
if (fifo->last == fifo->root.next)
fifo->last = &fifo->root;
tmp = fifo->root.next->next;
av_free(fifo->root.next);
fifo->root.next = tmp;
return 0;
}

View File

@ -261,11 +261,6 @@ int ff_add_channel_layout(AVFilterChannelLayouts **l, uint64_t channel_layout)
}
AVFilterFormats *ff_all_formats(enum AVMediaType type)
{
return avfilter_make_all_formats(type);
}
AVFilterFormats *avfilter_make_all_formats(enum AVMediaType type)
{
AVFilterFormats *ret = NULL;
int fmt;

View File

@ -173,6 +173,14 @@ struct AVFilterPad {
* and another value on error.
*/
int (*config_props)(AVFilterLink *link);
/**
* The filter expects a fifo to be inserted on its input link,
* typically because it has a delay.
*
* input pads only.
*/
int needs_fifo;
};
#endif

View File

@ -94,7 +94,7 @@ static const uint8_t offset[511][2]= {
{ 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 7, 3}, {15, 3}, { 7,11}, {15,11},
{ 7, 5}, {15, 5}, { 7,13}, {15,13}, { 7, 7}, {15, 7}, { 7,15}, {15,15},
{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11, 1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, { 9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
{ 0, 0}, { 8, 0}, { 0, 8}, { 8, 8}, { 4, 4}, {12, 4}, { 4,12}, {12,12}, { 0, 4}, { 8, 4}, { 0,12}, { 8,12}, { 4, 0}, {12, 0}, { 4, 8}, {12, 8}, { 2, 2}, {10, 2}, { 2,10}, {10,10}, { 6, 6}, {14, 6}, { 6,14}, {14,14}, { 2, 6}, {10, 6}, { 2,14}, {10,14}, { 6, 2}, {14, 2}, { 6,10}, {14,10}, { 0, 2}, { 8, 2}, { 0,10}, { 8,10}, { 4, 6}, {12, 6}, { 4,14}, {12,14}, { 0, 6}, { 8, 6}, { 0,14}, { 8,14}, { 4, 2}, {12, 2}, { 4,10}, {12,10}, { 2, 0}, {10, 0}, { 2, 8}, {10, 8}, { 6, 4}, {14, 4}, { 6,12}, {14,12}, { 2, 4}, {10, 4}, { 2,12}, {10,12}, { 6, 0}, {14, 0}, { 6, 8}, {14, 8}, { 1, 1}, { 9, 1}, { 1, 9}, { 9, 9}, { 5, 5}, {13, 5}, { 5,13}, {13,13}, { 1, 5}, { 9, 5}, { 1,13}, { 9,13}, { 5, 1}, {13, 1}, { 5, 9}, {13, 9}, { 3, 3}, {11, 3}, { 3,11}, {11,11}, { 7, 7}, {15, 7}, { 7,15}, {15,15}, { 3, 7}, {11, 7}, { 3,15}, {11,15}, { 7, 3}, {15, 3}, { 7,11}, {15,11}, { 1, 3}, { 9, 3}, { 1,11}, { 9,11}, { 5, 7}, {13, 7}, { 5,15}, {13,15}, { 1, 7}, { 9, 7}, { 1,15}, { 9,15}, { 5, 3}, {13, 3}, { 5,11}, {13,11}, { 3, 1}, {11,1}, { 3, 9}, {11, 9}, { 7, 5}, {15, 5}, { 7,13}, {15,13}, { 3, 5}, {11, 5}, { 3,13}, {11,13}, { 7, 1}, {15, 1}, { 7, 9}, {15, 9}, { 0, 1}, { 8, 1}, { 0, 9}, { 8, 9}, { 4, 5}, {12, 5}, { 4,13}, {12,13}, { 0, 5}, { 8, 5}, { 0,13}, { 8,13}, { 4, 1}, {12, 1}, { 4, 9}, {12, 9}, { 2, 3}, {10, 3}, { 2,11}, {10,11}, { 6, 7}, {14, 7}, { 6,15}, {14,15}, { 2, 7}, {10, 7}, { 2,15}, {10,15}, { 6, 3}, {14, 3}, { 6,11}, {14,11}, { 0, 3}, { 8, 3}, { 0,11}, { 8,11}, { 4, 7}, {12, 7}, { 4,15}, {12,15}, { 0, 7}, { 8, 7}, { 0,15}, { 8,15}, { 4, 3}, {12, 3}, { 4,11}, {12,11}, { 2, 1}, {10, 1}, { 2, 9}, {10, 9}, { 6, 5}, {14, 5}, { 6,13}, {14,13}, { 2, 5}, {10, 5}, { 2,13}, {10,13}, { 6, 1}, {14, 1}, { 6, 9}, {14, 9}, { 1, 0}, { 9, 0}, { 1, 8}, { 9, 8}, { 5, 4}, {13, 4}, { 5,12}, {13,12}, { 1, 4}, { 9, 4}, { 1,12}, { 9,12}, { 5, 0}, {13, 0}, { 5, 8}, {13, 8}, { 3, 2}, {11, 2}, { 3,10}, {11,10}, { 7, 6}, {15, 6}, { 7,14}, {15,14}, { 3, 6}, {11, 6}, { 3,14}, {11,14}, { 7, 2}, {15, 2}, { 7,10}, {15,10}, { 1, 2}, { 9, 2}, { 1,10}, {9,10}, { 5, 6}, {13, 6}, { 5,14}, {13,14}, { 1, 6}, { 9, 6}, { 1,14}, { 9,14}, { 5, 2}, {13, 2}, { 5,10}, {13,10}, { 3, 0}, {11, 0}, { 3, 8}, {11, 8}, { 7, 4}, {15, 4}, { 7,12}, {15,12}, { 3, 4}, {11, 4}, { 3,12}, {11,12}, { 7, 0}, {15, 0}, { 7, 8}, {15, 8},
};
struct vf_priv_s {

View File

@ -127,7 +127,7 @@ int av_buffersink_get_buffer_ref(AVFilterContext *ctx,
if (!av_fifo_size(buf->fifo)) {
if (flags & AV_BUFFERSINK_FLAG_NO_REQUEST)
return AVERROR(EAGAIN);
if ((ret = avfilter_request_frame(inlink)) < 0)
if ((ret = ff_request_frame(inlink)) < 0)
return ret;
}

View File

@ -28,8 +28,8 @@
#include "libavutil/avutil.h"
#define LIBAVFILTER_VERSION_MAJOR 2
#define LIBAVFILTER_VERSION_MINOR 82
#define LIBAVFILTER_VERSION_MAJOR 3
#define LIBAVFILTER_VERSION_MINOR 0
#define LIBAVFILTER_VERSION_MICRO 100
#define LIBAVFILTER_VERSION_INT AV_VERSION_INT(LIBAVFILTER_VERSION_MAJOR, \

View File

@ -136,7 +136,7 @@ static int request_frame(AVFilterLink *outlink)
AVFilterContext *ctx = outlink->src;
BlackDetectContext *blackdetect = ctx->priv;
AVFilterLink *inlink = ctx->inputs[0];
int ret = avfilter_request_frame(inlink);
int ret = ff_request_frame(inlink);
if (ret == AVERROR_EOF && blackdetect->black_started) {
// FIXME: black_end should be set to last_picref_pts + last_picref_duration

View File

@ -216,7 +216,7 @@ static int request_frame(AVFilterLink *link)
do {
int ret;
if ((ret = avfilter_request_frame(link->src->inputs[0])))
if ((ret = ff_request_frame(link->src->inputs[0])))
return ret;
} while (!idet->cur);
@ -231,7 +231,7 @@ static int poll_frame(AVFilterLink *link)
val = ff_poll_frame(link->src->inputs[0]);
if (val >= 1 && !idet->next) { //FIXME change API to not requre this red tape
if ((ret = avfilter_request_frame(link->src->inputs[0])) < 0)
if ((ret = ff_request_frame(link->src->inputs[0])) < 0)
return ret;
val = ff_poll_frame(link->src->inputs[0]);
}

View File

@ -25,6 +25,9 @@
*/
#include "avfilter.h"
#include "video.h"
#include "formats.h"
#include "internal.h"
#include "libavutil/avassert.h"
#include "libavutil/pixdesc.h"
#include "libavutil/intreadwrite.h"
@ -633,9 +636,9 @@ int vf_next_put_image(struct vf_instance *vf,mp_image_t *mpi, double pts){
if(pts != MP_NOPTS_VALUE)
picref->pts= pts * av_q2d(outlink->time_base);
avfilter_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
avfilter_draw_slice(outlink, 0, picref->video->h, 1);
avfilter_end_frame(outlink);
ff_start_frame(outlink, avfilter_ref_buffer(picref, ~0));
ff_draw_slice(outlink, 0, picref->video->h, 1);
ff_end_frame(outlink);
avfilter_unref_buffer(picref);
m->frame_returned++;
@ -788,14 +791,14 @@ static int query_formats(AVFilterContext *ctx)
if(m->vf.query_format(&m->vf, conversion_map[i].fmt)){
av_log(ctx, AV_LOG_DEBUG, "supported,adding\n");
if (conversion_map[i].pix_fmt != lastpixfmt) {
avfilter_add_format(&avfmts, conversion_map[i].pix_fmt);
ff_add_format(&avfmts, conversion_map[i].pix_fmt);
lastpixfmt = conversion_map[i].pix_fmt;
}
}
}
//We assume all allowed input formats are also allowed output formats
avfilter_set_common_pixel_formats(ctx, avfmts);
ff_set_common_formats(ctx, avfmts);
return 0;
}
@ -836,7 +839,7 @@ static int request_frame(AVFilterLink *outlink)
av_log(m->avfctx, AV_LOG_DEBUG, "mp request_frame\n");
for(m->frame_returned=0; !m->frame_returned;){
ret=avfilter_request_frame(outlink->src->inputs[0]);
ret=ff_request_frame(outlink->src->inputs[0]);
if(ret<0)
break;
}

View File

@ -178,7 +178,7 @@ static int request_frame(AVFilterLink *link)
/* loop until a frame thumbnail is available (when a frame is queued,
* thumb->n is reset to zero) */
do {
int ret = avfilter_request_frame(link->src->inputs[0]);
int ret = ff_request_frame(link->src->inputs[0]);
if (ret < 0)
return ret;
} while (thumb->n);
@ -203,7 +203,7 @@ static int poll_frame(AVFilterLink *link)
/* we have some frame(s) available in the input link, but not yet enough to
* output a thumbnail, so we request more */
ret = avfilter_request_frame(inlink);
ret = ff_request_frame(inlink);
return ret < 0 ? ret : 0;
}

View File

@ -28,6 +28,7 @@
#include "drawutils.h"
#include "formats.h"
#include "video.h"
#include "internal.h"
typedef struct {
unsigned w, h;
@ -170,7 +171,7 @@ static int request_frame(AVFilterLink *outlink)
int r;
while (1) {
r = avfilter_request_frame(inlink);
r = ff_request_frame(inlink);
if (r < 0) {
if (r == AVERROR_EOF && tile->current)
end_last_frame(ctx);

View File

@ -334,7 +334,7 @@ static int poll_frame(AVFilterLink *outlink)
val = ff_poll_frame(inlink);
if (val == 1 && !tinterlace->next) {
if ((ret = avfilter_request_frame(inlink)) < 0)
if ((ret = ff_request_frame(inlink)) < 0)
return ret;
val = ff_poll_frame(inlink);
}
@ -351,7 +351,7 @@ static int request_frame(AVFilterLink *outlink)
do {
int ret;
if ((ret = avfilter_request_frame(inlink)) < 0)
if ((ret = ff_request_frame(inlink)) < 0)
return ret;
} while (!tinterlace->cur);

View File

@ -321,6 +321,11 @@ void ff_draw_slice(AVFilterLink *link, int y, int h, int slice_dir)
draw_slice(link, y, h, slice_dir);
}
void avfilter_default_end_frame(AVFilterLink *inlink)
{
default_end_frame(inlink);
}
#if FF_API_FILTERS_PUBLIC
AVFilterBufferRef *avfilter_default_get_video_buffer(AVFilterLink *link, int perms, int w, int h)
{
@ -330,10 +335,6 @@ void avfilter_default_start_frame(AVFilterLink *inlink, AVFilterBufferRef *picre
{
default_start_frame(inlink, picref);
}
void avfilter_default_end_frame(AVFilterLink *inlink)
{
default_end_frame(inlink);
}
void avfilter_default_draw_slice(AVFilterLink *inlink, int y, int h, int slice_dir)
{
default_draw_slice(inlink, y, h, slice_dir);

View File

@ -49,7 +49,7 @@ void av_set_cpu_flags_mask(int mask)
int av_parse_cpu_flags(const char *s)
{
#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2)
#define CPUFLAG_MMX2 (AV_CPU_FLAG_MMX | AV_CPU_FLAG_MMX2 | AV_CPU_FLAG_CMOV)
#define CPUFLAG_3DNOW (AV_CPU_FLAG_3DNOW | AV_CPU_FLAG_MMX)
#define CPUFLAG_3DNOWEXT (AV_CPU_FLAG_3DNOWEXT | CPUFLAG_3DNOW)
#define CPUFLAG_SSE (AV_CPU_FLAG_SSE | CPUFLAG_MMX2)
@ -84,6 +84,7 @@ int av_parse_cpu_flags(const char *s)
{ "fma4" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_FMA4 }, .unit = "flags" },
{ "3dnow" , NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOW }, .unit = "flags" },
{ "3dnowext", NULL, 0, AV_OPT_TYPE_CONST, { CPUFLAG_3DNOWEXT }, .unit = "flags" },
{ "cmov", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_CMOV }, .unit = "flags" },
#elif ARCH_ARM
{ "armv5te", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV5TE }, .unit = "flags" },
{ "armv6", NULL, 0, AV_OPT_TYPE_CONST, { AV_CPU_FLAG_ARMV6 }, .unit = "flags" },
@ -188,6 +189,7 @@ static const struct {
{ AV_CPU_FLAG_FMA4, "fma4" },
{ AV_CPU_FLAG_3DNOW, "3dnow" },
{ AV_CPU_FLAG_3DNOWEXT, "3dnowext" },
{ AV_CPU_FLAG_CMOV, "cmov" },
#endif
{ 0 }
};

View File

@ -40,9 +40,14 @@
#define AV_CPU_FLAG_SSE4 0x0100 ///< Penryn SSE4.1 functions
#define AV_CPU_FLAG_SSE42 0x0200 ///< Nehalem SSE4.2 functions
#define AV_CPU_FLAG_AVX 0x4000 ///< AVX functions: requires OS support even if YMM registers aren't used
#define AV_CPU_FLAG_CMOV 0x1000000 ///< supports cmov instruction
#define AV_CPU_FLAG_XOP 0x0400 ///< Bulldozer XOP functions
#define AV_CPU_FLAG_FMA4 0x0800 ///< Bulldozer FMA4 functions
#if LIBAVUTIL_VERSION_MAJOR <52
#define AV_CPU_FLAG_CMOV 0x1001000 ///< supports cmov instruction
#else
#define AV_CPU_FLAG_CMOV 0x1000 ///< supports cmov instruction
#endif
#define AV_CPU_FLAG_ALTIVEC 0x0001 ///< standard
#define AV_CPU_FLAG_ARMV5TE (1 << 0)

View File

@ -83,7 +83,7 @@ int ff_get_cpu_flags_x86(void)
cpuid(1, eax, ebx, ecx, std_caps);
family = ((eax>>8)&0xf) + ((eax>>20)&0xff);
model = ((eax>>4)&0xf) + ((eax>>12)&0xf0);
if (std_caps & (1<<15))
if (std_caps & (1 << 15))
rval |= AV_CPU_FLAG_CMOV;
if (std_caps & (1<<23))
rval |= AV_CPU_FLAG_MMX;