From 775af761a0805b2523923636020c5aebf764af13 Mon Sep 17 00:00:00 2001 From: Anton Khirnov Date: Wed, 21 Sep 2011 20:25:19 +0200 Subject: [PATCH 01/14] eval: test isnan(sqrt(-1)) instead of just sqrt(-1) sqrt(-1) returns "some NaN", it's not specified which exactly. --- libavutil/eval.c | 2 +- tests/ref/fate/eval | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/libavutil/eval.c b/libavutil/eval.c index 4126cd7f69..9941ed7060 100644 --- a/libavutil/eval.c +++ b/libavutil/eval.c @@ -608,7 +608,7 @@ int main(int argc, char **argv) "ceil(123.123)", "ceil(-123.123)", "sqrt(1764)", - "sqrt(-1)", + "isnan(sqrt(-1))", "not(1)", "not(NAN)", "not(0)", diff --git a/tests/ref/fate/eval b/tests/ref/fate/eval index 0e4844efc5..ef50292024 100644 --- a/tests/ref/fate/eval +++ b/tests/ref/fate/eval @@ -136,8 +136,8 @@ Evaluating 'ceil(-123.123)' Evaluating 'sqrt(1764)' 'sqrt(1764)' -> 42.000000 -Evaluating 'sqrt(-1)' -'sqrt(-1)' -> -nan +Evaluating 'isnan(sqrt(-1))' +'isnan(sqrt(-1))' -> 1.000000 Evaluating 'not(1)' 'not(1)' -> 0.000000 From fe476e5a9b5a1e56e53f1fa62374778fa00ec1fd Mon Sep 17 00:00:00 2001 From: Laurent Aimar Date: Wed, 21 Sep 2011 20:46:31 +0200 Subject: [PATCH 02/14] rv34: Check for invalid slices offsets MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- libavcodec/rv34.c | 11 ++++++++++- 1 file changed, 10 insertions(+), 1 deletion(-) diff --git a/libavcodec/rv34.c b/libavcodec/rv34.c index a760e5e147..abdfce50a5 100644 --- a/libavcodec/rv34.c +++ b/libavcodec/rv34.c @@ -1513,13 +1513,18 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, else size = get_slice_offset(avctx, slices_hdr, i+1) - offset; - if(offset < 0 || offset > buf_size || size < 0){ + if(offset < 0 || offset > buf_size){ av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); break; } r->si.end = s->mb_width * s->mb_height; if(i+1 < slice_count){ + if (get_slice_offset(avctx, slices_hdr, i+1) < 0 || + get_slice_offset(avctx, slices_hdr, i+1) > buf_size) { + av_log(avctx, AV_LOG_ERROR, "Slice offset is invalid\n"); + break; + } init_get_bits(&s->gb, buf+get_slice_offset(avctx, slices_hdr, i+1), (buf_size-get_slice_offset(avctx, slices_hdr, i+1))*8); if(r->parse_slice_header(r, &r->s.gb, &si) < 0){ if(i+2 < slice_count) @@ -1529,6 +1534,10 @@ int ff_rv34_decode_frame(AVCodecContext *avctx, }else r->si.end = si.start; } + if (size < 0 || size > buf_size - offset) { + av_log(avctx, AV_LOG_ERROR, "Slice size is invalid\n"); + break; + } last = rv34_decode_slice(r, r->si.end, buf + offset, size); s->mb_num_left = r->s.mb_x + r->s.mb_y*r->s.mb_width - r->si.start; if(last) From b14629e5eafb34dd71702aa42863388438060cd1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Martin=20Storsj=C3=B6?= Date: Wed, 21 Sep 2011 23:21:30 +0300 Subject: [PATCH 03/14] rtmp: Make the input FLV parser handle data cut at any point MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This makes the RTMP writing code able to handle FLV data fed in arbitrarily small or large chunks, with multiple consecutive packets in one write call, or having the FLV packet header split over numerous write calls. When used in conjunction with the flv muxer, the AVIO buffer size still needs to be large enough to fit the initial metadata packet though, since the size of that packet is written with a seekback. Signed-off-by: Martin Storsjö --- libavformat/rtmpproto.c | 61 ++++++++++++++++++----------------------- 1 file changed, 27 insertions(+), 34 deletions(-) diff --git a/libavformat/rtmpproto.c b/libavformat/rtmpproto.c index a8be052fa0..093d21a585 100644 --- a/libavformat/rtmpproto.c +++ b/libavformat/rtmpproto.c @@ -72,6 +72,8 @@ typedef struct RTMPContext { uint32_t bytes_read; ///< number of bytes read from server uint32_t last_bytes_read; ///< number of bytes read last reported to server int skip_bytes; ///< number of bytes to skip from the input FLV stream in the next write call + uint8_t flv_header[11]; ///< partial incoming flv packet header + int flv_header_bytes; ///< number of initialized bytes in flv_header } RTMPContext; #define PLAYER_KEY_OPEN_PART_LEN 30 ///< length of partial key used for first client digest signing @@ -880,6 +882,7 @@ static int rtmp_open(URLContext *s, const char *uri, int flags) rt->flv_size = 0; rt->flv_data = NULL; rt->flv_off = 0; + rt->skip_bytes = 13; } s->max_packet_size = rt->stream->max_packet_size; @@ -926,34 +929,29 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) uint32_t ts; const uint8_t *buf_temp = buf; - if (rt->skip_bytes) { - int skip = FFMIN(rt->skip_bytes, size); - buf_temp += skip; - size_temp -= skip; - rt->skip_bytes -= skip; - if (size_temp <= 0) - return size; - } - - if (!rt->flv_off && size_temp < 11) { - av_log(s, AV_LOG_DEBUG, "FLV packet too small %d\n", size); - return 0; - } - do { - if (!rt->flv_off) { - //skip flv header - if (buf_temp[0] == 'F' && buf_temp[1] == 'L' && buf_temp[2] == 'V') { - buf_temp += 9 + 4; - size_temp -= 9 + 4; - } + if (rt->skip_bytes) { + int skip = FFMIN(rt->skip_bytes, size_temp); + buf_temp += skip; + size_temp -= skip; + rt->skip_bytes -= skip; + continue; + } + + if (rt->flv_header_bytes < 11) { + const uint8_t *header = rt->flv_header; + int copy = FFMIN(11 - rt->flv_header_bytes, size_temp); + bytestream_get_buffer(&buf_temp, rt->flv_header + rt->flv_header_bytes, copy); + rt->flv_header_bytes += copy; + size_temp -= copy; + if (rt->flv_header_bytes < 11) + break; - pkttype = bytestream_get_byte(&buf_temp); - pktsize = bytestream_get_be24(&buf_temp); - ts = bytestream_get_be24(&buf_temp); - ts |= bytestream_get_byte(&buf_temp) << 24; - bytestream_get_be24(&buf_temp); - size_temp -= 11; + pkttype = bytestream_get_byte(&header); + pktsize = bytestream_get_be24(&header); + ts = bytestream_get_be24(&header); + ts |= bytestream_get_byte(&header) << 24; + bytestream_get_be24(&header); rt->flv_size = pktsize; //force 12bytes header @@ -984,18 +982,13 @@ static int rtmp_write(URLContext *s, const uint8_t *buf, int size) } if (rt->flv_off == rt->flv_size) { - if (size_temp < 4) { - rt->skip_bytes = 4 - size_temp; - buf_temp += size_temp; - size_temp = 0; - } else { - bytestream_get_be32(&buf_temp); - size_temp -= 4; - } + rt->skip_bytes = 4; + ff_rtmp_packet_write(rt->stream, &rt->out_pkt, rt->chunk_size, rt->prev_pkt[1]); ff_rtmp_packet_destroy(&rt->out_pkt); rt->flv_size = 0; rt->flv_off = 0; + rt->flv_header_bytes = 0; } } while (buf_temp - buf < size); return size; From be64629a135642f20325e1422352707bb81d5c91 Mon Sep 17 00:00:00 2001 From: Maxim Poliakovski Date: Wed, 21 Sep 2011 13:09:32 +0200 Subject: [PATCH 04/14] Apple ProRes decoder MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Signed-off-by: Martin Storsjö --- Changelog | 1 + doc/general.texi | 1 + libavcodec/Makefile | 1 + libavcodec/allcodecs.c | 1 + libavcodec/proresdec.c | 733 +++++++++++++++++++++++++++++++++++++++++ libavcodec/version.h | 2 +- 6 files changed, 738 insertions(+), 1 deletion(-) create mode 100644 libavcodec/proresdec.c diff --git a/Changelog b/Changelog index 24fa85c898..3cd2c0de05 100644 --- a/Changelog +++ b/Changelog @@ -47,6 +47,7 @@ easier to use. The changes are: - split filter - libcdio-paranoia input device for audio CD grabbing - select filter +- Apple ProRes decoder version 0.7: diff --git a/doc/general.texi b/doc/general.texi index 50278e1eee..2c463cb53e 100644 --- a/doc/general.texi +++ b/doc/general.texi @@ -341,6 +341,7 @@ following image formats are supported: @tab Used in Chinese MP3 players. @item ANSI/ASCII art @tab @tab X @item Apple MJPEG-B @tab @tab X +@item Apple ProRes @tab @tab X @item Apple QuickDraw @tab @tab X @tab fourcc: qdrw @item Asus v1 @tab X @tab X diff --git a/libavcodec/Makefile b/libavcodec/Makefile index 7697f731b2..3c4e2f84b9 100644 --- a/libavcodec/Makefile +++ b/libavcodec/Makefile @@ -295,6 +295,7 @@ OBJS-$(CONFIG_PNG_DECODER) += png.o pngdec.o OBJS-$(CONFIG_PNG_ENCODER) += png.o pngenc.o OBJS-$(CONFIG_PPM_DECODER) += pnmdec.o pnm.o OBJS-$(CONFIG_PPM_ENCODER) += pnmenc.o pnm.o +OBJS-$(CONFIG_PRORES_DECODER) += proresdec.o OBJS-$(CONFIG_PTX_DECODER) += ptx.o OBJS-$(CONFIG_QCELP_DECODER) += qcelpdec.o celp_math.o \ celp_filters.o acelp_vectors.o \ diff --git a/libavcodec/allcodecs.c b/libavcodec/allcodecs.c index b483f81aa2..fdb0a9cba8 100644 --- a/libavcodec/allcodecs.c +++ b/libavcodec/allcodecs.c @@ -164,6 +164,7 @@ void avcodec_register_all(void) REGISTER_DECODER (PICTOR, pictor); REGISTER_ENCDEC (PNG, png); REGISTER_ENCDEC (PPM, ppm); + REGISTER_DECODER (PRORES, prores); REGISTER_DECODER (PTX, ptx); REGISTER_DECODER (QDRAW, qdraw); REGISTER_DECODER (QPEG, qpeg); diff --git a/libavcodec/proresdec.c b/libavcodec/proresdec.c new file mode 100644 index 0000000000..057089851c --- /dev/null +++ b/libavcodec/proresdec.c @@ -0,0 +1,733 @@ +/* + * Apple ProRes compatible decoder + * + * Copyright (c) 2010-2011 Maxim Poliakovski + * + * 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 + * This is a decoder for Apple ProRes 422 SD/HQ/LT/Proxy and ProRes 4444. + * It is used for storing and editing high definition video data in Apple's Final Cut Pro. + * + * @see http://wiki.multimedia.cx/index.php?title=Apple_ProRes + */ + +#define A32_BITSTREAM_READER // some ProRes vlc codes require up to 28 bits to be read at once + +#include + +#include "libavutil/intmath.h" +#include "avcodec.h" +#include "dsputil.h" +#include "get_bits.h" + +#define BITS_PER_SAMPLE 10 ///< output precision of that decoder +#define BIAS (1 << (BITS_PER_SAMPLE - 1)) ///< bias value for converting signed pixels into unsigned ones +#define CLIP_MIN (1 << (BITS_PER_SAMPLE - 8)) ///< minimum value for clipping resulting pixels +#define CLIP_MAX (1 << BITS_PER_SAMPLE) - CLIP_MIN - 1 ///< maximum value for clipping resulting pixels + + +typedef struct { + DSPContext dsp; + AVFrame picture; + ScanTable scantable; + int scantable_type; ///< -1 = uninitialized, 0 = progressive, 1/2 = interlaced + + int frame_type; ///< 0 = progressive, 1 = top-field first, 2 = bottom-field first + int pic_format; ///< 2 = 422, 3 = 444 + uint8_t qmat_luma[64]; ///< dequantization matrix for luma + uint8_t qmat_chroma[64]; ///< dequantization matrix for chroma + int qmat_changed; ///< 1 - global quantization matrices changed + int prev_slice_sf; ///< scalefactor of the previous decoded slice + DECLARE_ALIGNED(16, int16_t, qmat_luma_scaled[64]); + DECLARE_ALIGNED(16, int16_t, qmat_chroma_scaled[64]); + DECLARE_ALIGNED(16, DCTELEM, blocks[8 * 4 * 64]); + int total_slices; ///< total number of slices in a picture + const uint8_t **slice_data_index; ///< array of pointers to the data of each slice + int chroma_factor; + int mb_chroma_factor; + int num_chroma_blocks; ///< number of chrominance blocks in a macroblock + int num_x_slices; + int num_y_slices; + int slice_width_factor; + int slice_height_factor; + int num_x_mbs; + int num_y_mbs; +} ProresContext; + + +static const uint8_t progressive_scan[64] = { + 0, 1, 8, 9, 2, 3, 10, 11, + 16, 17, 24, 25, 18, 19, 26, 27, + 4, 5, 12, 20, 13, 6, 7, 14, + 21, 28, 29, 22, 15, 23, 30, 31, + 32, 33, 40, 48, 41, 34, 35, 42, + 49, 56, 57, 50, 43, 36, 37, 44, + 51, 58, 59, 52, 45, 38, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +static const uint8_t interlaced_scan[64] = { + 0, 8, 1, 9, 16, 24, 17, 25, + 2, 10, 3, 11, 18, 26, 19, 27, + 32, 40, 33, 34, 41, 48, 56, 49, + 42, 35, 43, 50, 57, 58, 51, 59, + 4, 12, 5, 6, 13, 20, 28, 21, + 14, 7, 15, 22, 29, 36, 44, 37, + 30, 23, 31, 38, 45, 52, 60, 53, + 46, 39, 47, 54, 61, 62, 55, 63 +}; + + +static av_cold int decode_init(AVCodecContext *avctx) +{ + ProresContext *ctx = avctx->priv_data; + + ctx->total_slices = 0; + ctx->slice_data_index = 0; + + avctx->pix_fmt = PIX_FMT_YUV422P10; // set default pixel format + + avctx->bits_per_raw_sample = BITS_PER_SAMPLE; + dsputil_init(&ctx->dsp, avctx); + + avctx->coded_frame = &ctx->picture; + avcodec_get_frame_defaults(&ctx->picture); + ctx->picture.type = AV_PICTURE_TYPE_I; + ctx->picture.key_frame = 1; + + ctx->scantable_type = -1; // set scantable type to uninitialized + memset(ctx->qmat_luma, 4, 64); + memset(ctx->qmat_chroma, 4, 64); + ctx->prev_slice_sf = 0; + + return 0; +} + + +static int decode_frame_header(ProresContext *ctx, const uint8_t *buf, + const int data_size, AVCodecContext *avctx) +{ + int hdr_size, version, width, height, flags; + const uint8_t *ptr; + + hdr_size = AV_RB16(buf); + if (hdr_size > data_size) { + av_log(avctx, AV_LOG_ERROR, "frame data too short!\n"); + return -1; + } + + version = AV_RB16(buf + 2); + if (version >= 2) { + av_log(avctx, AV_LOG_ERROR, + "unsupported header version: %d\n", version); + return -1; + } + + width = AV_RB16(buf + 8); + height = AV_RB16(buf + 10); + if (width != avctx->width || height != avctx->height) { + av_log(avctx, AV_LOG_ERROR, + "picture dimension changed! Old: %d x %d, new: %d x %d\n", + avctx->width, avctx->height, width, height); + return -1; + } + + ctx->frame_type = (buf[12] >> 2) & 3; + if (ctx->frame_type > 2) { + av_log(avctx, AV_LOG_ERROR, + "unsupported frame type: %d!\n", ctx->frame_type); + return -1; + } + + ctx->chroma_factor = (buf[12] >> 6) & 3; + ctx->mb_chroma_factor = ctx->chroma_factor + 2; + ctx->num_chroma_blocks = (1 << ctx->chroma_factor) >> 1; + switch (ctx->chroma_factor) { + case 2: + avctx->pix_fmt = PIX_FMT_YUV422P10; + break; + case 3: + avctx->pix_fmt = PIX_FMT_YUV444P10; + break; + default: + av_log(avctx, AV_LOG_ERROR, + "unsupported picture format: %d!\n", ctx->pic_format); + return -1; + } + + if (ctx->scantable_type != ctx->frame_type) { + if (!ctx->frame_type) + ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, + progressive_scan); + else + ff_init_scantable(ctx->dsp.idct_permutation, &ctx->scantable, + interlaced_scan); + ctx->scantable_type = ctx->frame_type; + } + + if (ctx->frame_type) { /* if interlaced */ + ctx->picture.interlaced_frame = 1; + ctx->picture.top_field_first = ctx->frame_type & 1; + } + + ctx->qmat_changed = 0; + ptr = buf + 20; + flags = buf[19]; + if (flags & 2) { + if (ptr - buf > hdr_size - 64) { + av_log(avctx, AV_LOG_ERROR, "Too short header data\n"); + return -1; + } + if (memcmp(ctx->qmat_luma, ptr, 64)) { + memcpy(ctx->qmat_luma, ptr, 64); + ctx->qmat_changed = 1; + } + ptr += 64; + } else { + memset(ctx->qmat_luma, 4, 64); + ctx->qmat_changed = 1; + } + + if (flags & 1) { + if (ptr - buf > hdr_size - 64) { + av_log(avctx, AV_LOG_ERROR, "Too short header data\n"); + return -1; + } + if (memcmp(ctx->qmat_chroma, ptr, 64)) { + memcpy(ctx->qmat_chroma, ptr, 64); + ctx->qmat_changed = 1; + } + } else { + memset(ctx->qmat_chroma, 4, 64); + ctx->qmat_changed = 1; + } + + return hdr_size; +} + + +static int decode_picture_header(ProresContext *ctx, const uint8_t *buf, + const int data_size, AVCodecContext *avctx) +{ + int i, hdr_size, pic_data_size, num_slices; + int slice_width_factor, slice_height_factor; + int remainder, num_x_slices; + const uint8_t *data_ptr, *index_ptr; + + hdr_size = data_size > 0 ? buf[0] >> 3 : 0; + if (hdr_size < 8 || hdr_size > data_size) { + av_log(avctx, AV_LOG_ERROR, "picture header too short!\n"); + return -1; + } + + pic_data_size = AV_RB32(buf + 1); + if (pic_data_size > data_size) { + av_log(avctx, AV_LOG_ERROR, "picture data too short!\n"); + return -1; + } + + slice_width_factor = buf[7] >> 4; + slice_height_factor = buf[7] & 0xF; + if (slice_width_factor > 3 || slice_height_factor) { + av_log(avctx, AV_LOG_ERROR, + "unsupported slice dimension: %d x %d!\n", + 1 << slice_width_factor, 1 << slice_height_factor); + return -1; + } + + ctx->slice_width_factor = slice_width_factor; + ctx->slice_height_factor = slice_height_factor; + + ctx->num_x_mbs = (avctx->width + 15) >> 4; + ctx->num_y_mbs = + (avctx->height + (1 << (4 + ctx->picture.interlaced_frame)) - 1) >> + (4 + ctx->picture.interlaced_frame); + + remainder = ctx->num_x_mbs & ((1 << slice_width_factor) - 1); + num_x_slices = (ctx->num_x_mbs >> slice_width_factor) + (remainder & 1) + + ((remainder >> 1) & 1) + ((remainder >> 2) & 1); + + num_slices = num_x_slices * ctx->num_y_mbs; + if (num_slices != AV_RB16(buf + 5)) { + av_log(avctx, AV_LOG_ERROR, "invalid number of slices!\n"); + return -1; + } + + if (ctx->total_slices != num_slices) { + av_freep(&ctx->slice_data_index); + ctx->slice_data_index = + av_malloc((num_slices + 1) * sizeof(uint8_t*)); + if (!ctx->slice_data_index) + return AVERROR(ENOMEM); + ctx->total_slices = num_slices; + } + + if (hdr_size + num_slices * 2 > data_size) { + av_log(avctx, AV_LOG_ERROR, "slice table too short!\n"); + return -1; + } + + /* parse slice table allowing quick access to the slice data */ + index_ptr = buf + hdr_size; + data_ptr = index_ptr + num_slices * 2; + + for (i = 0; i < num_slices; i++) { + ctx->slice_data_index[i] = data_ptr; + data_ptr += AV_RB16(index_ptr + i * 2); + } + ctx->slice_data_index[i] = data_ptr; + + if (data_ptr > buf + data_size) { + av_log(avctx, AV_LOG_ERROR, "out of slice data!\n"); + return -1; + } + + return pic_data_size; +} + + +/** + * Read an unsigned rice/exp golomb codeword. + */ +static inline int decode_vlc_codeword(GetBitContext *gb, uint8_t codebook) +{ + unsigned int rice_order, exp_order, switch_bits; + unsigned int buf, code; + int log, prefix_len, len; + + OPEN_READER(re, gb); + UPDATE_CACHE(re, gb); + buf = GET_CACHE(re, gb); + + /* number of prefix bits to switch between Rice and expGolomb */ + switch_bits = (codebook & 3) + 1; + rice_order = codebook >> 5; /* rice code order */ + exp_order = (codebook >> 2) & 7; /* exp golomb code order */ + + log = 31 - av_log2(buf); /* count prefix bits (zeroes) */ + + if (log < switch_bits) { /* ok, we got a rice code */ + if (!rice_order) { + /* shortcut for faster decoding of rice codes without remainder */ + code = log; + LAST_SKIP_BITS(re, gb, log + 1); + } else { + prefix_len = log + 1; + code = (log << rice_order) + NEG_USR32((buf << prefix_len), rice_order); + LAST_SKIP_BITS(re, gb, prefix_len + rice_order); + } + } else { /* otherwise we got a exp golomb code */ + len = (log << 1) - switch_bits + exp_order + 1; + code = NEG_USR32(buf, len) - (1 << exp_order) + (switch_bits << rice_order); + LAST_SKIP_BITS(re, gb, len); + } + + CLOSE_READER(re, gb); + + return code; +} + +#define LSB2SIGN(x) (-((x) & 1)) +#define TOSIGNED(x) (((x) >> 1) ^ LSB2SIGN(x)) + +#define FIRST_DC_CB 0xB8 // rice_order = 5, exp_golomb_order = 6, switch_bits = 0 + +static uint8_t dc_codebook[4] = { + 0x04, // rice_order = 0, exp_golomb_order = 1, switch_bits = 0 + 0x28, // rice_order = 1, exp_golomb_order = 2, switch_bits = 0 + 0x4D, // rice_order = 2, exp_golomb_order = 3, switch_bits = 1 + 0x70 // rice_order = 3, exp_golomb_order = 4, switch_bits = 0 +}; + + +/** + * Decode DC coefficients for all blocks in a slice. + */ +static inline void decode_dc_coeffs(GetBitContext *gb, DCTELEM *out, + int nblocks) +{ + DCTELEM prev_dc; + int i, sign; + int16_t delta; + unsigned int code; + + code = decode_vlc_codeword(gb, FIRST_DC_CB); + out[0] = prev_dc = TOSIGNED(code); + + out += 64; /* move to the DC coeff of the next block */ + delta = 3; + + for (i = 1; i < nblocks; i++, out += 64) { + code = decode_vlc_codeword(gb, dc_codebook[FFMIN(FFABS(delta), 3)]); + + sign = -(((delta >> 15) & 1) ^ (code & 1)); + delta = (((code + 1) >> 1) ^ sign) - sign; + prev_dc += delta; + out[0] = prev_dc; + } +} + + +static uint8_t ac_codebook[7] = { + 0x04, // rice_order = 0, exp_golomb_order = 1, switch_bits = 0 + 0x28, // rice_order = 1, exp_golomb_order = 2, switch_bits = 0 + 0x4C, // rice_order = 2, exp_golomb_order = 3, switch_bits = 0 + 0x05, // rice_order = 0, exp_golomb_order = 1, switch_bits = 1 + 0x29, // rice_order = 1, exp_golomb_order = 2, switch_bits = 1 + 0x06, // rice_order = 0, exp_golomb_order = 1, switch_bits = 2 + 0x0A, // rice_order = 0, exp_golomb_order = 2, switch_bits = 2 +}; + +/** + * Lookup tables for adaptive switching between codebooks + * according with previous run/level value. + */ +static uint8_t run_to_cb_index[16] = + { 5, 5, 3, 3, 0, 4, 4, 4, 4, 1, 1, 1, 1, 1, 1, 2 }; + +static uint8_t lev_to_cb_index[10] = { 0, 6, 3, 5, 0, 1, 1, 1, 1, 2 }; + + +/** + * Decode AC coefficients for all blocks in a slice. + */ +static inline void decode_ac_coeffs(GetBitContext *gb, DCTELEM *out, + int blocks_per_slice, + int plane_size_factor, + const uint8_t *scan) +{ + int pos, block_mask, run, level, sign, run_cb_index, lev_cb_index; + int max_coeffs, bits_left; + + /* set initial prediction values */ + run = 4; + level = 2; + + max_coeffs = blocks_per_slice << 6; + block_mask = blocks_per_slice - 1; + + for (pos = blocks_per_slice - 1; pos < max_coeffs;) { + run_cb_index = run_to_cb_index[FFMIN(run, 15)]; + lev_cb_index = lev_to_cb_index[FFMIN(level, 9)]; + + bits_left = get_bits_left(gb); + if (bits_left <= 8 && !show_bits(gb, bits_left)) + return; + + run = decode_vlc_codeword(gb, ac_codebook[run_cb_index]); + + bits_left = get_bits_left(gb); + if (bits_left <= 8 && !show_bits(gb, bits_left)) + return; + + level = decode_vlc_codeword(gb, ac_codebook[lev_cb_index]) + 1; + + pos += run + 1; + if (pos >= max_coeffs) + break; + + sign = get_sbits(gb, 1); + out[((pos & block_mask) << 6) + scan[pos >> plane_size_factor]] = + (level ^ sign) - sign; + } +} + + +#define CLIP_AND_BIAS(x) (av_clip((x) + BIAS, CLIP_MIN, CLIP_MAX)) + +/** + * Add bias value, clamp and output pixels of a slice + */ +static void put_pixels(const DCTELEM *in, uint16_t *out, int stride, + int mbs_per_slice, int blocks_per_mb) +{ + int mb, x, y, src_offset, dst_offset; + const DCTELEM *src1, *src2; + uint16_t *dst1, *dst2; + + src1 = in; + src2 = in + (blocks_per_mb << 5); + dst1 = out; + dst2 = out + (stride << 3); + + for (mb = 0; mb < mbs_per_slice; mb++) { + for (y = 0, dst_offset = 0; y < 8; y++, dst_offset += stride) { + for (x = 0; x < 8; x++) { + src_offset = (y << 3) + x; + + dst1[dst_offset + x] = CLIP_AND_BIAS(src1[src_offset]); + dst2[dst_offset + x] = CLIP_AND_BIAS(src2[src_offset]); + + if (blocks_per_mb > 2) { + dst1[dst_offset + x + 8] = + CLIP_AND_BIAS(src1[src_offset + 64]); + dst2[dst_offset + x + 8] = + CLIP_AND_BIAS(src2[src_offset + 64]); + } + } + } + + src1 += blocks_per_mb << 6; + src2 += blocks_per_mb << 6; + dst1 += blocks_per_mb << 2; + dst2 += blocks_per_mb << 2; + } +} + + +/** + * Decode a slice plane (luma or chroma). + */ +static void decode_slice_plane(ProresContext *ctx, const uint8_t *buf, + int data_size, uint16_t *out_ptr, + int linesize, int mbs_per_slice, + int blocks_per_mb, int plane_size_factor, + const int16_t *qmat) +{ + GetBitContext gb; + DCTELEM *block_ptr; + int i, blk_num, blocks_per_slice; + + blocks_per_slice = mbs_per_slice * blocks_per_mb; + + memset(ctx->blocks, 0, 8 * 4 * 64 * sizeof(*ctx->blocks)); + + init_get_bits(&gb, buf, data_size << 3); + + decode_dc_coeffs(&gb, ctx->blocks, blocks_per_slice); + + decode_ac_coeffs(&gb, ctx->blocks, blocks_per_slice, + plane_size_factor, ctx->scantable.permutated); + + /* inverse quantization, inverse transform and output */ + block_ptr = ctx->blocks; + + for (blk_num = 0; blk_num < blocks_per_slice; + blk_num++, block_ptr += 64) { + /* TODO: the correct solution shoud be (block_ptr[i] * qmat[i]) >> 1 + * and the input of the inverse transform should be scaled by 2 + * in order to avoid rounding errors. + * Due to the fact the existing Libav transforms are incompatible with + * that input I temporally introduced the coarse solution below... */ + for (i = 0; i < 64; i++) + block_ptr[i] = (block_ptr[i] * qmat[i]) >> 2; + + ctx->dsp.idct(block_ptr); + } + + put_pixels(ctx->blocks, out_ptr, linesize >> 1, mbs_per_slice, + blocks_per_mb); +} + + +static int decode_slice(ProresContext *ctx, int pic_num, int slice_num, + int mb_x_pos, int mb_y_pos, int mbs_per_slice, + AVCodecContext *avctx) +{ + const uint8_t *buf; + uint8_t *y_data, *u_data, *v_data; + AVFrame *pic = avctx->coded_frame; + int i, sf, slice_width_factor; + int slice_data_size, hdr_size, y_data_size, u_data_size, v_data_size; + int y_linesize, u_linesize, v_linesize; + + buf = ctx->slice_data_index[slice_num]; + slice_data_size = ctx->slice_data_index[slice_num + 1] - buf; + + slice_width_factor = av_log2(mbs_per_slice); + + y_data = pic->data[0]; + u_data = pic->data[1]; + v_data = pic->data[2]; + y_linesize = pic->linesize[0]; + u_linesize = pic->linesize[1]; + v_linesize = pic->linesize[2]; + + if (pic->interlaced_frame) { + if (!(pic_num ^ pic->top_field_first)) { + y_data += y_linesize; + u_data += u_linesize; + v_data += v_linesize; + } + y_linesize <<= 1; + u_linesize <<= 1; + v_linesize <<= 1; + } + + if (slice_data_size < 6) { + av_log(avctx, AV_LOG_ERROR, "slice data too short!\n"); + return -1; + } + + /* parse slice header */ + hdr_size = buf[0] >> 3; + y_data_size = AV_RB16(buf + 2); + u_data_size = AV_RB16(buf + 4); + v_data_size = slice_data_size - y_data_size - u_data_size - hdr_size; + + if (v_data_size < 0 || hdr_size < 6) { + av_log(avctx, AV_LOG_ERROR, "invalid data sizes!\n"); + return -1; + } + + sf = av_clip(buf[1], 1, 224); + sf = sf > 128 ? (sf - 96) << 2 : sf; + + /* scale quantization matrixes according with slice's scale factor */ + /* TODO: this can be SIMD-optimized alot */ + if (ctx->qmat_changed || sf != ctx->prev_slice_sf) { + ctx->prev_slice_sf = sf; + for (i = 0; i < 64; i++) { + ctx->qmat_luma_scaled[i] = ctx->qmat_luma[i] * sf; + ctx->qmat_chroma_scaled[i] = ctx->qmat_chroma[i] * sf; + } + } + + /* decode luma plane */ + decode_slice_plane(ctx, buf + hdr_size, y_data_size, + (uint16_t*) (y_data + (mb_y_pos << 4) * y_linesize + + (mb_x_pos << 5)), y_linesize, + mbs_per_slice, 4, slice_width_factor + 2, + ctx->qmat_luma_scaled); + + /* decode U chroma plane */ + decode_slice_plane(ctx, buf + hdr_size + y_data_size, u_data_size, + (uint16_t*) (u_data + (mb_y_pos << 4) * u_linesize + + (mb_x_pos << ctx->mb_chroma_factor)), + u_linesize, mbs_per_slice, ctx->num_chroma_blocks, + slice_width_factor + ctx->chroma_factor - 1, + ctx->qmat_chroma_scaled); + + /* decode V chroma plane */ + decode_slice_plane(ctx, buf + hdr_size + y_data_size + u_data_size, + v_data_size, + (uint16_t*) (v_data + (mb_y_pos << 4) * v_linesize + + (mb_x_pos << ctx->mb_chroma_factor)), + v_linesize, mbs_per_slice, ctx->num_chroma_blocks, + slice_width_factor + ctx->chroma_factor - 1, + ctx->qmat_chroma_scaled); + + return 0; +} + + +static int decode_picture(ProresContext *ctx, int pic_num, + AVCodecContext *avctx) +{ + int slice_num, slice_width, x_pos, y_pos; + + slice_num = 0; + + for (y_pos = 0; y_pos < ctx->num_y_mbs; y_pos++) { + slice_width = 1 << ctx->slice_width_factor; + + for (x_pos = 0; x_pos < ctx->num_x_mbs && slice_width; + x_pos += slice_width) { + while (ctx->num_x_mbs - x_pos < slice_width) + slice_width >>= 1; + + if (decode_slice(ctx, pic_num, slice_num, x_pos, y_pos, + slice_width, avctx) < 0) + return -1; + + slice_num++; + } + } + + return 0; +} + + +#define FRAME_ID MKBETAG('i', 'c', 'p', 'f') +#define MOVE_DATA_PTR(nbytes) buf += (nbytes); buf_size -= (nbytes) + +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, + AVPacket *avpkt) +{ + ProresContext *ctx = avctx->priv_data; + AVFrame *picture = avctx->coded_frame; + const uint8_t *buf = avpkt->data; + int buf_size = avpkt->size; + int frame_hdr_size, pic_num, pic_data_size; + + /* check frame atom container */ + if (buf_size < 28 || buf_size < AV_RB32(buf) || + AV_RB32(buf + 4) != FRAME_ID) { + av_log(avctx, AV_LOG_ERROR, "invalid frame\n"); + return -1; + } + + MOVE_DATA_PTR(8); + + frame_hdr_size = decode_frame_header(ctx, buf, buf_size, avctx); + if (frame_hdr_size < 0) + return -1; + + MOVE_DATA_PTR(frame_hdr_size); + + if (picture->data[0]) + avctx->release_buffer(avctx, picture); + + picture->reference = 0; + if (avctx->get_buffer(avctx, picture) < 0) + return -1; + + for (pic_num = 0; ctx->picture.interlaced_frame - pic_num + 1; pic_num++) { + pic_data_size = decode_picture_header(ctx, buf, buf_size, avctx); + if (pic_data_size < 0) + return -1; + + if (decode_picture(ctx, pic_num, avctx)) + return -1; + + MOVE_DATA_PTR(pic_data_size); + } + + *data_size = sizeof(AVPicture); + *(AVFrame*) data = *avctx->coded_frame; + + return avpkt->size; +} + + +static av_cold int decode_close(AVCodecContext *avctx) +{ + ProresContext *ctx = avctx->priv_data; + + if (ctx->picture.data[0]) + avctx->release_buffer(avctx, &ctx->picture); + + av_freep(&ctx->slice_data_index); + + return 0; +} + + +AVCodec ff_prores_decoder = { + .name = "ProRes", + .type = AVMEDIA_TYPE_VIDEO, + .id = CODEC_ID_PRORES, + .priv_data_size = sizeof(ProresContext), + .init = decode_init, + .close = decode_close, + .decode = decode_frame, + .capabilities = CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("Apple ProRes (iCodec Pro)") +}; diff --git a/libavcodec/version.h b/libavcodec/version.h index a430e3b55b..374013fe88 100644 --- a/libavcodec/version.h +++ b/libavcodec/version.h @@ -21,7 +21,7 @@ #define AVCODEC_VERSION_H #define LIBAVCODEC_VERSION_MAJOR 53 -#define LIBAVCODEC_VERSION_MINOR 10 +#define LIBAVCODEC_VERSION_MINOR 11 #define LIBAVCODEC_VERSION_MICRO 0 #define LIBAVCODEC_VERSION_INT AV_VERSION_INT(LIBAVCODEC_VERSION_MAJOR, \ From 12ad0677b4a81152339e55e60464bc76b450e4db Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Tue, 20 Sep 2011 17:09:44 +0200 Subject: [PATCH 05/14] fate.sh: Run git-pull in quiet mode to avoid console spam. Since fate.sh can be run from cron, silent commands are preferrable. --- tests/fate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fate.sh b/tests/fate.sh index 9fd117c3bc..617a726d95 100755 --- a/tests/fate.sh +++ b/tests/fate.sh @@ -35,7 +35,7 @@ checkout(){ update()( cd ${src} || return case "$repo" in - git:*) git pull ;; + git:*) git pull --quiet ;; esac ) From 20e1829dad73b5093d95fc7d45776d40b2705635 Mon Sep 17 00:00:00 2001 From: Diego Biurrun Date: Tue, 20 Sep 2011 17:09:45 +0200 Subject: [PATCH 06/14] fate.sh: Ignore errors from rm command during cleanup. The install directory being deleted might not be present if the build failed. This can lead to annoying error output if the FATE client is run as a cronjob. --- tests/fate.sh | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/fate.sh b/tests/fate.sh index 617a726d95..e04c8710d7 100755 --- a/tests/fate.sh +++ b/tests/fate.sh @@ -70,7 +70,7 @@ fate()( ) clean(){ - rm -r ${build} ${inst} + rm -rf ${build} ${inst} } report(){ From 1c2e07b8111b24f62b8d1bda62907848e34dfbcb Mon Sep 17 00:00:00 2001 From: Alex Converse Date: Wed, 21 Sep 2011 15:26:35 -0700 Subject: [PATCH 07/14] mp4: Don't read an empty Decoder Config Descriptor --- libavformat/isom.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/libavformat/isom.c b/libavformat/isom.c index 48fd8e1452..896730c5a6 100644 --- a/libavformat/isom.c +++ b/libavformat/isom.c @@ -418,7 +418,7 @@ int ff_mp4_read_dec_config_descr(AVFormatContext *fc, AVStream *st, AVIOContext len = ff_mp4_read_descr(fc, pb, &tag); if (tag == MP4DecSpecificDescrTag) { av_dlog(fc, "Specific MPEG4 header len=%d\n", len); - if((uint64_t)len > (1<<30)) + if (!len || (uint64_t)len > (1<<30)) return -1; av_free(st->codec->extradata); st->codec->extradata = av_mallocz(len + FF_INPUT_BUFFER_PADDING_SIZE); From ac68607bfe62000520db2e1c2416c11c51b3b295 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 6 Sep 2011 15:13:59 -0400 Subject: [PATCH 08/14] 8svx: split delta decoding into a separate function. Based on a patch by Stefano Sabatini. git.videolan.org/ffmpeg.git commit e280a4da2ae6fd44f0079358ecc5aa08e388a5ed --- libavcodec/8svx.c | 30 +++++++++++++++++++++++------- 1 file changed, 23 insertions(+), 7 deletions(-) diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index 4b60377128..dccaadddb0 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -41,6 +41,28 @@ static const int16_t fibonacci[16] = { -34<<8, -21<<8, -13<<8, -8<<8, -5<<8, static const int16_t exponential[16] = { -128<<8, -64<<8, -32<<8, -16<<8, -8<<8, -4<<8, -2<<8, -1<<8, 0, 1<<8, 2<<8, 4<<8, 8<<8, 16<<8, 32<<8, 64<<8 }; +/** + * Delta decode the compressed values in src, and put the resulting + * decoded samples in dst. + * + * @param[in,out] state starting value. it is saved for use in the next call. + */ +static void delta_decode(int16_t *dst, const uint8_t *src, int src_size, + int16_t *state, const int16_t *table) +{ + int val = *state; + + while (src_size--) { + uint8_t d = *src++; + val = av_clip_int16(val + table[d & 0xF]); + *dst++ = val; + val = av_clip_int16(val + table[d >> 4]); + *dst++ = val; + } + + *state = val; +} + /** decode a frame */ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) @@ -63,13 +85,7 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_si *data_size = buf_size << 2; - while(buf < buf_end) { - uint8_t d = *buf++; - esc->fib_acc += esc->table[d & 0x0f]; - *out_data++ = esc->fib_acc; - esc->fib_acc += esc->table[d >> 4]; - *out_data++ = esc->fib_acc; - } + delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table); return consumed; } From e3718784160a5bfed8de9622afda19313ec7ca50 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 6 Sep 2011 18:40:06 -0400 Subject: [PATCH 09/14] 8svx: output 8-bit samples instead of 16-bit. Based on a patch by Stefano Sabatini. git.videolan.org/ffmpeg.git commit e280a4da2ae6fd44f0079358ecc5aa08e388a5ed --- libavcodec/8svx.c | 37 ++++++++++++++++++------------------- 1 file changed, 18 insertions(+), 19 deletions(-) diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index dccaadddb0..adface26ce 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -32,14 +32,14 @@ /** decoder context */ typedef struct EightSvxContext { - int16_t fib_acc; - const int16_t *table; + uint8_t fib_acc; + const int8_t *table; } EightSvxContext; -static const int16_t fibonacci[16] = { -34<<8, -21<<8, -13<<8, -8<<8, -5<<8, -3<<8, -2<<8, -1<<8, - 0, 1<<8, 2<<8, 3<<8, 5<<8, 8<<8, 13<<8, 21<<8 }; -static const int16_t exponential[16] = { -128<<8, -64<<8, -32<<8, -16<<8, -8<<8, -4<<8, -2<<8, -1<<8, - 0, 1<<8, 2<<8, 4<<8, 8<<8, 16<<8, 32<<8, 64<<8 }; +static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1, + 0, 1, 2, 3, 5, 8, 13, 21 }; +static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, + 0, 1, 2, 4, 8, 16, 32, 64 }; /** * Delta decode the compressed values in src, and put the resulting @@ -47,16 +47,16 @@ static const int16_t exponential[16] = { -128<<8, -64<<8, -32<<8, -16<<8, -8<<8, * * @param[in,out] state starting value. it is saved for use in the next call. */ -static void delta_decode(int16_t *dst, const uint8_t *src, int src_size, - int16_t *state, const int16_t *table) +static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size, + uint8_t *state, const int8_t *table) { - int val = *state; + uint8_t val = *state; while (src_size--) { uint8_t d = *src++; - val = av_clip_int16(val + table[d & 0xF]); + val = av_clip_uint8(val + table[d & 0xF]); *dst++ = val; - val = av_clip_int16(val + table[d >> 4]); + val = av_clip_uint8(val + table[d >> 4]); *dst++ = val; } @@ -70,23 +70,22 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_si const uint8_t *buf = avpkt->data; int buf_size = avpkt->size; EightSvxContext *esc = avctx->priv_data; - int16_t *out_data = data; + uint8_t *out_data = data; int consumed = buf_size; - const uint8_t *buf_end = buf + buf_size; - - if((*data_size >> 2) < buf_size) - return -1; if(avctx->frame_number == 0) { - esc->fib_acc = buf[1] << 8; + esc->fib_acc = (int8_t)buf[1] + 128; buf_size -= 2; buf += 2; } - *data_size = buf_size << 2; + if (*data_size < buf_size * 2) + return AVERROR(EINVAL); delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table); + *data_size = buf_size * 2; + return consumed; } @@ -105,7 +104,7 @@ static av_cold int eightsvx_decode_init(AVCodecContext *avctx) default: return -1; } - avctx->sample_fmt = AV_SAMPLE_FMT_S16; + avctx->sample_fmt = AV_SAMPLE_FMT_U8; return 0; } From 0ac3b8fc4aeb1755717f44482f3236134a5b8405 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 6 Sep 2011 18:43:55 -0400 Subject: [PATCH 10/14] 8svx: check packet size before reading the initial sample value. --- libavcodec/8svx.c | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index adface26ce..0f53d39a8d 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -74,6 +74,10 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_si int consumed = buf_size; if(avctx->frame_number == 0) { + if (buf_size < 2) { + av_log(avctx, AV_LOG_ERROR, "packet size is too small\n"); + return AVERROR(EINVAL); + } esc->fib_acc = (int8_t)buf[1] + 128; buf_size -= 2; buf += 2; From fda459cee7a4227c34dfbc5dca1427c00d0d792e Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Tue, 6 Sep 2011 18:49:07 -0400 Subject: [PATCH 11/14] 8svx: log an error message if output buffer is too small Based on a patch by Stefano Sabatini. git.videolan.org/ffmpeg.git commit e280a4da2ae6fd44f0079358ecc5aa08e388a5ed --- libavcodec/8svx.c | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index 0f53d39a8d..af3b5fe789 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -83,8 +83,11 @@ static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_si buf += 2; } - if (*data_size < buf_size * 2) + if (*data_size < buf_size * 2) { + av_log(avctx, AV_LOG_ERROR, "Provided buffer with size %d is too small.\n", + *data_size); return AVERROR(EINVAL); + } delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table); From 1993c6849cf93f90066e4490c1547e2db845050c Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 7 Sep 2011 15:28:07 -0400 Subject: [PATCH 12/14] 8svx/iff: fix decoding of compressed stereo 8svx files. Make the iff demuxer send the whole audio chunk to the decoder as a single packet and move stereo interleaving from the iff demuxer to the decoder. Based on a patch by Stefano Sabatini. git.videolan.org/ffmpeg.git commit e280a4da2ae6fd44f0079358ecc5aa08e388a5ed --- libavcodec/8svx.c | 101 +++++++++++++++++++++++++++++++++++++--------- libavformat/iff.c | 45 +++------------------ 2 files changed, 88 insertions(+), 58 deletions(-) diff --git a/libavcodec/8svx.c b/libavcodec/8svx.c index af3b5fe789..a7b9c86065 100644 --- a/libavcodec/8svx.c +++ b/libavcodec/8svx.c @@ -32,8 +32,14 @@ /** decoder context */ typedef struct EightSvxContext { - uint8_t fib_acc; + uint8_t fib_acc[2]; const int8_t *table; + + /* buffer used to store the whole first packet. + data is only sent as one large packet */ + uint8_t *data[2]; + int data_size; + int data_idx; } EightSvxContext; static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1, @@ -41,6 +47,8 @@ static const int8_t fibonacci[16] = { -34, -21, -13, -8, -5, -3, -2, -1, static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, 0, 1, 2, 4, 8, 16, 32, 64 }; +#define MAX_FRAME_SIZE 32768 + /** * Delta decode the compressed values in src, and put the resulting * decoded samples in dst. @@ -48,16 +56,18 @@ static const int8_t exponential[16] = { -128, -64, -32, -16, -8, -4, -2, -1, * @param[in,out] state starting value. it is saved for use in the next call. */ static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size, - uint8_t *state, const int8_t *table) + uint8_t *state, const int8_t *table, int channels) { uint8_t val = *state; while (src_size--) { uint8_t d = *src++; val = av_clip_uint8(val + table[d & 0xF]); - *dst++ = val; + *dst = val; + dst += channels; val = av_clip_uint8(val + table[d >> 4]); - *dst++ = val; + *dst = val; + dst += channels; } *state = val; @@ -67,33 +77,69 @@ static void delta_decode(uint8_t *dst, const uint8_t *src, int src_size, static int eightsvx_decode_frame(AVCodecContext *avctx, void *data, int *data_size, AVPacket *avpkt) { - const uint8_t *buf = avpkt->data; - int buf_size = avpkt->size; EightSvxContext *esc = avctx->priv_data; + int buf_size; uint8_t *out_data = data; - int consumed = buf_size; + int out_data_size; + + /* for the first packet, copy data to buffer */ + if (avpkt->data) { + int chan_size = (avpkt->size / avctx->channels) - 2; - if(avctx->frame_number == 0) { - if (buf_size < 2) { + if (avpkt->size < 2) { av_log(avctx, AV_LOG_ERROR, "packet size is too small\n"); return AVERROR(EINVAL); } - esc->fib_acc = (int8_t)buf[1] + 128; - buf_size -= 2; - buf += 2; + if (esc->data[0]) { + av_log(avctx, AV_LOG_ERROR, "unexpected data after first packet\n"); + return AVERROR(EINVAL); + } + + esc->fib_acc[0] = avpkt->data[1] + 128; + if (avctx->channels == 2) + esc->fib_acc[1] = avpkt->data[2+chan_size+1] + 128; + + esc->data_idx = 0; + esc->data_size = chan_size; + if (!(esc->data[0] = av_malloc(chan_size))) + return AVERROR(ENOMEM); + if (avctx->channels == 2) { + if (!(esc->data[1] = av_malloc(chan_size))) { + av_freep(&esc->data[0]); + return AVERROR(ENOMEM); + } + } + memcpy(esc->data[0], &avpkt->data[2], chan_size); + if (avctx->channels == 2) + memcpy(esc->data[1], &avpkt->data[2+chan_size+2], chan_size); + } + if (!esc->data[0]) { + av_log(avctx, AV_LOG_ERROR, "unexpected empty packet\n"); + return AVERROR(EINVAL); } - if (*data_size < buf_size * 2) { + /* decode next piece of data from the buffer */ + buf_size = FFMIN(MAX_FRAME_SIZE, esc->data_size - esc->data_idx); + if (buf_size <= 0) { + *data_size = 0; + return avpkt->size; + } + out_data_size = buf_size * 2 * avctx->channels; + if (*data_size < out_data_size) { av_log(avctx, AV_LOG_ERROR, "Provided buffer with size %d is too small.\n", *data_size); return AVERROR(EINVAL); } + delta_decode(out_data, &esc->data[0][esc->data_idx], buf_size, + &esc->fib_acc[0], esc->table, avctx->channels); + if (avctx->channels == 2) { + delta_decode(&out_data[1], &esc->data[1][esc->data_idx], buf_size, + &esc->fib_acc[1], esc->table, avctx->channels); + } + esc->data_idx += buf_size; + *data_size = out_data_size; - delta_decode(out_data, buf, buf_size, &esc->fib_acc, esc->table); - - *data_size = buf_size * 2; - - return consumed; + return avpkt->size; } /** initialize 8svx decoder */ @@ -101,6 +147,11 @@ static av_cold int eightsvx_decode_init(AVCodecContext *avctx) { EightSvxContext *esc = avctx->priv_data; + if (avctx->channels < 1 || avctx->channels > 2) { + av_log(avctx, AV_LOG_ERROR, "8SVX does not support more than 2 channels\n"); + return AVERROR(EINVAL); + } + switch(avctx->codec->id) { case CODEC_ID_8SVX_FIB: esc->table = fibonacci; @@ -115,13 +166,25 @@ static av_cold int eightsvx_decode_init(AVCodecContext *avctx) return 0; } +static av_cold int eightsvx_decode_close(AVCodecContext *avctx) +{ + EightSvxContext *esc = avctx->priv_data; + + av_freep(&esc->data[0]); + av_freep(&esc->data[1]); + + return 0; +} + AVCodec ff_eightsvx_fib_decoder = { .name = "8svx_fib", .type = AVMEDIA_TYPE_AUDIO, .id = CODEC_ID_8SVX_FIB, .priv_data_size = sizeof (EightSvxContext), .init = eightsvx_decode_init, + .close = eightsvx_decode_close, .decode = eightsvx_decode_frame, + .capabilities = CODEC_CAP_DELAY, .long_name = NULL_IF_CONFIG_SMALL("8SVX fibonacci"), }; @@ -131,6 +194,8 @@ AVCodec ff_eightsvx_exp_decoder = { .id = CODEC_ID_8SVX_EXP, .priv_data_size = sizeof (EightSvxContext), .init = eightsvx_decode_init, + .close = eightsvx_decode_close, .decode = eightsvx_decode_frame, + .capabilities = CODEC_CAP_DELAY, .long_name = NULL_IF_CONFIG_SMALL("8SVX exponential"), }; diff --git a/libavformat/iff.c b/libavformat/iff.c index f388ca9e32..8f309b95dd 100644 --- a/libavformat/iff.c +++ b/libavformat/iff.c @@ -59,8 +59,6 @@ #define RIGHT 4 #define STEREO 6 -#define PACKET_SIZE 1024 - typedef enum { COMP_NONE, COMP_FIB, @@ -76,22 +74,9 @@ typedef struct { uint64_t body_pos; uint32_t body_size; uint32_t sent_bytes; - uint32_t audio_frame_count; } IffDemuxContext; -static void interleave_stereo(const uint8_t *src, uint8_t *dest, int size) -{ - uint8_t *end = dest + size; - size = size>>1; - - while(dest < end) { - *dest++ = *src; - *dest++ = *(src+size); - src++; - } -} - /* Metadata string read */ static int get_metadata(AVFormatContext *s, const char *const tag, @@ -278,40 +263,20 @@ static int iff_read_packet(AVFormatContext *s, { IffDemuxContext *iff = s->priv_data; AVIOContext *pb = s->pb; - AVStream *st = s->streams[0]; int ret; if(iff->sent_bytes >= iff->body_size) - return AVERROR(EIO); - - if(st->codec->channels == 2) { - uint8_t sample_buffer[PACKET_SIZE]; + return AVERROR_EOF; - ret = avio_read(pb, sample_buffer, PACKET_SIZE); - if(av_new_packet(pkt, PACKET_SIZE) < 0) { - av_log(s, AV_LOG_ERROR, "cannot allocate packet\n"); - return AVERROR(ENOMEM); - } - interleave_stereo(sample_buffer, pkt->data, PACKET_SIZE); - } else if (st->codec->codec_type == AVMEDIA_TYPE_VIDEO) { - ret = av_get_packet(pb, pkt, iff->body_size); - } else { - ret = av_get_packet(pb, pkt, PACKET_SIZE); - } + ret = av_get_packet(pb, pkt, iff->body_size); + if (ret < 0) + return ret; if(iff->sent_bytes == 0) pkt->flags |= AV_PKT_FLAG_KEY; + iff->sent_bytes = iff->body_size; - if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - iff->sent_bytes += PACKET_SIZE; - } else { - iff->sent_bytes = iff->body_size; - } pkt->stream_index = 0; - if(st->codec->codec_type == AVMEDIA_TYPE_AUDIO) { - pkt->pts = iff->audio_frame_count; - iff->audio_frame_count += ret / st->codec->channels; - } return ret; } From 59df4b82a5d2d614636076b0bd3e03aba400fc96 Mon Sep 17 00:00:00 2001 From: Justin Ruggles Date: Wed, 7 Sep 2011 15:29:53 -0400 Subject: [PATCH 13/14] avplay: flush audio decoder with empty packets at EOF if the decoder has CODEC_CAP_DELAY set. --- avplay.c | 29 +++++++++++++++++++++++------ 1 file changed, 23 insertions(+), 6 deletions(-) diff --git a/avplay.c b/avplay.c index 198dce1d2b..b95cba750f 100644 --- a/avplay.c +++ b/avplay.c @@ -2008,10 +2008,15 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) AVCodecContext *dec= is->audio_st->codec; int n, len1, data_size; double pts; + int new_packet = 0; + int flush_complete = 0; for(;;) { /* NOTE: the audio packet can contain several frames */ - while (pkt_temp->size > 0) { + while (pkt_temp->size > 0 || (!pkt_temp->data && new_packet)) { + if (flush_complete) + break; + new_packet = 0; data_size = sizeof(is->audio_buf1); len1 = avcodec_decode_audio3(dec, (int16_t *)is->audio_buf1, &data_size, @@ -2024,8 +2029,13 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) pkt_temp->data += len1; pkt_temp->size -= len1; - if (data_size <= 0) + + if (data_size <= 0) { + /* stop sending empty packets if the decoder is finished */ + if (!pkt_temp->data && dec->codec->capabilities & CODEC_CAP_DELAY) + flush_complete = 1; continue; + } if (dec->sample_fmt != is->audio_src_fmt) { if (is->reformat_ctx) @@ -2086,12 +2096,11 @@ static int audio_decode_frame(VideoState *is, double *pts_ptr) } /* read next packet */ - if (packet_queue_get(&is->audioq, pkt, 1) < 0) + if ((new_packet = packet_queue_get(&is->audioq, pkt, 1)) < 0) return -1; - if(pkt->data == flush_pkt.data){ + + if (pkt->data == flush_pkt.data) avcodec_flush_buffers(dec); - continue; - } pkt_temp->data = pkt->data; pkt_temp->size = pkt->size; @@ -2508,6 +2517,14 @@ static int decode_thread(void *arg) pkt->stream_index= is->video_stream; packet_queue_put(&is->videoq, pkt); } + if (is->audio_stream >= 0 && + is->audio_st->codec->codec->capabilities & CODEC_CAP_DELAY) { + av_init_packet(pkt); + pkt->data = NULL; + pkt->size = 0; + pkt->stream_index = is->audio_stream; + packet_queue_put(&is->audioq, pkt); + } SDL_Delay(10); if(is->audioq.size + is->videoq.size + is->subtitleq.size ==0){ if(loop!=1 && (!loop || --loop)){ From dcb9f6a20dbddd1f95b6b322fc4c5fd0b5315729 Mon Sep 17 00:00:00 2001 From: Janne Grunau Date: Tue, 6 Sep 2011 22:08:29 +0200 Subject: [PATCH 14/14] Add LATM demuxer This is a raw demuxer for the AAC LATM decoder and thus limited to single stream LOAS. --- Changelog | 2 +- libavformat/Makefile | 1 + libavformat/allformats.c | 2 +- libavformat/rawdec.c | 12 ++++++++++++ libavformat/version.h | 2 +- 5 files changed, 16 insertions(+), 3 deletions(-) diff --git a/Changelog b/Changelog index 3cd2c0de05..bbe6a60325 100644 --- a/Changelog +++ b/Changelog @@ -42,7 +42,7 @@ easier to use. The changes are: * -intra option was removed, it's equivalent to -g 0. - XMV demuxer - Windows Media Image decoder -- LATM muxer +- LATM muxer/demuxer - showinfo filter - split filter - libcdio-paranoia input device for audio CD grabbing diff --git a/libavformat/Makefile b/libavformat/Makefile index 06c2027692..59dd42f643 100644 --- a/libavformat/Makefile +++ b/libavformat/Makefile @@ -109,6 +109,7 @@ OBJS-$(CONFIG_IV8_DEMUXER) += iv8.o OBJS-$(CONFIG_IVF_DEMUXER) += ivfdec.o riff.o OBJS-$(CONFIG_IVF_MUXER) += ivfenc.o OBJS-$(CONFIG_JV_DEMUXER) += jvdec.o +OBJS-$(CONFIG_LATM_DEMUXER) += rawdec.o OBJS-$(CONFIG_LATM_MUXER) += latmenc.o OBJS-$(CONFIG_LMLM4_DEMUXER) += lmlm4.o OBJS-$(CONFIG_LXF_DEMUXER) += lxfdec.o diff --git a/libavformat/allformats.c b/libavformat/allformats.c index d640340cec..8e89b2f4ff 100644 --- a/libavformat/allformats.c +++ b/libavformat/allformats.c @@ -113,7 +113,7 @@ void av_register_all(void) REGISTER_DEMUXER (IV8, iv8); REGISTER_MUXDEMUX (IVF, ivf); REGISTER_DEMUXER (JV, jv); - REGISTER_MUXER (LATM, latm); + REGISTER_MUXDEMUX (LATM, latm); REGISTER_DEMUXER (LMLM4, lmlm4); REGISTER_DEMUXER (LXF, lxf); REGISTER_MUXDEMUX (M4V, m4v); diff --git a/libavformat/rawdec.c b/libavformat/rawdec.c index 35df5e2462..9b3ef49fda 100644 --- a/libavformat/rawdec.c +++ b/libavformat/rawdec.c @@ -198,6 +198,18 @@ AVInputFormat ff_gsm_demuxer = { }; #endif +#if CONFIG_LATM_DEMUXER +AVInputFormat ff_latm_demuxer = { + .name = "latm", + .long_name = NULL_IF_CONFIG_SMALL("raw LOAS/LATM"), + .read_header = ff_raw_audio_read_header, + .read_packet = ff_raw_read_partial_packet, + .flags= AVFMT_GENERIC_INDEX, + .extensions = "latm", + .value = CODEC_ID_AAC_LATM, +}; +#endif + #if CONFIG_MJPEG_DEMUXER FF_DEF_RAWVIDEO_DEMUXER(mjpeg, "raw MJPEG video", NULL, "mjpg,mjpeg", CODEC_ID_MJPEG) #endif diff --git a/libavformat/version.h b/libavformat/version.h index 2d64826e32..82a07dbc32 100644 --- a/libavformat/version.h +++ b/libavformat/version.h @@ -24,7 +24,7 @@ #include "libavutil/avutil.h" #define LIBAVFORMAT_VERSION_MAJOR 53 -#define LIBAVFORMAT_VERSION_MINOR 7 +#define LIBAVFORMAT_VERSION_MINOR 8 #define LIBAVFORMAT_VERSION_MICRO 0 #define LIBAVFORMAT_VERSION_INT AV_VERSION_INT(LIBAVFORMAT_VERSION_MAJOR, \