diff options
45 files changed, 648 insertions, 339 deletions
diff --git a/libavcodec/Makefile b/libavcodec/Makefile index d50a40e522..e695eafa06 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -327,7 +327,7 @@ OBJS-$(CONFIG_MSMPEG4V3_ENCODER) += msmpeg4.o msmpeg4enc.o msmpeg4data.o \ h263dec.o h263.o ituh263dec.o \ mpeg4videodec.o OBJS-$(CONFIG_MSRLE_DECODER) += msrle.o msrledec.o -OBJS-$(CONFIG_MSA1_DECODER) += mss3.o +OBJS-$(CONFIG_MSA1_DECODER) += mss3.o mss34dsp.o OBJS-$(CONFIG_MSS1_DECODER) += mss1.o OBJS-$(CONFIG_MSVIDEO1_DECODER) += msvideo1.o OBJS-$(CONFIG_MSVIDEO1_ENCODER) += msvideo1enc.o elbg.o diff --git a/libavcodec/libx264.c b/libavcodec/libx264.c index d56dfe76fd..2ffdc7df9d 100644 --- a/libavcodec/libx264.c +++ b/libavcodec/libx264.c @@ -175,10 +175,10 @@ static int X264_frame(AVCodecContext *ctx, AVPacket *pkt, const AVFrame *frame, x4->params.b_tff = frame->top_field_first; x264_encoder_reconfig(x4->enc, &x4->params); } - if (x4->params.vui.i_sar_height != ctx->sample_aspect_ratio.den - || x4->params.vui.i_sar_width != ctx->sample_aspect_ratio.num) { + if (x4->params.vui.i_sar_height != ctx->sample_aspect_ratio.den || + x4->params.vui.i_sar_width != ctx->sample_aspect_ratio.num) { x4->params.vui.i_sar_height = ctx->sample_aspect_ratio.den; - x4->params.vui.i_sar_width = ctx->sample_aspect_ratio.num; + x4->params.vui.i_sar_width = ctx->sample_aspect_ratio.num; x264_encoder_reconfig(x4->enc, &x4->params); } } diff --git a/libavcodec/motion-test.c b/libavcodec/motion-test.c index f55ac21c06..6b954ebc9b 100644 --- a/libavcodec/motion-test.c +++ b/libavcodec/motion-test.c @@ -119,15 +119,9 @@ int main(int argc, char **argv) int flags[2] = { AV_CPU_FLAG_MMX, AV_CPU_FLAG_MMX2 }; int flags_size = HAVE_MMX2 ? 2 : 1; - for(;;) { - c = getopt(argc, argv, "h"); - if (c == -1) - break; - switch(c) { - case 'h': - help(); - return 1; - } + if (argc > 1) { + help(); + return 1; } printf("ffmpeg motion test\n"); diff --git a/libavcodec/mss3.c b/libavcodec/mss3.c index 649b7ca918..6fbaef9552 100644 --- a/libavcodec/mss3.c +++ b/libavcodec/mss3.c @@ -26,6 +26,8 @@ #include "avcodec.h" #include "bytestream.h" +#include "dsputil.h" +#include "mss34dsp.h" #define HEADER_SIZE 27 @@ -119,39 +121,6 @@ typedef struct MSS3Context { int hblock[16 * 16]; } MSS3Context; -static const uint8_t mss3_luma_quant[64] = { - 16, 11, 10, 16, 24, 40, 51, 61, - 12, 12, 14, 19, 26, 58, 60, 55, - 14, 13, 16, 24, 40, 57, 69, 56, - 14, 17, 22, 29, 51, 87, 80, 62, - 18, 22, 37, 56, 68, 109, 103, 77, - 24, 35, 55, 64, 81, 104, 113, 92, - 49, 64, 78, 87, 103, 121, 120, 101, - 72, 92, 95, 98, 112, 100, 103, 99 -}; - -static const uint8_t mss3_chroma_quant[64] = { - 17, 18, 24, 47, 99, 99, 99, 99, - 18, 21, 26, 66, 99, 99, 99, 99, - 24, 26, 56, 99, 99, 99, 99, 99, - 47, 66, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99, - 99, 99, 99, 99, 99, 99, 99, 99 -}; - -static const uint8_t zigzag_scan[64] = { - 0, 1, 8, 16, 9, 2, 3, 10, - 17, 24, 32, 25, 18, 11, 4, 5, - 12, 19, 26, 33, 40, 48, 41, 34, - 27, 20, 13, 6, 7, 14, 21, 28, - 35, 42, 49, 56, 57, 50, 43, 36, - 29, 22, 15, 23, 30, 37, 44, 51, - 58, 59, 52, 45, 38, 31, 39, 46, - 53, 60, 61, 54, 47, 55, 62, 63 -}; - static void model2_reset(Model2 *m) { @@ -578,7 +547,7 @@ static int decode_dct(RangeCoder *c, DCTBlockCoder *bc, int *block, if (!sign) val = -val; - zz_pos = zigzag_scan[pos]; + zz_pos = ff_zigzag_direct[pos]; block[zz_pos] = val * bc->qmat[zz_pos]; pos++; } @@ -586,58 +555,6 @@ static int decode_dct(RangeCoder *c, DCTBlockCoder *bc, int *block, return pos == 64 ? 0 : -1; } -#define DCT_TEMPLATE(blk, step, SOP, shift) \ - const int t0 = -39409 * blk[7 * step] - 58980 * blk[1 * step]; \ - const int t1 = 39410 * blk[1 * step] - 58980 * blk[7 * step]; \ - const int t2 = -33410 * blk[5 * step] - 167963 * blk[3 * step]; \ - const int t3 = 33410 * blk[3 * step] - 167963 * blk[5 * step]; \ - const int t4 = blk[3 * step] + blk[7 * step]; \ - const int t5 = blk[1 * step] + blk[5 * step]; \ - const int t6 = 77062 * t4 + 51491 * t5; \ - const int t7 = 77062 * t5 - 51491 * t4; \ - const int t8 = 35470 * blk[2 * step] - 85623 * blk[6 * step]; \ - const int t9 = 35470 * blk[6 * step] + 85623 * blk[2 * step]; \ - const int tA = SOP(blk[0 * step] - blk[4 * step]); \ - const int tB = SOP(blk[0 * step] + blk[4 * step]); \ - \ - blk[0 * step] = ( t1 + t6 + t9 + tB) >> shift; \ - blk[1 * step] = ( t3 + t7 + t8 + tA) >> shift; \ - blk[2 * step] = ( t2 + t6 - t8 + tA) >> shift; \ - blk[3 * step] = ( t0 + t7 - t9 + tB) >> shift; \ - blk[4 * step] = (-(t0 + t7) - t9 + tB) >> shift; \ - blk[5 * step] = (-(t2 + t6) - t8 + tA) >> shift; \ - blk[6 * step] = (-(t3 + t7) + t8 + tA) >> shift; \ - blk[7 * step] = (-(t1 + t6) + t9 + tB) >> shift; \ - -#define SOP_ROW(a) ((a) << 16) + 0x2000 -#define SOP_COL(a) ((a + 32) << 16) - -static void dct_put(uint8_t *dst, int stride, int *block) -{ - int i, j; - int *ptr; - - ptr = block; - for (i = 0; i < 8; i++) { - DCT_TEMPLATE(ptr, 1, SOP_ROW, 13); - ptr += 8; - } - - ptr = block; - for (i = 0; i < 8; i++) { - DCT_TEMPLATE(ptr, 8, SOP_COL, 22); - ptr++; - } - - ptr = block; - for (j = 0; j < 8; j++) { - for (i = 0; i < 8; i++) - dst[i] = av_clip_uint8(ptr[i] + 128); - dst += stride; - ptr += 8; - } -} - static void decode_dct_block(RangeCoder *c, DCTBlockCoder *bc, uint8_t *dst, int stride, int block_size, int *block, int mb_x, int mb_y) @@ -655,7 +572,7 @@ static void decode_dct_block(RangeCoder *c, DCTBlockCoder *bc, c->got_error = 1; return; } - dct_put(dst + i * 8, stride, block); + ff_mss34_dct_put(dst + i * 8, stride, block); } dst += 8 * stride; } @@ -702,14 +619,6 @@ static void decode_haar_block(RangeCoder *c, HaarBlockCoder *hc, } } -static void gen_quant_mat(uint16_t *qmat, const uint8_t *ref, float scale) -{ - int i; - - for (i = 0; i < 64; i++) - qmat[i] = (uint16_t)(ref[i] * scale + 50.0) / 100; -} - static void reset_coders(MSS3Context *ctx, int quality) { int i, j; @@ -726,15 +635,8 @@ static void reset_coders(MSS3Context *ctx, int quality) for (j = 0; j < 125; j++) model_reset(&ctx->image_coder[i].vq_model[j]); if (ctx->dct_coder[i].quality != quality) { - float scale; ctx->dct_coder[i].quality = quality; - if (quality > 50) - scale = 200.0f - 2 * quality; - else - scale = 5000.0f / quality; - gen_quant_mat(ctx->dct_coder[i].qmat, - i ? mss3_chroma_quant : mss3_luma_quant, - scale); + ff_mss34_gen_quant_mat(ctx->dct_coder[i].qmat, quality, !i); } memset(ctx->dct_coder[i].prev_dc, 0, sizeof(*ctx->dct_coder[i].prev_dc) * diff --git a/libavcodec/mss34dsp.c b/libavcodec/mss34dsp.c new file mode 100644 index 0000000000..e4d4299805 --- /dev/null +++ b/libavcodec/mss34dsp.c @@ -0,0 +1,114 @@ +/* + * Common stuff for some Microsoft Screen codecs + * Copyright (C) 2012 Konstantin Shishkov + * + * 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 <stdint.h> +#include "libavutil/common.h" +#include "mss34dsp.h" + +static const uint8_t luma_quant[64] = { + 16, 11, 10, 16, 24, 40, 51, 61, + 12, 12, 14, 19, 26, 58, 60, 55, + 14, 13, 16, 24, 40, 57, 69, 56, + 14, 17, 22, 29, 51, 87, 80, 62, + 18, 22, 37, 56, 68, 109, 103, 77, + 24, 35, 55, 64, 81, 104, 113, 92, + 49, 64, 78, 87, 103, 121, 120, 101, + 72, 92, 95, 98, 112, 100, 103, 99 +}; + +static const uint8_t chroma_quant[64] = { + 17, 18, 24, 47, 99, 99, 99, 99, + 18, 21, 26, 66, 99, 99, 99, 99, + 24, 26, 56, 99, 99, 99, 99, 99, + 47, 66, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99, + 99, 99, 99, 99, 99, 99, 99, 99 +}; + +void ff_mss34_gen_quant_mat(uint16_t *qmat, int quality, int luma) +{ + int i; + const uint8_t *qsrc = luma ? luma_quant : chroma_quant; + + if (quality >= 50) { + int scale = 200 - 2 * quality; + + for (i = 0; i < 64; i++) + qmat[i] = (qsrc[i] * scale + 50) / 100; + } else { + for (i = 0; i < 64; i++) + qmat[i] = (5000 * qsrc[i] / quality + 50) / 100; + } +} + +#define DCT_TEMPLATE(blk, step, SOP, shift) \ + const int t0 = -39409 * blk[7 * step] - 58980 * blk[1 * step]; \ + const int t1 = 39410 * blk[1 * step] - 58980 * blk[7 * step]; \ + const int t2 = -33410 * blk[5 * step] - 167963 * blk[3 * step]; \ + const int t3 = 33410 * blk[3 * step] - 167963 * blk[5 * step]; \ + const int t4 = blk[3 * step] + blk[7 * step]; \ + const int t5 = blk[1 * step] + blk[5 * step]; \ + const int t6 = 77062 * t4 + 51491 * t5; \ + const int t7 = 77062 * t5 - 51491 * t4; \ + const int t8 = 35470 * blk[2 * step] - 85623 * blk[6 * step]; \ + const int t9 = 35470 * blk[6 * step] + 85623 * blk[2 * step]; \ + const int tA = SOP(blk[0 * step] - blk[4 * step]); \ + const int tB = SOP(blk[0 * step] + blk[4 * step]); \ + \ + blk[0 * step] = ( t1 + t6 + t9 + tB) >> shift; \ + blk[1 * step] = ( t3 + t7 + t8 + tA) >> shift; \ + blk[2 * step] = ( t2 + t6 - t8 + tA) >> shift; \ + blk[3 * step] = ( t0 + t7 - t9 + tB) >> shift; \ + blk[4 * step] = (-(t0 + t7) - t9 + tB) >> shift; \ + blk[5 * step] = (-(t2 + t6) - t8 + tA) >> shift; \ + blk[6 * step] = (-(t3 + t7) + t8 + tA) >> shift; \ + blk[7 * step] = (-(t1 + t6) + t9 + tB) >> shift; \ + +#define SOP_ROW(a) ((a) << 16) + 0x2000 +#define SOP_COL(a) ((a + 32) << 16) + +void ff_mss34_dct_put(uint8_t *dst, int stride, int *block) +{ + int i, j; + int *ptr; + + ptr = block; + for (i = 0; i < 8; i++) { + DCT_TEMPLATE(ptr, 1, SOP_ROW, 13); + ptr += 8; + } + + ptr = block; + for (i = 0; i < 8; i++) { + DCT_TEMPLATE(ptr, 8, SOP_COL, 22); + ptr++; + } + + ptr = block; + for (j = 0; j < 8; j++) { + for (i = 0; i < 8; i++) + dst[i] = av_clip_uint8(ptr[i] + 128); + dst += stride; + ptr += 8; + } +} diff --git a/libavcodec/mss34dsp.h b/libavcodec/mss34dsp.h new file mode 100644 index 0000000000..2f9827d3e5 --- /dev/null +++ b/libavcodec/mss34dsp.h @@ -0,0 +1,45 @@ +/* + * Common stuff for some Microsoft Screen codecs + * Copyright (C) 2012 Konstantin Shishkov + * + * 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 + */ + +#ifndef AVCODEC_MSS34DSP_H +#define AVCODEC_MSS34DSP_H + +#include <stdint.h> + +/** + * Generate quantisation matrix for given quality. + * + * @param qmat destination matrix + * @param quality quality setting (1-100) + * @param luma generate quantisation matrix for luma or chroma + */ +void ff_mss34_gen_quant_mat(uint16_t *qmat, int quality, int luma); + +/** + * Transform and output DCT block. + * + * @param dst output plane + * @param stride output plane stride + * @param block block to transform and output + */ +void ff_mss34_dct_put(uint8_t *dst, int stride, int *block); + +#endif /* AVCODEC_MSS34DSP_H */ diff --git a/libavfilter/af_aconvert.c b/libavfilter/af_aconvert.c index 51167f4327..dc9cf455a3 100644 --- a/libavfilter/af_aconvert.c +++ b/libavfilter/af_aconvert.c @@ -135,12 +135,13 @@ static int config_output(AVFilterLink *outlink) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) { AConvertContext *aconvert = inlink->dst->priv; const int n = insamplesref->audio->nb_samples; AVFilterLink *const outlink = inlink->dst->outputs[0]; AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n); + int ret; swr_convert(aconvert->swr, outsamplesref->data, n, (void *)insamplesref->data, n); @@ -148,8 +149,9 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref avfilter_copy_buffer_ref_props(outsamplesref, insamplesref); outsamplesref->audio->channel_layout = outlink->channel_layout; - ff_filter_samples(outlink, outsamplesref); + ret = ff_filter_samples(outlink, outsamplesref); avfilter_unref_buffer(insamplesref); + return ret; } AVFilter avfilter_af_aconvert = { diff --git a/libavfilter/af_amerge.c b/libavfilter/af_amerge.c index 802188d028..660ae5dc9d 100644 --- a/libavfilter/af_amerge.c +++ b/libavfilter/af_amerge.c @@ -212,7 +212,7 @@ static inline void copy_samples(int nb_inputs, struct amerge_input in[], } } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterContext *ctx = inlink->dst; AMergeContext *am = ctx->priv; @@ -232,7 +232,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) for (i = 1; i < am->nb_inputs; i++) nb_samples = FFMIN(nb_samples, am->in[i].nb_samples); if (!nb_samples) - return; + return 0; outbuf = ff_get_audio_buffer(ctx->outputs[0], AV_PERM_WRITE, nb_samples); outs = outbuf->data[0]; @@ -285,7 +285,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) } } } - ff_filter_samples(ctx->outputs[0], outbuf); + return ff_filter_samples(ctx->outputs[0], outbuf); } static av_cold int init(AVFilterContext *ctx, const char *args) diff --git a/libavfilter/af_amix.c b/libavfilter/af_amix.c index 6dad3db0d0..7f83750fa1 100644 --- a/libavfilter/af_amix.c +++ b/libavfilter/af_amix.c @@ -305,9 +305,7 @@ static int output_frame(AVFilterLink *outlink, int nb_samples) if (s->next_pts != AV_NOPTS_VALUE) s->next_pts += nb_samples; - ff_filter_samples(outlink, out_buf); - - return 0; + return ff_filter_samples(outlink, out_buf); } /** @@ -448,31 +446,37 @@ static int request_frame(AVFilterLink *outlink) return output_frame(outlink, available_samples); } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; MixContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; - int i; + int i, ret = 0; for (i = 0; i < ctx->nb_inputs; i++) if (ctx->inputs[i] == inlink) break; if (i >= ctx->nb_inputs) { av_log(ctx, AV_LOG_ERROR, "unknown input link\n"); - return; + ret = AVERROR(EINVAL); + goto fail; } if (i == 0) { int64_t pts = av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); - frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts); + ret = frame_list_add_frame(s->frame_list, buf->audio->nb_samples, pts); + if (ret < 0) + goto fail; } - av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, - buf->audio->nb_samples); + ret = av_audio_fifo_write(s->fifos[i], (void **)buf->extended_data, + buf->audio->nb_samples); +fail: avfilter_unref_buffer(buf); + + return ret; } static int init(AVFilterContext *ctx, const char *args) diff --git a/libavfilter/af_aresample.c b/libavfilter/af_aresample.c index 095a2b50e1..cf1d8df0ce 100644 --- a/libavfilter/af_aresample.c +++ b/libavfilter/af_aresample.c @@ -168,13 +168,14 @@ static int config_output(AVFilterLink *outlink) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref) { AResampleContext *aresample = inlink->dst->priv; const int n_in = insamplesref->audio->nb_samples; int n_out = n_in * aresample->ratio * 2 ; AVFilterLink *const outlink = inlink->dst->outputs[0]; AVFilterBufferRef *outsamplesref = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n_out); + int ret; avfilter_copy_buffer_ref_props(outsamplesref, insamplesref); @@ -193,15 +194,16 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamplesref if (n_out <= 0) { avfilter_unref_buffer(outsamplesref); avfilter_unref_buffer(insamplesref); - return; + return 0; } outsamplesref->audio->sample_rate = outlink->sample_rate; outsamplesref->audio->nb_samples = n_out; - ff_filter_samples(outlink, outsamplesref); + ret = ff_filter_samples(outlink, outsamplesref); aresample->req_fullfilled= 1; avfilter_unref_buffer(insamplesref); + return ret; } static int request_frame(AVFilterLink *outlink) diff --git a/libavfilter/af_asetnsamples.c b/libavfilter/af_asetnsamples.c index 7a6c381853..95fd507d4d 100644 --- a/libavfilter/af_asetnsamples.c +++ b/libavfilter/af_asetnsamples.c @@ -131,7 +131,7 @@ static int push_samples(AVFilterLink *outlink) return nb_out_samples; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterContext *ctx = inlink->dst; ASNSContext *asns = ctx->priv; @@ -145,7 +145,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) if (ret < 0) { av_log(ctx, AV_LOG_ERROR, "Stretching audio fifo failed, discarded %d samples\n", nb_samples); - return; + return -1; } } av_audio_fifo_write(asns->fifo, (void **)insamples->extended_data, nb_samples); @@ -155,6 +155,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) if (av_audio_fifo_size(asns->fifo) >= asns->nb_out_samples) push_samples(outlink); + return 0; } static int request_frame(AVFilterLink *outlink) diff --git a/libavfilter/af_ashowinfo.c b/libavfilter/af_ashowinfo.c index d774ec72a1..0d4bbb23f6 100644 --- a/libavfilter/af_ashowinfo.c +++ b/libavfilter/af_ashowinfo.c @@ -40,7 +40,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) { AVFilterContext *ctx = inlink->dst; ShowInfoContext *showinfo = ctx->priv; @@ -83,7 +83,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) av_log(ctx, AV_LOG_INFO, "]\n"); showinfo->frame++; - ff_filter_samples(inlink->dst->outputs[0], samplesref); + return ff_filter_samples(inlink->dst->outputs[0], samplesref); } AVFilter avfilter_af_ashowinfo = { diff --git a/libavfilter/af_astreamsync.c b/libavfilter/af_astreamsync.c index 8cf3f39b52..587d9a7662 100644 --- a/libavfilter/af_astreamsync.c +++ b/libavfilter/af_astreamsync.c @@ -107,11 +107,12 @@ static int config_output(AVFilterLink *outlink) return 0; } -static void send_out(AVFilterContext *ctx, int out_id) +static int send_out(AVFilterContext *ctx, int out_id) { AStreamSyncContext *as = ctx->priv; struct buf_queue *queue = &as->queue[out_id]; AVFilterBufferRef *buf = queue->buf[queue->tail]; + int ret; queue->buf[queue->tail] = NULL; as->var_values[VAR_B1 + out_id]++; @@ -121,11 +122,12 @@ static void send_out(AVFilterContext *ctx, int out_id) av_q2d(ctx->outputs[out_id]->time_base) * buf->pts; as->var_values[VAR_T1 + out_id] += buf->audio->nb_samples / (double)ctx->inputs[out_id]->sample_rate; - ff_filter_samples(ctx->outputs[out_id], buf); + ret = ff_filter_samples(ctx->outputs[out_id], buf); queue->nb--; queue->tail = (queue->tail + 1) % QUEUE_SIZE; if (as->req[out_id]) as->req[out_id]--; + return ret; } static void send_next(AVFilterContext *ctx) @@ -165,7 +167,7 @@ static int request_frame(AVFilterLink *outlink) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterContext *ctx = inlink->dst; AStreamSyncContext *as = ctx->priv; @@ -175,6 +177,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) insamples; as->eof &= ~(1 << id); send_next(ctx); + return 0; } AVFilter avfilter_af_astreamsync = { diff --git a/libavfilter/af_asyncts.c b/libavfilter/af_asyncts.c index 2435cca26e..7459610af8 100644 --- a/libavfilter/af_asyncts.c +++ b/libavfilter/af_asyncts.c @@ -37,6 +37,9 @@ typedef struct ASyncContext { int resample; float min_delta_sec; int max_comp; + + /* set by filter_samples() to signal an output frame to request_frame() */ + int got_output; } ASyncContext; #define OFFSET(x) offsetof(ASyncContext, x) @@ -112,9 +115,13 @@ static int request_frame(AVFilterLink *link) { AVFilterContext *ctx = link->src; ASyncContext *s = ctx->priv; - int ret = ff_request_frame(ctx->inputs[0]); + int ret = 0; int nb_samples; + s->got_output = 0; + while (ret >= 0 && !s->got_output) + ret = ff_request_frame(ctx->inputs[0]); + /* flush the fifo */ if (ret == AVERROR_EOF && (nb_samples = avresample_get_delay(s->avr))) { AVFilterBufferRef *buf = ff_get_audio_buffer(link, AV_PERM_WRITE, @@ -124,18 +131,18 @@ static int request_frame(AVFilterLink *link) avresample_convert(s->avr, (void**)buf->extended_data, buf->linesize[0], nb_samples, NULL, 0, 0); buf->pts = s->pts; - ff_filter_samples(link, buf); - return 0; + return ff_filter_samples(link, buf); } return ret; } -static void write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) +static int write_to_fifo(ASyncContext *s, AVFilterBufferRef *buf) { - avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, - buf->linesize[0], buf->audio->nb_samples); + int ret = avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); avfilter_unref_buffer(buf); + return ret; } /* get amount of data currently buffered, in samples */ @@ -144,7 +151,7 @@ static int64_t get_delay(ASyncContext *s) return avresample_available(s->avr) + avresample_get_delay(s->avr); } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; ASyncContext *s = ctx->priv; @@ -152,7 +159,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) int nb_channels = av_get_channel_layout_nb_channels(buf->audio->channel_layout); int64_t pts = (buf->pts == AV_NOPTS_VALUE) ? buf->pts : av_rescale_q(buf->pts, inlink->time_base, outlink->time_base); - int out_size; + int out_size, ret; int64_t delta; /* buffer data until we get the first timestamp */ @@ -160,14 +167,12 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) if (pts != AV_NOPTS_VALUE) { s->pts = pts - get_delay(s); } - write_to_fifo(s, buf); - return; + return write_to_fifo(s, buf); } /* now wait for the next timestamp */ if (pts == AV_NOPTS_VALUE) { - write_to_fifo(s, buf); - return; + return write_to_fifo(s, buf); } /* when we have two timestamps, compute how many samples would we have @@ -190,8 +195,10 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) if (out_size > 0) { AVFilterBufferRef *buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, out_size); - if (!buf_out) - return; + if (!buf_out) { + ret = AVERROR(ENOMEM); + goto fail; + } avresample_read(s->avr, (void**)buf_out->extended_data, out_size); buf_out->pts = s->pts; @@ -200,7 +207,10 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) av_samples_set_silence(buf_out->extended_data, out_size - delta, delta, nb_channels, buf->format); } - ff_filter_samples(outlink, buf_out); + ret = ff_filter_samples(outlink, buf_out); + if (ret < 0) + goto fail; + s->got_output = 1; } else { av_log(ctx, AV_LOG_WARNING, "Non-monotonous timestamps, dropping " "whole buffer.\n"); @@ -210,9 +220,13 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) avresample_read(s->avr, NULL, avresample_available(s->avr)); s->pts = pts - avresample_get_delay(s->avr); - avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, - buf->linesize[0], buf->audio->nb_samples); + ret = avresample_convert(s->avr, NULL, 0, 0, (void**)buf->extended_data, + buf->linesize[0], buf->audio->nb_samples); + +fail: avfilter_unref_buffer(buf); + + return ret; } AVFilter avfilter_af_asyncts = { diff --git a/libavfilter/af_atempo.c b/libavfilter/af_atempo.c index 7a08503906..959cacb6ad 100644 --- a/libavfilter/af_atempo.c +++ b/libavfilter/af_atempo.c @@ -1040,7 +1040,7 @@ static void push_samples(ATempoContext *atempo, atempo->nsamples_out += n_out; } -static void filter_samples(AVFilterLink *inlink, +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *src_buffer) { AVFilterContext *ctx = inlink->dst; @@ -1074,6 +1074,7 @@ static void filter_samples(AVFilterLink *inlink, atempo->nsamples_in += n_in; avfilter_unref_bufferp(&src_buffer); + return 0; } static int request_frame(AVFilterLink *outlink) diff --git a/libavfilter/af_channelmap.c b/libavfilter/af_channelmap.c index 8d908ca737..1c1837c3d4 100644 --- a/libavfilter/af_channelmap.c +++ b/libavfilter/af_channelmap.c @@ -313,7 +313,7 @@ static int channelmap_query_formats(AVFilterContext *ctx) return 0; } -static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -330,8 +330,10 @@ static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *b 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 (!new_extended_data) { + avfilter_unref_buffer(buf); + return AVERROR(ENOMEM); + } if (buf->extended_data == buf->data) { buf->extended_data = new_extended_data; } else { @@ -353,7 +355,7 @@ static void channelmap_filter_samples(AVFilterLink *inlink, AVFilterBufferRef *b memcpy(buf->data, buf->extended_data, FFMIN(FF_ARRAY_ELEMS(buf->data), nch_out) * sizeof(buf->data[0])); - ff_filter_samples(outlink, buf); + return ff_filter_samples(outlink, buf); } static int channelmap_config_input(AVFilterLink *inlink) diff --git a/libavfilter/af_channelsplit.c b/libavfilter/af_channelsplit.c index bf0b24dc5e..3db08045c2 100644 --- a/libavfilter/af_channelsplit.c +++ b/libavfilter/af_channelsplit.c @@ -105,24 +105,29 @@ static int query_formats(AVFilterContext *ctx) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; - int i; + int i, ret = 0; for (i = 0; i < ctx->nb_outputs; i++) { AVFilterBufferRef *buf_out = avfilter_ref_buffer(buf, ~AV_PERM_WRITE); - if (!buf_out) - return; + if (!buf_out) { + ret = AVERROR(ENOMEM); + break; + } buf_out->data[0] = buf_out->extended_data[0] = buf_out->extended_data[i]; buf_out->audio->channel_layout = av_channel_layout_extract_channel(buf->audio->channel_layout, i); - ff_filter_samples(ctx->outputs[i], buf_out); + ret = ff_filter_samples(ctx->outputs[i], buf_out); + if (ret < 0) + break; } avfilter_unref_buffer(buf); + return ret; } AVFilter avfilter_af_channelsplit = { diff --git a/libavfilter/af_earwax.c b/libavfilter/af_earwax.c index d86b410a1e..7265c437d3 100644 --- a/libavfilter/af_earwax.c +++ b/libavfilter/af_earwax.c @@ -120,13 +120,15 @@ static inline int16_t *scalarproduct(const int16_t *in, const int16_t *endin, in return out; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterLink *outlink = inlink->dst->outputs[0]; int16_t *taps, *endin, *in, *out; AVFilterBufferRef *outsamples = ff_get_audio_buffer(inlink, AV_PERM_WRITE, insamples->audio->nb_samples); + int ret; + avfilter_copy_buffer_ref_props(outsamples, insamples); taps = ((EarwaxContext *)inlink->dst->priv)->taps; @@ -144,8 +146,9 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) // save part of input for next round memcpy(taps, endin, NUMTAPS * sizeof(*taps)); - ff_filter_samples(outlink, outsamples); + ret = ff_filter_samples(outlink, outsamples); avfilter_unref_buffer(insamples); + return ret; } AVFilter avfilter_af_earwax = { diff --git a/libavfilter/af_join.c b/libavfilter/af_join.c index e86c556f5b..9ed11a9991 100644 --- a/libavfilter/af_join.c +++ b/libavfilter/af_join.c @@ -92,7 +92,7 @@ static const AVClass join_class = { .version = LIBAVUTIL_VERSION_INT, }; -static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) { AVFilterContext *ctx = link->dst; JoinContext *s = ctx->priv; @@ -104,6 +104,8 @@ static void filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) av_assert0(i < ctx->nb_inputs); av_assert0(!s->input_frames[i]); s->input_frames[i] = buf; + + return 0; } static int parse_maps(AVFilterContext *ctx) @@ -468,11 +470,11 @@ static int join_request_frame(AVFilterLink *outlink) priv->nb_in_buffers = ctx->nb_inputs; buf->buf->priv = priv; - ff_filter_samples(outlink, buf); + ret = ff_filter_samples(outlink, buf); memset(s->input_frames, 0, sizeof(*s->input_frames) * ctx->nb_inputs); - return 0; + return ret; fail: avfilter_unref_buffer(buf); diff --git a/libavfilter/af_pan.c b/libavfilter/af_pan.c index f451e0034c..bb96ad0511 100644 --- a/libavfilter/af_pan.c +++ b/libavfilter/af_pan.c @@ -343,8 +343,9 @@ static int config_props(AVFilterLink *link) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { + int ret; int n = insamples->audio->nb_samples; AVFilterLink *const outlink = inlink->dst->outputs[0]; AVFilterBufferRef *outsamples = ff_get_audio_buffer(outlink, AV_PERM_WRITE, n); @@ -354,8 +355,9 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) avfilter_copy_buffer_ref_props(outsamples, insamples); outsamples->audio->channel_layout = outlink->channel_layout; - ff_filter_samples(outlink, outsamples); + ret = ff_filter_samples(outlink, outsamples); avfilter_unref_buffer(insamples); + return ret; } static av_cold void uninit(AVFilterContext *ctx) diff --git a/libavfilter/af_resample.c b/libavfilter/af_resample.c index 8a02cfe976..1360c1ca49 100644 --- a/libavfilter/af_resample.c +++ b/libavfilter/af_resample.c @@ -38,6 +38,9 @@ typedef struct ResampleContext { AVAudioResampleContext *avr; int64_t next_pts; + + /* set by filter_samples() to signal an output frame to request_frame() */ + int got_output; } ResampleContext; static av_cold void uninit(AVFilterContext *ctx) @@ -102,12 +105,6 @@ static int config_output(AVFilterLink *outlink) av_opt_set_int(s->avr, "in_sample_rate", inlink ->sample_rate, 0); av_opt_set_int(s->avr, "out_sample_rate", outlink->sample_rate, 0); - /* if both the input and output formats are s16 or u8, use s16 as - the internal sample format */ - if (av_get_bytes_per_sample(inlink->format) <= 2 && - av_get_bytes_per_sample(outlink->format) <= 2) - av_opt_set_int(s->avr, "internal_sample_fmt", AV_SAMPLE_FMT_S16P, 0); - if ((ret = avresample_open(s->avr)) < 0) return ret; @@ -130,7 +127,11 @@ static int request_frame(AVFilterLink *outlink) { AVFilterContext *ctx = outlink->src; ResampleContext *s = ctx->priv; - int ret = ff_request_frame(ctx->inputs[0]); + int ret = 0; + + s->got_output = 0; + while (ret >= 0 && !s->got_output) + ret = ff_request_frame(ctx->inputs[0]); /* flush the lavr delay buffer */ if (ret == AVERROR_EOF && s->avr) { @@ -156,21 +157,21 @@ static int request_frame(AVFilterLink *outlink) } buf->pts = s->next_pts; - ff_filter_samples(outlink, buf); - return 0; + return ff_filter_samples(outlink, buf); } return ret; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) { AVFilterContext *ctx = inlink->dst; ResampleContext *s = ctx->priv; AVFilterLink *outlink = ctx->outputs[0]; + int ret; if (s->avr) { AVFilterBufferRef *buf_out; - int delay, nb_samples, ret; + int delay, nb_samples; /* maximum possible samples lavr can output */ delay = avresample_get_delay(s->avr); @@ -179,10 +180,19 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) AV_ROUND_UP); buf_out = ff_get_audio_buffer(outlink, AV_PERM_WRITE, nb_samples); + if (!buf_out) { + ret = AVERROR(ENOMEM); + goto fail; + } + ret = avresample_convert(s->avr, (void**)buf_out->extended_data, buf_out->linesize[0], nb_samples, (void**)buf->extended_data, buf->linesize[0], buf->audio->nb_samples); + if (ret < 0) { + avfilter_unref_buffer(buf_out); + goto fail; + } av_assert0(!avresample_available(s->avr)); @@ -208,11 +218,18 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *buf) s->next_pts = buf_out->pts + buf_out->audio->nb_samples; - ff_filter_samples(outlink, buf_out); + ret = ff_filter_samples(outlink, buf_out); + s->got_output = 1; } + +fail: avfilter_unref_buffer(buf); - } else - ff_filter_samples(outlink, buf); + } else { + ret = ff_filter_samples(outlink, buf); + s->got_output = 1; + } + + return ret; } AVFilter avfilter_af_resample = { diff --git a/libavfilter/af_silencedetect.c b/libavfilter/af_silencedetect.c index 724a92362f..d3b125fc5b 100644 --- a/libavfilter/af_silencedetect.c +++ b/libavfilter/af_silencedetect.c @@ -78,7 +78,7 @@ static av_cold int init(AVFilterContext *ctx, const char *args) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { int i; SilenceDetectContext *silence = inlink->dst->priv; @@ -118,7 +118,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) } } - ff_filter_samples(inlink->dst->outputs[0], insamples); + return ff_filter_samples(inlink->dst->outputs[0], insamples); } static int query_formats(AVFilterContext *ctx) diff --git a/libavfilter/af_volume.c b/libavfilter/af_volume.c index 11da2265c9..09302ee5d9 100644 --- a/libavfilter/af_volume.c +++ b/libavfilter/af_volume.c @@ -110,7 +110,7 @@ static int query_formats(AVFilterContext *ctx) return 0; } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { VolumeContext *vol = inlink->dst->priv; AVFilterLink *outlink = inlink->dst->outputs[0]; @@ -169,7 +169,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) } } } - ff_filter_samples(outlink, insamples); + return ff_filter_samples(outlink, insamples); } AVFilter avfilter_af_volume = { diff --git a/libavfilter/asink_anullsink.c b/libavfilter/asink_anullsink.c index 4349544b62..d9e3e5a0cd 100644 --- a/libavfilter/asink_anullsink.c +++ b/libavfilter/asink_anullsink.c @@ -21,7 +21,10 @@ #include "avfilter.h" #include "internal.h" -static void null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { } +static int null_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) +{ + return 0; +} AVFilter avfilter_asink_anullsink = { .name = "anullsink", diff --git a/libavfilter/audio.c b/libavfilter/audio.c index 0ebec3c2d0..f3eebbfdae 100644 --- a/libavfilter/audio.c +++ b/libavfilter/audio.c @@ -150,19 +150,19 @@ fail: return NULL; } -static void default_filter_samples(AVFilterLink *link, - AVFilterBufferRef *samplesref) +static int default_filter_samples(AVFilterLink *link, + AVFilterBufferRef *samplesref) { - ff_filter_samples(link->dst->outputs[0], samplesref); + return ff_filter_samples(link->dst->outputs[0], samplesref); } -void ff_filter_samples_framed(AVFilterLink *link, - AVFilterBufferRef *samplesref) +int ff_filter_samples_framed(AVFilterLink *link, AVFilterBufferRef *samplesref) { - void (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); + int (*filter_samples)(AVFilterLink *, AVFilterBufferRef *); AVFilterPad *dst = link->dstpad; int64_t pts; AVFilterBufferRef *buf_out; + int ret; FF_TPRINTF_START(NULL, filter_samples); ff_tlog_link(NULL, link, 1); @@ -193,21 +193,22 @@ void ff_filter_samples_framed(AVFilterLink *link, link->cur_buf = buf_out; pts = buf_out->pts; - filter_samples(link, buf_out); + ret = filter_samples(link, buf_out); ff_update_link_current_pts(link, pts); + return ret; } -void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) +int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { int insamples = samplesref->audio->nb_samples, inpos = 0, nb_samples; AVFilterBufferRef *pbuf = link->partial_buf; int nb_channels = av_get_channel_layout_nb_channels(link->channel_layout); + int ret = 0; if (!link->min_samples || (!pbuf && insamples >= link->min_samples && insamples <= link->max_samples)) { - ff_filter_samples_framed(link, samplesref); - return; + return ff_filter_samples_framed(link, samplesref); } /* Handle framing (min_samples, max_samples) */ while (insamples) { @@ -218,7 +219,7 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) if (!pbuf) { av_log(link->dst, AV_LOG_WARNING, "Samples dropped due to memory allocation failure.\n"); - return; + return 0; } avfilter_copy_buffer_ref_props(pbuf, samplesref); pbuf->pts = samplesref->pts + @@ -234,10 +235,11 @@ void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) insamples -= nb_samples; pbuf->audio->nb_samples += nb_samples; if (pbuf->audio->nb_samples >= link->min_samples) { - ff_filter_samples_framed(link, pbuf); + ret = ff_filter_samples_framed(link, pbuf); pbuf = NULL; } } avfilter_unref_buffer(samplesref); link->partial_buf = pbuf; + return ret; } diff --git a/libavfilter/audio.h b/libavfilter/audio.h index cab1a6c722..a84c378ec8 100644 --- a/libavfilter/audio.h +++ b/libavfilter/audio.h @@ -70,14 +70,17 @@ AVFilterBufferRef *ff_get_audio_buffer(AVFilterLink *link, int perms, * @param samplesref a reference to the buffer of audio samples being sent. The * receiving filter will free this reference when it no longer * needs it or pass it on to the next filter. + * + * @return >= 0 on success, a negative AVERROR on error. The receiving filter + * is responsible for unreferencing samplesref in case of error. */ -void ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); +int ff_filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref); /** * Send a buffer of audio samples to the next link, without checking * min_samples. */ -void ff_filter_samples_framed(AVFilterLink *link, +int ff_filter_samples_framed(AVFilterLink *link, AVFilterBufferRef *samplesref); #endif /* AVFILTER_AUDIO_H */ diff --git a/libavfilter/avf_showwaves.c b/libavfilter/avf_showwaves.c index f0ebbf3c84..9a267a6b71 100644 --- a/libavfilter/avf_showwaves.c +++ b/libavfilter/avf_showwaves.c @@ -180,7 +180,7 @@ static int request_frame(AVFilterLink *outlink) #define MAX_INT16 ((1<<15) -1) -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -225,6 +225,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) } avfilter_unref_buffer(insamples); + return 0; } AVFilter avfilter_avf_showwaves = { diff --git a/libavfilter/avfilter.h b/libavfilter/avfilter.h index e08a389275..52de7405e3 100644 --- a/libavfilter/avfilter.h +++ b/libavfilter/avfilter.h @@ -301,8 +301,12 @@ struct AVFilterPad { * and should do its processing. * * Input audio pads only. + * + * @return >= 0 on success, a negative AVERROR on error. This function + * must ensure that samplesref is properly unreferenced on error if it + * hasn't been passed on to another filter. */ - void (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); + int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); /** * Frame poll callback. This returns the number of immediately available diff --git a/libavfilter/buffersink.c b/libavfilter/buffersink.c index 642350080b..9e908adf6b 100644 --- a/libavfilter/buffersink.c +++ b/libavfilter/buffersink.c @@ -56,6 +56,12 @@ static void start_frame(AVFilterLink *link, AVFilterBufferRef *buf) link->cur_buf = NULL; }; +static int filter_samples(AVFilterLink *link, AVFilterBufferRef *buf) +{ + start_frame(link, buf); + return 0; +} + int av_buffersink_read(AVFilterContext *ctx, AVFilterBufferRef **buf) { BufferSinkContext *s = ctx->priv; @@ -160,7 +166,7 @@ AVFilter avfilter_asink_abuffer = { .inputs = (AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_AUDIO, - .filter_samples = start_frame, + .filter_samples = filter_samples, .min_perms = AV_PERM_READ, .needs_fifo = 1 }, { .name = NULL }}, diff --git a/libavfilter/buffersrc.c b/libavfilter/buffersrc.c index dd9eb39b59..2592cfb64a 100644 --- a/libavfilter/buffersrc.c +++ b/libavfilter/buffersrc.c @@ -408,6 +408,7 @@ static int request_frame(AVFilterLink *link) { BufferSourceContext *c = link->src->priv; AVFilterBufferRef *buf; + int ret = 0; if (!av_fifo_size(c->fifo)) { if (c->eof) @@ -424,7 +425,7 @@ static int request_frame(AVFilterLink *link) ff_end_frame(link); break; case AVMEDIA_TYPE_AUDIO: - ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); + ret = ff_filter_samples(link, avfilter_ref_buffer(buf, ~0)); break; default: return AVERROR(EINVAL); @@ -432,7 +433,7 @@ static int request_frame(AVFilterLink *link) avfilter_unref_buffer(buf); - return 0; + return ret; } static int poll_frame(AVFilterLink *link) diff --git a/libavfilter/f_settb.c b/libavfilter/f_settb.c index 6549a5c26c..3ba35be70e 100644 --- a/libavfilter/f_settb.c +++ b/libavfilter/f_settb.c @@ -117,7 +117,7 @@ static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *picref) ff_start_frame(outlink, picref2); } -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) { AVFilterContext *ctx = inlink->dst; AVFilterLink *outlink = ctx->outputs[0]; @@ -132,7 +132,7 @@ static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *insamples) avfilter_unref_buffer(insamples); } - ff_filter_samples(outlink, outsamples); + return ff_filter_samples(outlink, outsamples); } #if CONFIG_SETTB_FILTER diff --git a/libavfilter/fifo.c b/libavfilter/fifo.c index bc9c8fa580..34db5ecbee 100644 --- a/libavfilter/fifo.c +++ b/libavfilter/fifo.c @@ -72,13 +72,25 @@ static av_cold void uninit(AVFilterContext *ctx) avfilter_unref_buffer(fifo->buf_out); } -static void add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) +static int add_to_queue(AVFilterLink *inlink, AVFilterBufferRef *buf) { FifoContext *fifo = inlink->dst->priv; fifo->last->next = av_mallocz(sizeof(Buf)); + if (!fifo->last->next) { + avfilter_unref_buffer(buf); + return AVERROR(ENOMEM); + } + fifo->last = fifo->last->next; fifo->last->buf = buf; + + return 0; +} + +static void start_frame(AVFilterLink *inlink, AVFilterBufferRef *buf) +{ + add_to_queue(inlink, buf); } static void queue_pop(FifoContext *s) @@ -210,15 +222,13 @@ static int return_audio_frame(AVFilterContext *ctx) buf_out = s->buf_out; s->buf_out = NULL; } - ff_filter_samples(link, buf_out); - - return 0; + return ff_filter_samples(link, buf_out); } static int request_frame(AVFilterLink *outlink) { FifoContext *fifo = outlink->src->priv; - int ret; + int ret = 0; if (!fifo->root.next) { if ((ret = ff_request_frame(outlink->src->inputs[0])) < 0) @@ -238,7 +248,7 @@ static int request_frame(AVFilterLink *outlink) if (outlink->request_samples) { return return_audio_frame(outlink->src); } else { - ff_filter_samples(outlink, fifo->root.next->buf); + ret = ff_filter_samples(outlink, fifo->root.next->buf); queue_pop(fifo); } break; @@ -246,7 +256,7 @@ static int request_frame(AVFilterLink *outlink) return AVERROR(EINVAL); } - return 0; + return ret; } AVFilter avfilter_vf_fifo = { @@ -261,7 +271,7 @@ AVFilter avfilter_vf_fifo = { .inputs = (const AVFilterPad[]) {{ .name = "default", .type = AVMEDIA_TYPE_VIDEO, .get_video_buffer= ff_null_get_video_buffer, - .start_frame = add_to_queue, + .start_frame = start_frame, .draw_slice = draw_slice, .end_frame = end_frame, .rej_perms = AV_PERM_REUSE2, }, diff --git a/libavfilter/internal.h b/libavfilter/internal.h index 40ffef5721..d1bcb0353c 100644 --- a/libavfilter/internal.h +++ b/libavfilter/internal.h @@ -135,8 +135,12 @@ struct AVFilterPad { * and should do its processing. * * Input audio pads only. + * + * @return >= 0 on success, a negative AVERROR on error. This function + * must ensure that samplesref is properly unreferenced on error if it + * hasn't been passed on to another filter. */ - void (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); + int (*filter_samples)(AVFilterLink *link, AVFilterBufferRef *samplesref); /** * Frame poll callback. This returns the number of immediately available diff --git a/libavfilter/sink_buffer.c b/libavfilter/sink_buffer.c index 8275f80965..ceae11203d 100644 --- a/libavfilter/sink_buffer.c +++ b/libavfilter/sink_buffer.c @@ -244,9 +244,10 @@ AVFilter avfilter_vsink_buffersink = { #if CONFIG_ABUFFERSINK_FILTER -static void filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) +static int filter_samples(AVFilterLink *link, AVFilterBufferRef *samplesref) { end_frame(link); + return 0; } static av_cold int asink_init(AVFilterContext *ctx, const char *args) diff --git a/libavfilter/split.c b/libavfilter/split.c index 837dc0da15..98be342bfc 100644 --- a/libavfilter/split.c +++ b/libavfilter/split.c @@ -110,15 +110,19 @@ AVFilter avfilter_vf_split = { .outputs = (AVFilterPad[]) {{ .name = NULL}}, }; -static void filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) +static int filter_samples(AVFilterLink *inlink, AVFilterBufferRef *samplesref) { AVFilterContext *ctx = inlink->dst; - int i; + int i, ret = 0; - for (i = 0; i < ctx->nb_outputs; i++) - ff_filter_samples(inlink->dst->outputs[i], - avfilter_ref_buffer(samplesref, ~AV_PERM_WRITE)); + for (i = 0; i < ctx->nb_outputs; i++) { + ret = ff_filter_samples(inlink->dst->outputs[i], + avfilter_ref_buffer(samplesref, ~AV_PERM_WRITE)); + if (ret < 0) + break; + } avfilter_unref_buffer(samplesref); + return ret; } AVFilter avfilter_af_asplit = { diff --git a/libavformat/matroskadec.c b/libavformat/matroskadec.c index aaeff210df..42aa961a41 100644 --- a/libavformat/matroskadec.c +++ b/libavformat/matroskadec.c @@ -842,8 +842,11 @@ static int ebml_parse_id(MatroskaDemuxContext *matroska, EbmlSyntax *syntax, matroska->num_levels > 0 && matroska->levels[matroska->num_levels-1].length == 0xffffffffffffff) return 0; // we reached the end of an unknown size cluster - if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) + if (!syntax[i].id && id != EBML_ID_VOID && id != EBML_ID_CRC32) { av_log(matroska->ctx, AV_LOG_INFO, "Unknown entry 0x%X\n", id); + if (matroska->ctx->error_recognition & AV_EF_EXPLODE) + return AVERROR_INVALIDDATA; + } return ebml_parse_elem(matroska, &syntax[i], data); } diff --git a/libavformat/tcp.c b/libavformat/tcp.c index 42dcee0c16..70a50159eb 100644 --- a/libavformat/tcp.c +++ b/libavformat/tcp.c @@ -43,7 +43,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) char buf[256]; int ret; socklen_t optlen; - int timeout = 50; + int timeout = 50, listen_timeout = -1; char hostname[1024],proto[1024],path[1024]; char portstr[10]; @@ -59,6 +59,9 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (av_find_info_tag(buf, sizeof(buf), "timeout", p)) { timeout = strtol(buf, NULL, 10); } + if (av_find_info_tag(buf, sizeof(buf), "listen_timeout", p)) { + listen_timeout = strtol(buf, NULL, 10); + } } hints.ai_family = AF_UNSPEC; hints.ai_socktype = SOCK_STREAM; @@ -87,6 +90,7 @@ static int tcp_open(URLContext *h, const char *uri, int flags) if (listen_socket) { int fd1; int reuse = 1; + struct pollfd lp = { fd, POLLIN, 0 }; setsockopt(fd, SOL_SOCKET, SO_REUSEADDR, &reuse, sizeof(reuse)); ret = bind(fd, cur_ai->ai_addr, cur_ai->ai_addrlen); if (ret) { @@ -98,6 +102,11 @@ static int tcp_open(URLContext *h, const char *uri, int flags) ret = ff_neterrno(); goto fail1; } + ret = poll(&lp, 1, listen_timeout >= 0 ? listen_timeout : -1); + if (ret <= 0) { + ret = AVERROR(ETIMEDOUT); + goto fail1; + } fd1 = accept(fd, NULL, NULL); if (fd1 < 0) { ret = ff_neterrno(); diff --git a/libavresample/audio_mix.c b/libavresample/audio_mix.c index 93192221cd..2c2a356844 100644 --- a/libavresample/audio_mix.c +++ b/libavresample/audio_mix.c @@ -305,6 +305,14 @@ int ff_audio_mix_init(AVAudioResampleContext *avr) { int ret; + if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && + avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { + av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " + "mixing: %s\n", + av_get_sample_fmt_name(avr->internal_sample_fmt)); + return AVERROR(EINVAL); + } + /* build matrix if the user did not already set one */ if (!avr->am->matrix) { int i, j; diff --git a/libavresample/avresample.h b/libavresample/avresample.h index 002bec21fb..b93aba5d73 100644 --- a/libavresample/avresample.h +++ b/libavresample/avresample.h @@ -45,6 +45,13 @@ enum AVMixCoeffType { AV_MIX_COEFF_TYPE_NB, /** Number of coeff types. Not part of ABI */ }; +/** Resampling Filter Types */ +enum AVResampleFilterType { + AV_RESAMPLE_FILTER_TYPE_CUBIC, /**< Cubic */ + AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL, /**< Blackman Nuttall Windowed Sinc */ + AV_RESAMPLE_FILTER_TYPE_KAISER, /**< Kaiser Windowed Sinc */ +}; + /** * Return the LIBAVRESAMPLE_VERSION_INT constant. */ diff --git a/libavresample/internal.h b/libavresample/internal.h index fa9499a8ef..7b7648f0be 100644 --- a/libavresample/internal.h +++ b/libavresample/internal.h @@ -50,6 +50,8 @@ struct AVAudioResampleContext { int phase_shift; /**< log2 of the number of entries in the resampling polyphase filterbank */ int linear_interp; /**< if 1 then the resampling FIR filter will be linearly interpolated */ double cutoff; /**< resampling cutoff frequency. 1.0 corresponds to half the output sample rate */ + enum AVResampleFilterType filter_type; /**< resampling filter type */ + int kaiser_beta; /**< beta value for Kaiser window (only applicable if filter_type == AV_FILTER_TYPE_KAISER) */ int in_channels; /**< number of input channels */ int out_channels; /**< number of output channels */ diff --git a/libavresample/options.c b/libavresample/options.c index a1a0b0ca21..02e1f86308 100644 --- a/libavresample/options.c +++ b/libavresample/options.c @@ -39,7 +39,7 @@ static const AVOption options[] = { { "out_channel_layout", "Output Channel Layout", OFFSET(out_channel_layout), AV_OPT_TYPE_INT64, { 0 }, INT64_MIN, INT64_MAX, PARAM }, { "out_sample_fmt", "Output Sample Format", OFFSET(out_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_S16 }, AV_SAMPLE_FMT_U8, AV_SAMPLE_FMT_NB-1, PARAM }, { "out_sample_rate", "Output Sample Rate", OFFSET(out_sample_rate), AV_OPT_TYPE_INT, { 48000 }, 1, INT_MAX, PARAM }, - { "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_FLTP }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM }, + { "internal_sample_fmt", "Internal Sample Format", OFFSET(internal_sample_fmt), AV_OPT_TYPE_INT, { AV_SAMPLE_FMT_NONE }, AV_SAMPLE_FMT_NONE, AV_SAMPLE_FMT_NB-1, PARAM }, { "mix_coeff_type", "Mixing Coefficient Type", OFFSET(mix_coeff_type), AV_OPT_TYPE_INT, { AV_MIX_COEFF_TYPE_FLT }, AV_MIX_COEFF_TYPE_Q8, AV_MIX_COEFF_TYPE_NB-1, PARAM, "mix_coeff_type" }, { "q8", "16-bit 8.8 Fixed-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q8 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, { "q15", "32-bit 17.15 Fixed-Point", 0, AV_OPT_TYPE_CONST, { AV_MIX_COEFF_TYPE_Q15 }, INT_MIN, INT_MAX, PARAM, "mix_coeff_type" }, @@ -56,6 +56,11 @@ static const AVOption options[] = { { "none", "None", 0, AV_OPT_TYPE_CONST, { AV_MATRIX_ENCODING_NONE }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, { "dolby", "Dolby", 0, AV_OPT_TYPE_CONST, { AV_MATRIX_ENCODING_DOLBY }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, { "dplii", "Dolby Pro Logic II", 0, AV_OPT_TYPE_CONST, { AV_MATRIX_ENCODING_DPLII }, INT_MIN, INT_MAX, PARAM, "matrix_encoding" }, + { "filter_type", "Filter Type", OFFSET(filter_type), AV_OPT_TYPE_INT, { AV_RESAMPLE_FILTER_TYPE_KAISER }, AV_RESAMPLE_FILTER_TYPE_CUBIC, AV_RESAMPLE_FILTER_TYPE_KAISER, PARAM, "filter_type" }, + { "cubic", "Cubic", 0, AV_OPT_TYPE_CONST, { AV_RESAMPLE_FILTER_TYPE_CUBIC }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + { "blackman_nuttall", "Blackman Nuttall Windowed Sinc", 0, AV_OPT_TYPE_CONST, { AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + { "kaiser", "Kaiser Windowed Sinc", 0, AV_OPT_TYPE_CONST, { AV_RESAMPLE_FILTER_TYPE_KAISER }, INT_MIN, INT_MAX, PARAM, "filter_type" }, + { "kaiser_beta", "Kaiser Window Beta", OFFSET(kaiser_beta), AV_OPT_TYPE_INT, { 9 }, 2, 16, PARAM }, { NULL }, }; diff --git a/libavresample/resample.c b/libavresample/resample.c index 5529fafe8d..1c3d13ae0a 100644 --- a/libavresample/resample.c +++ b/libavresample/resample.c @@ -24,37 +24,10 @@ #include "internal.h" #include "audio_data.h" -#ifdef CONFIG_RESAMPLE_FLT -/* float template */ -#define FILTER_SHIFT 0 -#define FELEM float -#define FELEM2 float -#define FELEML float -#define WINDOW_TYPE 24 -#elifdef CONFIG_RESAMPLE_S32 -/* s32 template */ -#define FILTER_SHIFT 30 -#define FELEM int32_t -#define FELEM2 int64_t -#define FELEML int64_t -#define FELEM_MAX INT32_MAX -#define FELEM_MIN INT32_MIN -#define WINDOW_TYPE 12 -#else -/* s16 template */ -#define FILTER_SHIFT 15 -#define FELEM int16_t -#define FELEM2 int32_t -#define FELEML int64_t -#define FELEM_MAX INT16_MAX -#define FELEM_MIN INT16_MIN -#define WINDOW_TYPE 9 -#endif - struct ResampleContext { AVAudioResampleContext *avr; AudioData *buffer; - FELEM *filter_bank; + uint8_t *filter_bank; int filter_length; int ideal_dst_incr; int dst_incr; @@ -65,9 +38,35 @@ struct ResampleContext { int phase_shift; int phase_mask; int linear; + enum AVResampleFilterType filter_type; + int kaiser_beta; double factor; + void (*set_filter)(void *filter, double *tab, int phase, int tap_count); + void (*resample_one)(struct ResampleContext *c, int no_filter, void *dst0, + int dst_index, const void *src0, int src_size, + int index, int frac); }; + +/* double template */ +#define CONFIG_RESAMPLE_DBL +#include "resample_template.c" +#undef CONFIG_RESAMPLE_DBL + +/* float template */ +#define CONFIG_RESAMPLE_FLT +#include "resample_template.c" +#undef CONFIG_RESAMPLE_FLT + +/* s32 template */ +#define CONFIG_RESAMPLE_S32 +#include "resample_template.c" +#undef CONFIG_RESAMPLE_S32 + +/* s16 template */ +#include "resample_template.c" + + /** * 0th order modified bessel function of the first kind. */ @@ -95,17 +94,17 @@ static double bessel(double x) * @param tap_count tap count * @param phase_count phase count * @param scale wanted sum of coefficients for each filter - * @param type 0->cubic - * 1->blackman nuttall windowed sinc - * 2..16->kaiser windowed sinc beta=2..16 + * @param filter_type filter type + * @param kaiser_beta kaiser window beta * @return 0 on success, negative AVERROR code on failure */ -static int build_filter(FELEM *filter, double factor, int tap_count, - int phase_count, int scale, int type) +static int build_filter(ResampleContext *c) { int ph, i; - double x, y, w; + double x, y, w, factor; double *tab; + int tap_count = c->filter_length; + int phase_count = 1 << c->phase_shift; const int center = (tap_count - 1) / 2; tab = av_malloc(tap_count * sizeof(*tab)); @@ -113,8 +112,7 @@ static int build_filter(FELEM *filter, double factor, int tap_count, return AVERROR(ENOMEM); /* if upsampling, only need to interpolate, no filter */ - if (factor > 1.0) - factor = 1.0; + factor = FFMIN(c->factor, 1.0); for (ph = 0; ph < phase_count; ph++) { double norm = 0; @@ -122,39 +120,34 @@ static int build_filter(FELEM *filter, double factor, int tap_count, x = M_PI * ((double)(i - center) - (double)ph / phase_count) * factor; if (x == 0) y = 1.0; else y = sin(x) / x; - switch (type) { - case 0: { + switch (c->filter_type) { + case AV_RESAMPLE_FILTER_TYPE_CUBIC: { const float d = -0.5; //first order derivative = -0.5 x = fabs(((double)(i - center) - (double)ph / phase_count) * factor); if (x < 1.0) y = 1 - 3 * x*x + 2 * x*x*x + d * ( -x*x + x*x*x); else y = d * (-4 + 8 * x - 5 * x*x + x*x*x); break; } - case 1: + case AV_RESAMPLE_FILTER_TYPE_BLACKMAN_NUTTALL: w = 2.0 * x / (factor * tap_count) + M_PI; y *= 0.3635819 - 0.4891775 * cos( w) + 0.1365995 * cos(2 * w) - 0.0106411 * cos(3 * w); break; - default: + case AV_RESAMPLE_FILTER_TYPE_KAISER: w = 2.0 * x / (factor * tap_count * M_PI); - y *= bessel(type * sqrt(FFMAX(1 - w * w, 0))); + y *= bessel(c->kaiser_beta * sqrt(FFMAX(1 - w * w, 0))); break; } tab[i] = y; norm += y; } - /* normalize so that an uniform color remains the same */ - for (i = 0; i < tap_count; i++) { -#ifdef CONFIG_RESAMPLE_FLT - filter[ph * tap_count + i] = tab[i] / norm; -#else - filter[ph * tap_count + i] = av_clip(lrintf(tab[i] * scale / norm), - FELEM_MIN, FELEM_MAX); -#endif - } + for (i = 0; i < tap_count; i++) + tab[i] = tab[i] / norm; + + c->set_filter(c->filter_bank, tab, ph, tap_count); } av_free(tab); @@ -168,9 +161,12 @@ ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr) int in_rate = avr->in_sample_rate; double factor = FFMIN(out_rate * avr->cutoff / in_rate, 1.0); int phase_count = 1 << avr->phase_shift; + int felem_size; - /* TODO: add support for s32 and float internal formats */ - if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { + if (avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && + avr->internal_sample_fmt != AV_SAMPLE_FMT_S32P && + avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP && + avr->internal_sample_fmt != AV_SAMPLE_FMT_DBLP) { av_log(avr, AV_LOG_ERROR, "Unsupported internal format for " "resampling: %s\n", av_get_sample_fmt_name(avr->internal_sample_fmt)); @@ -186,18 +182,40 @@ ResampleContext *ff_audio_resample_init(AVAudioResampleContext *avr) c->linear = avr->linear_interp; c->factor = factor; c->filter_length = FFMAX((int)ceil(avr->filter_size / factor), 1); + c->filter_type = avr->filter_type; + c->kaiser_beta = avr->kaiser_beta; + + switch (avr->internal_sample_fmt) { + case AV_SAMPLE_FMT_DBLP: + c->resample_one = resample_one_dbl; + c->set_filter = set_filter_dbl; + break; + case AV_SAMPLE_FMT_FLTP: + c->resample_one = resample_one_flt; + c->set_filter = set_filter_flt; + break; + case AV_SAMPLE_FMT_S32P: + c->resample_one = resample_one_s32; + c->set_filter = set_filter_s32; + break; + case AV_SAMPLE_FMT_S16P: + c->resample_one = resample_one_s16; + c->set_filter = set_filter_s16; + break; + } - c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * sizeof(FELEM)); + felem_size = av_get_bytes_per_sample(avr->internal_sample_fmt); + c->filter_bank = av_mallocz(c->filter_length * (phase_count + 1) * felem_size); if (!c->filter_bank) goto error; - if (build_filter(c->filter_bank, factor, c->filter_length, phase_count, - 1 << FILTER_SHIFT, WINDOW_TYPE) < 0) + if (build_filter(c) < 0) goto error; - memcpy(&c->filter_bank[c->filter_length * phase_count + 1], - c->filter_bank, (c->filter_length - 1) * sizeof(FELEM)); - c->filter_bank[c->filter_length * phase_count] = c->filter_bank[c->filter_length - 1]; + memcpy(&c->filter_bank[(c->filter_length * phase_count + 1) * felem_size], + c->filter_bank, (c->filter_length - 1) * felem_size); + memcpy(&c->filter_bank[c->filter_length * phase_count * felem_size], + &c->filter_bank[(c->filter_length - 1) * felem_size], felem_size); c->compensation_distance = 0; if (!av_reduce(&c->src_incr, &c->dst_incr, out_rate, @@ -311,10 +329,10 @@ reinit_fail: return ret; } -static int resample(ResampleContext *c, int16_t *dst, const int16_t *src, +static int resample(ResampleContext *c, void *dst, const void *src, int *consumed, int src_size, int dst_size, int update_ctx) { - int dst_index, i; + int dst_index; int index = c->index; int frac = c->frac; int dst_incr_frac = c->dst_incr % c->src_incr; @@ -334,7 +352,7 @@ static int resample(ResampleContext *c, int16_t *dst, const int16_t *src, if (dst) { for(dst_index = 0; dst_index < dst_size; dst_index++) { - dst[dst_index] = src[index2 >> 32]; + c->resample_one(c, 1, dst, dst_index, src, 0, index2 >> 32, 0); index2 += incr; } } else { @@ -345,42 +363,14 @@ static int resample(ResampleContext *c, int16_t *dst, const int16_t *src, frac = (frac + dst_index * (int64_t)dst_incr_frac) % c->src_incr; } else { for (dst_index = 0; dst_index < dst_size; dst_index++) { - FELEM *filter = c->filter_bank + - c->filter_length * (index & c->phase_mask); int sample_index = index >> c->phase_shift; - if (!dst && (sample_index + c->filter_length > src_size || - -sample_index >= src_size)) + if (sample_index + c->filter_length > src_size || + -sample_index >= src_size) break; - if (dst) { - FELEM2 val = 0; - - if (sample_index < 0) { - for (i = 0; i < c->filter_length; i++) - val += src[FFABS(sample_index + i) % src_size] * - (FELEM2)filter[i]; - } else if (sample_index + c->filter_length > src_size) { - break; - } else if (c->linear) { - FELEM2 v2 = 0; - for (i = 0; i < c->filter_length; i++) { - val += src[abs(sample_index + i)] * (FELEM2)filter[i]; - v2 += src[abs(sample_index + i)] * (FELEM2)filter[i + c->filter_length]; - } - val += (v2 - val) * (FELEML)frac / c->src_incr; - } else { - for (i = 0; i < c->filter_length; i++) - val += src[sample_index + i] * (FELEM2)filter[i]; - } - -#ifdef CONFIG_RESAMPLE_FLT - dst[dst_index] = av_clip_int16(lrintf(val)); -#else - val = (val + (1<<(FILTER_SHIFT-1)))>>FILTER_SHIFT; - dst[dst_index] = av_clip_int16(val); -#endif - } + if (dst) + c->resample_one(c, 0, dst, dst_index, src, src_size, index, frac); frac += dst_incr_frac; index += dst_incr; @@ -451,8 +441,8 @@ int ff_audio_resample(ResampleContext *c, AudioData *dst, AudioData *src, /* resample each channel plane */ for (ch = 0; ch < c->buffer->channels; ch++) { - out_samples = resample(c, (int16_t *)dst->data[ch], - (const int16_t *)c->buffer->data[ch], consumed, + out_samples = resample(c, (void *)dst->data[ch], + (const void *)c->buffer->data[ch], consumed, c->buffer->nb_samples, dst->allocated_samples, ch + 1 == c->buffer->channels); } diff --git a/libavresample/resample_template.c b/libavresample/resample_template.c new file mode 100644 index 0000000000..06da90fe9f --- /dev/null +++ b/libavresample/resample_template.c @@ -0,0 +1,102 @@ +/* + * Copyright (c) 2004 Michael Niedermayer <michaelni@gmx.at> + * + * 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 + */ + +#if defined(CONFIG_RESAMPLE_DBL) +#define SET_TYPE(func) func ## _dbl +#define FELEM double +#define FELEM2 double +#define FELEML double +#define OUT(d, v) d = v +#define DBL_TO_FELEM(d, v) d = v +#elif defined(CONFIG_RESAMPLE_FLT) +#define SET_TYPE(func) func ## _flt +#define FELEM float +#define FELEM2 float +#define FELEML float +#define OUT(d, v) d = v +#define DBL_TO_FELEM(d, v) d = v +#elif defined(CONFIG_RESAMPLE_S32) +#define SET_TYPE(func) func ## _s32 +#define FELEM int32_t +#define FELEM2 int64_t +#define FELEML int64_t +#define OUT(d, v) d = av_clipl_int32((v + (1 << 29)) >> 30) +#define DBL_TO_FELEM(d, v) d = av_clipl_int32(llrint(v * (1 << 30))); +#else +#define SET_TYPE(func) func ## _s16 +#define FELEM int16_t +#define FELEM2 int32_t +#define FELEML int64_t +#define OUT(d, v) d = av_clip_int16((v + (1 << 14)) >> 15) +#define DBL_TO_FELEM(d, v) d = av_clip_int16(lrint(v * (1 << 15))) +#endif + +static void SET_TYPE(resample_one)(ResampleContext *c, int no_filter, + void *dst0, int dst_index, const void *src0, + int src_size, int index, int frac) +{ + FELEM *dst = dst0; + const FELEM *src = src0; + + if (no_filter) { + dst[dst_index] = src[index]; + } else { + int i; + int sample_index = index >> c->phase_shift; + FELEM2 val = 0; + FELEM *filter = ((FELEM *)c->filter_bank) + + c->filter_length * (index & c->phase_mask); + + if (sample_index < 0) { + for (i = 0; i < c->filter_length; i++) + val += src[FFABS(sample_index + i) % src_size] * + (FELEM2)filter[i]; + } else if (c->linear) { + FELEM2 v2 = 0; + for (i = 0; i < c->filter_length; i++) { + val += src[abs(sample_index + i)] * (FELEM2)filter[i]; + v2 += src[abs(sample_index + i)] * (FELEM2)filter[i + c->filter_length]; + } + val += (v2 - val) * (FELEML)frac / c->src_incr; + } else { + for (i = 0; i < c->filter_length; i++) + val += src[sample_index + i] * (FELEM2)filter[i]; + } + + OUT(dst[dst_index], val); + } +} + +static void SET_TYPE(set_filter)(void *filter0, double *tab, int phase, + int tap_count) +{ + int i; + FELEM *filter = ((FELEM *)filter0) + phase * tap_count; + for (i = 0; i < tap_count; i++) { + DBL_TO_FELEM(filter[i], tab[i]); + } +} + +#undef SET_TYPE +#undef FELEM +#undef FELEM2 +#undef FELEML +#undef OUT +#undef DBL_TO_FELEM diff --git a/libavresample/utils.c b/libavresample/utils.c index 21bb9309b3..caf9081e5d 100644 --- a/libavresample/utils.c +++ b/libavresample/utils.c @@ -57,18 +57,43 @@ int avresample_open(AVAudioResampleContext *avr) avr->resample_needed = avr->in_sample_rate != avr->out_sample_rate || avr->force_resampling; - /* set sample format conversion parameters */ - /* override user-requested internal format to avoid unexpected failures - TODO: support more internal formats */ - if (avr->resample_needed && avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P) { - av_log(avr, AV_LOG_WARNING, "Using s16p as internal sample format\n"); - avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; - } else if (avr->mixing_needed && - avr->internal_sample_fmt != AV_SAMPLE_FMT_S16P && - avr->internal_sample_fmt != AV_SAMPLE_FMT_FLTP) { - av_log(avr, AV_LOG_WARNING, "Using fltp as internal sample format\n"); - avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; + /* select internal sample format if not specified by the user */ + if (avr->internal_sample_fmt == AV_SAMPLE_FMT_NONE && + (avr->mixing_needed || avr->resample_needed)) { + enum AVSampleFormat in_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); + enum AVSampleFormat out_fmt = av_get_planar_sample_fmt(avr->out_sample_fmt); + int max_bps = FFMAX(av_get_bytes_per_sample(in_fmt), + av_get_bytes_per_sample(out_fmt)); + if (max_bps <= 2) { + avr->internal_sample_fmt = AV_SAMPLE_FMT_S16P; + } else if (avr->mixing_needed) { + avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; + } else { + if (max_bps <= 4) { + if (in_fmt == AV_SAMPLE_FMT_S32P || + out_fmt == AV_SAMPLE_FMT_S32P) { + if (in_fmt == AV_SAMPLE_FMT_FLTP || + out_fmt == AV_SAMPLE_FMT_FLTP) { + /* if one is s32 and the other is flt, use dbl */ + avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; + } else { + /* if one is s32 and the other is s32, s16, or u8, use s32 */ + avr->internal_sample_fmt = AV_SAMPLE_FMT_S32P; + } + } else { + /* if one is flt and the other is flt, s16 or u8, use flt */ + avr->internal_sample_fmt = AV_SAMPLE_FMT_FLTP; + } + } else { + /* if either is dbl, use dbl */ + avr->internal_sample_fmt = AV_SAMPLE_FMT_DBLP; + } + } + av_log(avr, AV_LOG_DEBUG, "Using %s as internal sample format\n", + av_get_sample_fmt_name(avr->internal_sample_fmt)); } + + /* set sample format conversion parameters */ if (avr->in_channels == 1) avr->in_sample_fmt = av_get_planar_sample_fmt(avr->in_sample_fmt); if (avr->out_channels == 1) diff --git a/tests/fate-run.sh b/tests/fate-run.sh index 39981c1332..ccd04a3108 100755 --- a/tests/fate-run.sh +++ b/tests/fate-run.sh @@ -75,7 +75,13 @@ probefmt(){ } ffmpeg(){ - run ffmpeg -nostats -threads $threads -thread_type $thread_type -cpuflags $cpuflags "$@" + dec_opts="-threads $threads -thread_type $thread_type" + ffmpeg_args="-nostats -cpuflags $cpuflags" + for arg in $@; do + [ ${arg} = -i ] && ffmpeg_args="${ffmpeg_args} ${dec_opts}" + ffmpeg_args="${ffmpeg_args} ${arg}" + done + run ffmpeg ${ffmpeg_args} } framecrc(){ |