From 875bbde0535cc0333e5b057291ff687ada3ad3a7 Mon Sep 17 00:00:00 2001 From: David McPaul Date: Mon, 15 Sep 2008 14:14:13 +0000 Subject: [PATCH] Update avcodec to 20080825 git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@27566 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- .../media/plugins/avcodec/libavcodec/lcl.h | 49 ++ .../media/plugins/avcodec/libavcodec/lcldec.c | 717 ++++++++++++++++ .../media/plugins/avcodec/libavcodec/lclenc.c | 232 ++++++ .../media/plugins/avcodec/libavcodec/liba52.c | 227 +++++ .../media/plugins/avcodec/libavcodec/libamr.c | 719 ++++++++++++++++ .../plugins/avcodec/libavcodec/libdirac.h | 49 ++ .../avcodec/libavcodec/libdirac_libschro.c | 117 +++ .../avcodec/libavcodec/libdirac_libschro.h | 109 +++ .../plugins/avcodec/libavcodec/libdiracdec.c | 209 +++++ .../plugins/avcodec/libavcodec/libdiracenc.c | 420 ++++++++++ .../plugins/avcodec/libavcodec/libfaac.c | 156 ++++ .../plugins/avcodec/libavcodec/libfaad.c | 340 ++++++++ .../media/plugins/avcodec/libavcodec/libgsm.c | 178 ++++ .../plugins/avcodec/libavcodec/libmp3lame.c | 226 +++++ .../avcodec/libavcodec/libschroedinger.c | 80 ++ .../avcodec/libavcodec/libschroedinger.h | 61 ++ .../avcodec/libavcodec/libschroedingerdec.c | 369 +++++++++ .../avcodec/libavcodec/libschroedingerenc.c | 433 ++++++++++ .../plugins/avcodec/libavcodec/libtheoraenc.c | 281 +++++++ .../plugins/avcodec/libavcodec/libvorbis.c | 222 +++++ .../plugins/avcodec/libavcodec/libx264.c | 305 +++++++ .../avcodec/libavcodec/libxvid_internal.h | 32 + .../plugins/avcodec/libavcodec/libxvid_rc.c | 148 ++++ .../plugins/avcodec/libavcodec/libxvidff.c | 782 ++++++++++++++++++ .../plugins/avcodec/libavcodec/ljpegenc.c | 198 +++++ .../media/plugins/avcodec/libavcodec/loco.c | 286 +++++++ .../plugins/avcodec/libavcodec/lowpass.c | 129 +++ .../plugins/avcodec/libavcodec/lowpass.h | 83 ++ .../media/plugins/avcodec/libavcodec/lpc.c | 205 +++++ .../media/plugins/avcodec/libavcodec/lpc.h | 48 ++ .../media/plugins/avcodec/libavcodec/lsp.c | 120 +++ .../media/plugins/avcodec/libavcodec/lsp.h | 70 ++ .../media/plugins/avcodec/libavcodec/lzw.c | 229 +++++ .../media/plugins/avcodec/libavcodec/lzw.h | 59 ++ .../media/plugins/avcodec/libavcodec/lzwenc.c | 262 ++++++ 35 files changed, 8150 insertions(+) create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lcl.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lcldec.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lclenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/liba52.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libamr.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libdirac.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libdiracdec.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libdiracenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libfaac.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libfaad.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libgsm.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libmp3lame.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerdec.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libtheoraenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libvorbis.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libx264.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libxvid_internal.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libxvid_rc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/libxvidff.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/ljpegenc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/loco.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lowpass.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lowpass.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lpc.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lpc.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lsp.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lsp.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lzw.c create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lzw.h create mode 100644 src/add-ons/media/plugins/avcodec/libavcodec/lzwenc.c diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lcl.h b/src/add-ons/media/plugins/avcodec/libavcodec/lcl.h new file mode 100644 index 0000000000..7d5a76a789 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lcl.h @@ -0,0 +1,49 @@ +/* + * LCL (LossLess Codec Library) Codec + * Copyright (c) 2002-2004 Roberto Togni + * + * 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 FFMPEG_LCL_H +#define FFMPEG_LCL_H + +#define BMPTYPE_YUV 1 +#define BMPTYPE_RGB 2 + +#define IMGTYPE_YUV111 0 +#define IMGTYPE_YUV422 1 +#define IMGTYPE_RGB24 2 +#define IMGTYPE_YUV411 3 +#define IMGTYPE_YUV211 4 +#define IMGTYPE_YUV420 5 + +#define COMP_MSZH 0 +#define COMP_MSZH_NOCOMP 1 +#define COMP_ZLIB_HISPEED 1 +#define COMP_ZLIB_HICOMP 9 +#define COMP_ZLIB_NORMAL -1 + +#define FLAG_MULTITHREAD 1 +#define FLAG_NULLFRAME 2 +#define FLAG_PNGFILTER 4 +#define FLAGMASK_UNUSED 0xf8 + +#define CODEC_MSZH 1 +#define CODEC_ZLIB 3 + +#endif /* FFMPEG_LCL_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lcldec.c b/src/add-ons/media/plugins/avcodec/libavcodec/lcldec.c new file mode 100644 index 0000000000..5560b9a646 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lcldec.c @@ -0,0 +1,717 @@ +/* + * LCL (LossLess Codec Library) Codec + * Copyright (c) 2002-2004 Roberto Togni + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file lcl.c + * LCL (LossLess Codec Library) Video Codec + * Decoder for MSZH and ZLIB codecs + * Experimental encoder for ZLIB RGB24 + * + * Fourcc: MSZH, ZLIB + * + * Original Win32 dll: + * Ver2.23 By Kenji Oshima 2000.09.20 + * avimszh.dll, avizlib.dll + * + * A description of the decoding algorithm can be found here: + * http://www.pcisys.net/~melanson/codecs + * + * Supports: BGR24 (RGB 24bpp) + * + */ + +#include +#include + +#include "avcodec.h" +#include "bitstream.h" +#include "lcl.h" + +#ifdef CONFIG_ZLIB +#include +#endif + +/* + * Decoder context + */ +typedef struct LclDecContext { + AVFrame pic; + + // Image type + int imgtype; + // Compression type + int compression; + // Flags + int flags; + // Decompressed data size + unsigned int decomp_size; + // Decompression buffer + unsigned char* decomp_buf; +#ifdef CONFIG_ZLIB + z_stream zstream; +#endif +} LclDecContext; + + +/* + * + * Helper functions + * + */ +static inline unsigned char fix (int pix14) +{ + int tmp; + + tmp = (pix14 + 0x80000) >> 20; + if (tmp < 0) + return 0; + if (tmp > 255) + return 255; + return tmp; +} + + + +static inline unsigned char get_b (unsigned char yq, signed char bq) +{ + return fix((yq << 20) + bq * 1858076); +} + + + +static inline unsigned char get_g (unsigned char yq, signed char bq, signed char rq) +{ + return fix((yq << 20) - bq * 360857 - rq * 748830); +} + + + +static inline unsigned char get_r (unsigned char yq, signed char rq) +{ + return fix((yq << 20) + rq * 1470103); +} + + + +static unsigned int mszh_decomp(unsigned char * srcptr, int srclen, unsigned char * destptr, unsigned int destsize) +{ + unsigned char *destptr_bak = destptr; + unsigned char *destptr_end = destptr + destsize; + unsigned char mask = 0; + unsigned char maskbit = 0; + unsigned int ofs, cnt; + + while ((srclen > 0) && (destptr < destptr_end)) { + if (maskbit == 0) { + mask = *(srcptr++); + maskbit = 8; + srclen--; + continue; + } + if ((mask & (1 << (--maskbit))) == 0) { + if (destptr + 4 > destptr_end) + break; + *(int*)destptr = *(int*)srcptr; + srclen -= 4; + destptr += 4; + srcptr += 4; + } else { + ofs = *(srcptr++); + cnt = *(srcptr++); + ofs += cnt * 256; + cnt = ((cnt >> 3) & 0x1f) + 1; + ofs &= 0x7ff; + srclen -= 2; + cnt *= 4; + if (destptr + cnt > destptr_end) { + cnt = destptr_end - destptr; + } + for (; cnt > 0; cnt--) { + *(destptr) = *(destptr - ofs); + destptr++; + } + } + } + + return (destptr - destptr_bak); +} + + + +/* + * + * Decode a frame + * + */ +static int decode_frame(AVCodecContext *avctx, void *data, int *data_size, const uint8_t *buf, int buf_size) +{ + LclDecContext * const c = avctx->priv_data; + unsigned char *encoded = (unsigned char *)buf; + unsigned int pixel_ptr; + int row, col; + unsigned char *outptr; + unsigned int width = avctx->width; // Real image width + unsigned int height = avctx->height; // Real image height + unsigned int mszh_dlen; + unsigned char yq, y1q, uq, vq; + int uqvq; + unsigned int mthread_inlen, mthread_outlen; +#ifdef CONFIG_ZLIB + int zret; // Zlib return code +#endif + unsigned int len = buf_size; + + if(c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); + + c->pic.reference = 0; + c->pic.buffer_hints = FF_BUFFER_HINTS_VALID; + if(avctx->get_buffer(avctx, &c->pic) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + + outptr = c->pic.data[0]; // Output image pointer + + /* Decompress frame */ + switch (avctx->codec_id) { + case CODEC_ID_MSZH: + switch (c->compression) { + case COMP_MSZH: + if (c->flags & FLAG_MULTITHREAD) { + mthread_inlen = *((unsigned int*)encoded); + mthread_outlen = *((unsigned int*)(encoded+4)); + if (mthread_outlen > c->decomp_size) // this should not happen + mthread_outlen = c->decomp_size; + mszh_dlen = mszh_decomp(encoded + 8, mthread_inlen, c->decomp_buf, c->decomp_size); + if (mthread_outlen != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%d != %d)\n", + mthread_outlen, mszh_dlen); + return -1; + } + mszh_dlen = mszh_decomp(encoded + 8 + mthread_inlen, len - mthread_inlen, + c->decomp_buf + mthread_outlen, c->decomp_size - mthread_outlen); + if (mthread_outlen != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %d)\n", + mthread_outlen, mszh_dlen); + return -1; + } + encoded = c->decomp_buf; + len = c->decomp_size; + } else { + mszh_dlen = mszh_decomp(encoded, len, c->decomp_buf, c->decomp_size); + if (c->decomp_size != mszh_dlen) { + av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %d)\n", + c->decomp_size, mszh_dlen); + return -1; + } + encoded = c->decomp_buf; + len = mszh_dlen; + } + break; + case COMP_MSZH_NOCOMP: + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown MSZH compression in frame decoder.\n"); + return -1; + } + break; + case CODEC_ID_ZLIB: +#ifdef CONFIG_ZLIB + /* Using the original dll with normal compression (-1) and RGB format + * gives a file with ZLIB fourcc, but frame is really uncompressed. + * To be sure that's true check also frame size */ + if ((c->compression == COMP_ZLIB_NORMAL) && (c->imgtype == IMGTYPE_RGB24) && + (len == width * height * 3)) + break; + zret = inflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate reset error: %d\n", zret); + return -1; + } + if (c->flags & FLAG_MULTITHREAD) { + mthread_inlen = *((unsigned int*)encoded); + mthread_outlen = *((unsigned int*)(encoded+4)); + if (mthread_outlen > c->decomp_size) + mthread_outlen = c->decomp_size; + c->zstream.next_in = encoded + 8; + c->zstream.avail_in = mthread_inlen; + c->zstream.next_out = c->decomp_buf; + c->zstream.avail_out = c->decomp_size; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 inflate error: %d\n", zret); + return -1; + } + if (mthread_outlen != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Mthread1 decoded size differs (%u != %lu)\n", + mthread_outlen, c->zstream.total_out); + return -1; + } + zret = inflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate reset error: %d\n", zret); + return -1; + } + c->zstream.next_in = encoded + 8 + mthread_inlen; + c->zstream.avail_in = len - mthread_inlen; + c->zstream.next_out = c->decomp_buf + mthread_outlen; + c->zstream.avail_out = c->decomp_size - mthread_outlen; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 inflate error: %d\n", zret); + return -1; + } + if (mthread_outlen != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Mthread2 decoded size differs (%d != %lu)\n", + mthread_outlen, c->zstream.total_out); + return -1; + } + } else { + c->zstream.next_in = encoded; + c->zstream.avail_in = len; + c->zstream.next_out = c->decomp_buf; + c->zstream.avail_out = c->decomp_size; + zret = inflate(&(c->zstream), Z_FINISH); + if ((zret != Z_OK) && (zret != Z_STREAM_END)) { + av_log(avctx, AV_LOG_ERROR, "Inflate error: %d\n", zret); + return -1; + } + if (c->decomp_size != (unsigned int)(c->zstream.total_out)) { + av_log(avctx, AV_LOG_ERROR, "Decoded size differs (%d != %lu)\n", + c->decomp_size, c->zstream.total_out); + return -1; + } + } + encoded = c->decomp_buf; + len = c->decomp_size; +#else + av_log(avctx, AV_LOG_ERROR, "BUG! Zlib support not compiled in frame decoder.\n"); + return -1; +#endif + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in frame decoder compression switch.\n"); + return -1; + } + + + /* Apply PNG filter */ + if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER)) { + switch (c->imgtype) { + case IMGTYPE_YUV111: + case IMGTYPE_RGB24: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 3; + yq = encoded[pixel_ptr++]; + uqvq = AV_RL16(encoded+pixel_ptr); + pixel_ptr += 2; + for (col = 1; col < width; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + uqvq -= AV_RL16(encoded+pixel_ptr+1); + AV_WL16(encoded+pixel_ptr+1, uqvq); + pixel_ptr += 3; + } + } + break; + case IMGTYPE_YUV422: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 2; + yq = uq = vq =0; + for (col = 0; col < width/4; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = uq -= encoded[pixel_ptr+5]; + encoded[pixel_ptr+6] = vq -= encoded[pixel_ptr+6]; + encoded[pixel_ptr+7] = vq -= encoded[pixel_ptr+7]; + pixel_ptr += 8; + } + } + break; + case IMGTYPE_YUV411: + for (row = 0; row < height; row++) { + pixel_ptr = row * width / 2 * 3; + yq = uq = vq =0; + for (col = 0; col < width/4; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = yq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = yq -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5]; + pixel_ptr += 6; + } + } + break; + case IMGTYPE_YUV211: + for (row = 0; row < height; row++) { + pixel_ptr = row * width * 2; + yq = uq = vq =0; + for (col = 0; col < width/2; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = uq -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = vq -= encoded[pixel_ptr+3]; + pixel_ptr += 4; + } + } + break; + case IMGTYPE_YUV420: + for (row = 0; row < height/2; row++) { + pixel_ptr = row * width * 3; + yq = y1q = uq = vq =0; + for (col = 0; col < width/2; col++) { + encoded[pixel_ptr] = yq -= encoded[pixel_ptr]; + encoded[pixel_ptr+1] = yq -= encoded[pixel_ptr+1]; + encoded[pixel_ptr+2] = y1q -= encoded[pixel_ptr+2]; + encoded[pixel_ptr+3] = y1q -= encoded[pixel_ptr+3]; + encoded[pixel_ptr+4] = uq -= encoded[pixel_ptr+4]; + encoded[pixel_ptr+5] = vq -= encoded[pixel_ptr+5]; + pixel_ptr += 6; + } + } + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in pngfilter switch.\n"); + return -1; + } + } + + /* Convert colorspace */ + switch (c->imgtype) { + case IMGTYPE_YUV111: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[1]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[1], encoded[2]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[2]); + encoded += 3; + } + } + break; + case IMGTYPE_YUV422: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/4; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[6]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[6]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[6]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[6]); + outptr[pixel_ptr++] = get_b(encoded[2], encoded[5]); + outptr[pixel_ptr++] = get_g(encoded[2], encoded[5], encoded[7]); + outptr[pixel_ptr++] = get_r(encoded[2], encoded[7]); + outptr[pixel_ptr++] = get_b(encoded[3], encoded[5]); + outptr[pixel_ptr++] = get_g(encoded[3], encoded[5], encoded[7]); + outptr[pixel_ptr++] = get_r(encoded[3], encoded[7]); + encoded += 8; + } + } + break; + case IMGTYPE_RGB24: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width; col++) { + outptr[pixel_ptr++] = encoded[0]; + outptr[pixel_ptr++] = encoded[1]; + outptr[pixel_ptr++] = encoded[2]; + encoded += 3; + } + } + break; + case IMGTYPE_YUV411: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/4; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[2], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[2], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[2], encoded[5]); + outptr[pixel_ptr++] = get_b(encoded[3], encoded[4]); + outptr[pixel_ptr++] = get_g(encoded[3], encoded[4], encoded[5]); + outptr[pixel_ptr++] = get_r(encoded[3], encoded[5]); + encoded += 6; + } + } + break; + case IMGTYPE_YUV211: + for (row = height - 1; row >= 0; row--) { + pixel_ptr = row * c->pic.linesize[0]; + for (col = 0; col < width/2; col++) { + outptr[pixel_ptr++] = get_b(encoded[0], encoded[2]); + outptr[pixel_ptr++] = get_g(encoded[0], encoded[2], encoded[3]); + outptr[pixel_ptr++] = get_r(encoded[0], encoded[3]); + outptr[pixel_ptr++] = get_b(encoded[1], encoded[2]); + outptr[pixel_ptr++] = get_g(encoded[1], encoded[2], encoded[3]); + outptr[pixel_ptr++] = get_r(encoded[1], encoded[3]); + encoded += 4; + } + } + break; + case IMGTYPE_YUV420: + for (row = height / 2 - 1; row >= 0; row--) { + pixel_ptr = 2 * row * c->pic.linesize[0]; + for (col = 0; col < width/2; col++) { + outptr[pixel_ptr] = get_b(encoded[0], encoded[4]); + outptr[pixel_ptr+1] = get_g(encoded[0], encoded[4], encoded[5]); + outptr[pixel_ptr+2] = get_r(encoded[0], encoded[5]); + outptr[pixel_ptr+3] = get_b(encoded[1], encoded[4]); + outptr[pixel_ptr+4] = get_g(encoded[1], encoded[4], encoded[5]); + outptr[pixel_ptr+5] = get_r(encoded[1], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]] = get_b(encoded[2], encoded[4]); + outptr[pixel_ptr-c->pic.linesize[0]+1] = get_g(encoded[2], encoded[4], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+2] = get_r(encoded[2], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+3] = get_b(encoded[3], encoded[4]); + outptr[pixel_ptr-c->pic.linesize[0]+4] = get_g(encoded[3], encoded[4], encoded[5]); + outptr[pixel_ptr-c->pic.linesize[0]+5] = get_r(encoded[3], encoded[5]); + pixel_ptr += 6; + encoded += 6; + } + } + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown imagetype in image decoder.\n"); + return -1; + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = c->pic; + + /* always report that the buffer was completely consumed */ + return buf_size; +} + +/* + * + * Init lcl decoder + * + */ +static av_cold int decode_init(AVCodecContext *avctx) +{ + LclDecContext * const c = avctx->priv_data; + unsigned int basesize = avctx->width * avctx->height; + unsigned int max_basesize = ((avctx->width + 3) & ~3) * ((avctx->height + 3) & ~3); + unsigned int max_decomp_size; + int zret; // Zlib return code + + c->pic.data[0] = NULL; + +#ifdef CONFIG_ZLIB + // Needed if zlib unused or init aborted before inflateInit + memset(&(c->zstream), 0, sizeof(z_stream)); +#endif + + if (avctx->extradata_size < 8) { + av_log(avctx, AV_LOG_ERROR, "Extradata size too small.\n"); + return 1; + } + + if (avcodec_check_dimensions(avctx, avctx->width, avctx->height) < 0) { + return 1; + } + + /* Check codec type */ + if (((avctx->codec_id == CODEC_ID_MSZH) && (*((char *)avctx->extradata + 7) != CODEC_MSZH)) || + ((avctx->codec_id == CODEC_ID_ZLIB) && (*((char *)avctx->extradata + 7) != CODEC_ZLIB))) { + av_log(avctx, AV_LOG_ERROR, "Codec id and codec type mismatch. This should not happen.\n"); + } + + /* Detect image type */ + switch (c->imgtype = *((char *)avctx->extradata + 4)) { + case IMGTYPE_YUV111: + c->decomp_size = basesize * 3; + max_decomp_size = max_basesize * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 1:1:1.\n"); + break; + case IMGTYPE_YUV422: + c->decomp_size = basesize * 2; + max_decomp_size = max_basesize * 2; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:2.\n"); + break; + case IMGTYPE_RGB24: + c->decomp_size = basesize * 3; + max_decomp_size = max_basesize * 3; + av_log(avctx, AV_LOG_INFO, "Image type is RGB 24.\n"); + break; + case IMGTYPE_YUV411: + c->decomp_size = basesize / 2 * 3; + max_decomp_size = max_basesize / 2 * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:1:1.\n"); + break; + case IMGTYPE_YUV211: + c->decomp_size = basesize * 2; + max_decomp_size = max_basesize * 2; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 2:1:1.\n"); + break; + case IMGTYPE_YUV420: + c->decomp_size = basesize / 2 * 3; + max_decomp_size = max_basesize / 2 * 3; + av_log(avctx, AV_LOG_INFO, "Image type is YUV 4:2:0.\n"); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported image format %d.\n", c->imgtype); + return 1; + } + + /* Detect compression method */ + c->compression = *((char *)avctx->extradata + 5); + switch (avctx->codec_id) { + case CODEC_ID_MSZH: + switch (c->compression) { + case COMP_MSZH: + av_log(avctx, AV_LOG_INFO, "Compression enabled.\n"); + break; + case COMP_MSZH_NOCOMP: + c->decomp_size = 0; + av_log(avctx, AV_LOG_INFO, "No compression.\n"); + break; + default: + av_log(avctx, AV_LOG_ERROR, "Unsupported compression format for MSZH (%d).\n", c->compression); + return 1; + } + break; + case CODEC_ID_ZLIB: +#ifdef CONFIG_ZLIB + switch (c->compression) { + case COMP_ZLIB_HISPEED: + av_log(avctx, AV_LOG_INFO, "High speed compression.\n"); + break; + case COMP_ZLIB_HICOMP: + av_log(avctx, AV_LOG_INFO, "High compression.\n"); + break; + case COMP_ZLIB_NORMAL: + av_log(avctx, AV_LOG_INFO, "Normal compression.\n"); + break; + default: + if ((c->compression < Z_NO_COMPRESSION) || (c->compression > Z_BEST_COMPRESSION)) { + av_log(avctx, AV_LOG_ERROR, "Unsupported compression level for ZLIB: (%d).\n", c->compression); + return 1; + } + av_log(avctx, AV_LOG_INFO, "Compression level for ZLIB: (%d).\n", c->compression); + } +#else + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#endif + break; + default: + av_log(avctx, AV_LOG_ERROR, "BUG! Unknown codec in compression switch.\n"); + return 1; + } + + /* Allocate decompression buffer */ + if (c->decomp_size) { + if ((c->decomp_buf = av_malloc(max_decomp_size)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't allocate decompression buffer.\n"); + return 1; + } + } + + /* Detect flags */ + c->flags = *((char *)avctx->extradata + 6); + if (c->flags & FLAG_MULTITHREAD) + av_log(avctx, AV_LOG_INFO, "Multithread encoder flag set.\n"); + if (c->flags & FLAG_NULLFRAME) + av_log(avctx, AV_LOG_INFO, "Nullframe insertion flag set.\n"); + if ((avctx->codec_id == CODEC_ID_ZLIB) && (c->flags & FLAG_PNGFILTER)) + av_log(avctx, AV_LOG_INFO, "PNG filter flag set.\n"); + if (c->flags & FLAGMASK_UNUSED) + av_log(avctx, AV_LOG_ERROR, "Unknown flag set (%d).\n", c->flags); + + /* If needed init zlib */ + if (avctx->codec_id == CODEC_ID_ZLIB) { +#ifdef CONFIG_ZLIB + c->zstream.zalloc = Z_NULL; + c->zstream.zfree = Z_NULL; + c->zstream.opaque = Z_NULL; + zret = inflateInit(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Inflate init error: %d\n", zret); + return 1; + } +#else + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#endif + } + + avctx->pix_fmt = PIX_FMT_BGR24; + + return 0; +} + +/* + * + * Uninit lcl decoder + * + */ +static av_cold int decode_end(AVCodecContext *avctx) +{ + LclDecContext * const c = avctx->priv_data; + + if (c->pic.data[0]) + avctx->release_buffer(avctx, &c->pic); +#ifdef CONFIG_ZLIB + inflateEnd(&(c->zstream)); +#endif + + return 0; +} + +#ifdef CONFIG_MSZH_DECODER +AVCodec mszh_decoder = { + "mszh", + CODEC_TYPE_VIDEO, + CODEC_ID_MSZH, + sizeof(LclDecContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) MSZH"), +}; +#endif + +#ifdef CONFIG_ZLIB_DECODER +AVCodec zlib_decoder = { + "zlib", + CODEC_TYPE_VIDEO, + CODEC_ID_ZLIB, + sizeof(LclDecContext), + decode_init, + NULL, + decode_end, + decode_frame, + CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) ZLIB"), +}; +#endif diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lclenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/lclenc.c new file mode 100644 index 0000000000..2d89998c07 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lclenc.c @@ -0,0 +1,232 @@ +/* + * LCL (LossLess Codec Library) Codec + * Copyright (c) 2002-2004 Roberto Togni + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file lcl.c + * LCL (LossLess Codec Library) Video Codec + * Decoder for MSZH and ZLIB codecs + * Experimental encoder for ZLIB RGB24 + * + * Fourcc: MSZH, ZLIB + * + * Original Win32 dll: + * Ver2.23 By Kenji Oshima 2000.09.20 + * avimszh.dll, avizlib.dll + * + * A description of the decoding algorithm can be found here: + * http://www.pcisys.net/~melanson/codecs + * + * Supports: BGR24 (RGB 24bpp) + * + */ + +#include +#include + +#include "avcodec.h" +#include "bitstream.h" +#include "lcl.h" + +#ifdef CONFIG_ZLIB +#include +#endif + +/* + * Decoder context + */ +typedef struct LclEncContext { + + AVCodecContext *avctx; + AVFrame pic; + PutBitContext pb; + + // Image type + int imgtype; + // Compression type + int compression; + // Flags + int flags; + // Decompressed data size + unsigned int decomp_size; + // Maximum compressed data size + unsigned int max_comp_size; + // Compression buffer + unsigned char* comp_buf; +#ifdef CONFIG_ZLIB + z_stream zstream; +#endif +} LclEncContext; + +/* + * + * Encode a frame + * + */ +static int encode_frame(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ + LclEncContext *c = avctx->priv_data; + AVFrame *pict = data; + AVFrame * const p = &c->pic; + int i; + int zret; // Zlib return code + +#ifndef CONFIG_ZLIB + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled in.\n"); + return -1; +#else + + init_put_bits(&c->pb, buf, buf_size); + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + if(avctx->pix_fmt != PIX_FMT_BGR24){ + av_log(avctx, AV_LOG_ERROR, "Format not supported!\n"); + return -1; + } + + zret = deflateReset(&(c->zstream)); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Deflate reset error: %d\n", zret); + return -1; + } + c->zstream.next_out = c->comp_buf; + c->zstream.avail_out = c->max_comp_size; + + for(i = avctx->height - 1; i >= 0; i--) { + c->zstream.next_in = p->data[0]+p->linesize[0]*i; + c->zstream.avail_in = avctx->width*3; + zret = deflate(&(c->zstream), Z_NO_FLUSH); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Deflate error: %d\n", zret); + return -1; + } + } + zret = deflate(&(c->zstream), Z_FINISH); + if (zret != Z_STREAM_END) { + av_log(avctx, AV_LOG_ERROR, "Deflate error: %d\n", zret); + return -1; + } + + for (i = 0; i < c->zstream.total_out; i++) + put_bits(&c->pb, 8, c->comp_buf[i]); + flush_put_bits(&c->pb); + + return c->zstream.total_out; +#endif +} + +/* + * + * Init lcl encoder + * + */ +static av_cold int encode_init(AVCodecContext *avctx) +{ + LclEncContext *c = avctx->priv_data; + int zret; // Zlib return code + +#ifndef CONFIG_ZLIB + av_log(avctx, AV_LOG_ERROR, "Zlib support not compiled.\n"); + return 1; +#else + + c->avctx= avctx; + + assert(avctx->width && avctx->height); + + avctx->extradata= av_mallocz(8); + avctx->coded_frame= &c->pic; + + // Will be user settable someday + c->compression = 6; + c->flags = 0; + + switch(avctx->pix_fmt){ + case PIX_FMT_BGR24: + c->imgtype = IMGTYPE_RGB24; + c->decomp_size = avctx->width * avctx->height * 3; + avctx->bits_per_sample= 24; + break; + default: + av_log(avctx, AV_LOG_ERROR, "Input pixel format %s not supported\n", avcodec_get_pix_fmt_name(avctx->pix_fmt)); + return -1; + } + + ((uint8_t*)avctx->extradata)[0]= 4; + ((uint8_t*)avctx->extradata)[1]= 0; + ((uint8_t*)avctx->extradata)[2]= 0; + ((uint8_t*)avctx->extradata)[3]= 0; + ((uint8_t*)avctx->extradata)[4]= c->imgtype; + ((uint8_t*)avctx->extradata)[5]= c->compression; + ((uint8_t*)avctx->extradata)[6]= c->flags; + ((uint8_t*)avctx->extradata)[7]= CODEC_ZLIB; + c->avctx->extradata_size= 8; + + c->zstream.zalloc = Z_NULL; + c->zstream.zfree = Z_NULL; + c->zstream.opaque = Z_NULL; + zret = deflateInit(&(c->zstream), c->compression); + if (zret != Z_OK) { + av_log(avctx, AV_LOG_ERROR, "Deflate init error: %d\n", zret); + return 1; + } + + /* Conservative upper bound taken from zlib v1.2.1 source */ + c->max_comp_size = c->decomp_size + ((c->decomp_size + 7) >> 3) + + ((c->decomp_size + 63) >> 6) + 11; + if ((c->comp_buf = av_malloc(c->max_comp_size)) == NULL) { + av_log(avctx, AV_LOG_ERROR, "Can't allocate compression buffer.\n"); + return 1; + } + + return 0; +#endif +} + +/* + * + * Uninit lcl encoder + * + */ +static av_cold int encode_end(AVCodecContext *avctx) +{ + LclEncContext *c = avctx->priv_data; + + av_freep(&avctx->extradata); + av_freep(&c->comp_buf); +#ifdef CONFIG_ZLIB + deflateEnd(&(c->zstream)); +#endif + + return 0; +} + +AVCodec zlib_encoder = { + "zlib", + CODEC_TYPE_VIDEO, + CODEC_ID_ZLIB, + sizeof(LclEncContext), + encode_init, + encode_frame, + encode_end, + .long_name = NULL_IF_CONFIG_SMALL("LCL (LossLess Codec Library) ZLIB"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/liba52.c b/src/add-ons/media/plugins/avcodec/libavcodec/liba52.c new file mode 100644 index 0000000000..ec0a252b5f --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/liba52.c @@ -0,0 +1,227 @@ +/* + * A52 decoder using liba52 + * Copyright (c) 2001 Fabrice Bellard. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file a52dec.c + * A52 decoder using liba52 + */ + +#include "avcodec.h" +#include + +#ifdef CONFIG_LIBA52BIN +#include +static const char* liba52name = "liba52.so.0"; +#endif + +/** + * liba52 - Copyright (C) Aaron Holtzman + * released under the GPL license. + */ +typedef struct AC3DecodeState { + int flags; + int channels; + a52_state_t* state; + sample_t* samples; + + /* + * virtual method table + * + * using this function table so the liba52 doesn't + * have to be really linked together with ffmpeg + * and might be linked in runtime - this allows binary + * distribution of ffmpeg library which doens't depend + * on liba52 library - but if user has it installed + * it will be used - user might install such library + * separately + */ + void* handle; + a52_state_t* (*a52_init)(uint32_t mm_accel); + sample_t* (*a52_samples)(a52_state_t * state); + int (*a52_syncinfo)(uint8_t * buf, int * flags, + int * sample_rate, int * bit_rate); + int (*a52_frame)(a52_state_t * state, uint8_t * buf, int * flags, + sample_t * level, sample_t bias); + void (*a52_dynrng)(a52_state_t * state, + sample_t (* call) (sample_t, void *), void * data); + int (*a52_block)(a52_state_t * state); + void (*a52_free)(a52_state_t * state); + +} AC3DecodeState; + +#ifdef CONFIG_LIBA52BIN +static void* dlsymm(void* handle, const char* symbol) +{ + void* f = dlsym(handle, symbol); + if (!f) + av_log( NULL, AV_LOG_ERROR, "A52 Decoder - function '%s' can't be resolved\n", symbol); + return f; +} +#endif + +static av_cold int a52_decode_init(AVCodecContext *avctx) +{ + AC3DecodeState *s = avctx->priv_data; + +#ifdef CONFIG_LIBA52BIN + s->handle = dlopen(liba52name, RTLD_LAZY); + if (!s->handle) + { + av_log( avctx, AV_LOG_ERROR, "A52 library %s could not be opened! \n%s\n", liba52name, dlerror()); + return -1; + } + s->a52_init = (a52_state_t* (*)(uint32_t)) dlsymm(s->handle, "a52_init"); + s->a52_samples = (sample_t* (*)(a52_state_t*)) dlsymm(s->handle, "a52_samples"); + s->a52_syncinfo = (int (*)(uint8_t*, int*, int*, int*)) dlsymm(s->handle, "a52_syncinfo"); + s->a52_frame = (int (*)(a52_state_t*, uint8_t*, int*, sample_t*, sample_t)) dlsymm(s->handle, "a52_frame"); + s->a52_block = (int (*)(a52_state_t*)) dlsymm(s->handle, "a52_block"); + s->a52_free = (void (*)(a52_state_t*)) dlsymm(s->handle, "a52_free"); + if (!s->a52_init || !s->a52_samples || !s->a52_syncinfo + || !s->a52_frame || !s->a52_block || !s->a52_free) + { + dlclose(s->handle); + return -1; + } +#else + s->handle = 0; + s->a52_init = a52_init; + s->a52_samples = a52_samples; + s->a52_syncinfo = a52_syncinfo; + s->a52_frame = a52_frame; + s->a52_block = a52_block; + s->a52_free = a52_free; +#endif + s->state = s->a52_init(0); /* later use CPU flags */ + s->samples = s->a52_samples(s->state); + + /* allow downmixing to stereo or mono */ + if (avctx->channels > 0 && avctx->request_channels > 0 && + avctx->request_channels < avctx->channels && + avctx->request_channels <= 2) { + avctx->channels = avctx->request_channels; + } + + avctx->sample_fmt = SAMPLE_FMT_S16; + return 0; +} + +/**** the following function comes from a52dec */ +static inline void float_to_int (float * _f, int16_t * s16, int nchannels) +{ + int i, j, c; + int32_t * f = (int32_t *) _f; // XXX assumes IEEE float format + + j = 0; + nchannels *= 256; + for (i = 0; i < 256; i++) { + for (c = 0; c < nchannels; c += 256) + s16[j++] = av_clip_int16(f[i + c] - 0x43c00000); + } +} + +/**** end */ + +#define HEADER_SIZE 7 + +static int a52_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + AC3DecodeState *s = avctx->priv_data; + int flags, i, len; + int sample_rate, bit_rate; + short *out_samples = data; + float level; + static const int ac3_channels[8] = { + 2, 1, 2, 3, 3, 4, 4, 5 + }; + + *data_size= 0; + + if (buf_size < HEADER_SIZE) { + av_log(avctx, AV_LOG_ERROR, "Error decoding frame, not enough bytes for header\n"); + return -1; + } + len = s->a52_syncinfo(buf, &s->flags, &sample_rate, &bit_rate); + if (len == 0) { + av_log(avctx, AV_LOG_ERROR, "Error decoding frame, no sync byte at begin\n"); + return -1; + } + if (buf_size < len) { + av_log(avctx, AV_LOG_ERROR, "Error decoding frame, not enough bytes\n"); + return -1; + } + /* update codec info */ + avctx->sample_rate = sample_rate; + s->channels = ac3_channels[s->flags & 7]; + if (s->flags & A52_LFE) + s->channels++; + if (avctx->request_channels > 0 && + avctx->request_channels <= 2 && + avctx->request_channels < s->channels) { + avctx->channels = avctx->request_channels; + } else { + avctx->channels = s->channels; + } + avctx->bit_rate = bit_rate; + flags = s->flags; + if (avctx->channels == 1) + flags = A52_MONO; + else if (avctx->channels == 2) + flags = A52_STEREO; + else + flags |= A52_ADJUST_LEVEL; + level = 1; + if (s->a52_frame(s->state, buf, &flags, &level, 384)) { + fail: + av_log(avctx, AV_LOG_ERROR, "Error decoding frame\n"); + return -1; + } + for (i = 0; i < 6; i++) { + if (s->a52_block(s->state)) + goto fail; + float_to_int(s->samples, out_samples + i * 256 * avctx->channels, avctx->channels); + } + *data_size = 6 * avctx->channels * 256 * sizeof(int16_t); + return len; +} + +static av_cold int a52_decode_end(AVCodecContext *avctx) +{ + AC3DecodeState *s = avctx->priv_data; + s->a52_free(s->state); +#ifdef CONFIG_LIBA52BIN + dlclose(s->handle); +#endif + return 0; +} + +AVCodec liba52_decoder = { + "liba52", + CODEC_TYPE_AUDIO, + CODEC_ID_AC3, + sizeof(AC3DecodeState), + a52_decode_init, + NULL, + a52_decode_end, + a52_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("liba52 ATSC A/52 / AC-3"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libamr.c b/src/add-ons/media/plugins/avcodec/libavcodec/libamr.c new file mode 100644 index 0000000000..4f56e4d729 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libamr.c @@ -0,0 +1,719 @@ +/* + * AMR Audio decoder stub + * Copyright (c) 2003 the ffmpeg project + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + + /** @file + * Adaptive Multi-Rate (AMR) Audio decoder stub. + * + * This code implements both an AMR-NarrowBand (AMR-NB) and an AMR-WideBand + * (AMR-WB) audio encoder/decoder through external reference code from + * http://www.3gpp.org/. The license of the code from 3gpp is unclear so you + * have to download the code separately. Two versions exists: One fixed-point + * and one floating-point. For some reason the float encoder is significantly + * faster at least on a P4 1.5GHz (0.9s instead of 9.9s on a 30s audio clip + * at MR102). Both float and fixed point are supported for AMR-NB, but only + * float for AMR-WB. + * + * \section AMR-NB + * + * \subsection Float + * The float version (default) can be downloaded from: + * http://www.3gpp.org/ftp/Specs/archive/26_series/26.104/26104-610.zip + * + * \subsection Fixed-point + * The fixed-point (TS26.073) can be downloaded from: + * http://www.3gpp.org/ftp/Specs/archive/26_series/26.073/26073-600.zip + * + * \subsection Specification + * The specification for AMR-NB can be found in TS 26.071 + * (http://www.3gpp.org/ftp/Specs/html-info/26071.htm) and some other + * info at http://www.3gpp.org/ftp/Specs/html-info/26-series.htm. + * + * \section AMR-WB + * + * \subsection Float + * The reference code can be downloaded from: + * http://www.3gpp.org/ftp/Specs/archive/26_series/26.204/26204-600.zip + * + * \subsection Fixed-point + * If someone wants to use the fixed point version it can be downloaded from: + * http://www.3gpp.org/ftp/Specs/archive/26_series/26.173/26173-571.zip. + * + * \subsection Specification + * The specification for AMR-WB can be found in TS 26.171 + * (http://www.3gpp.org/ftp/Specs/html-info/26171.htm) and some other + * info at http://www.3gpp.org/ftp/Specs/html-info/26-series.htm. + * + */ + +#include "avcodec.h" + +#ifdef CONFIG_LIBAMR_NB_FIXED + +#define MMS_IO + +#include "amr/sp_dec.h" +#include "amr/d_homing.h" +#include "amr/typedef.h" +#include "amr/sp_enc.h" +#include "amr/sid_sync.h" +#include "amr/e_homing.h" + +#else +#include +#include +#endif + +static const char *nb_bitrate_unsupported = + "bitrate not supported: use one of 4.75k, 5.15k, 5.9k, 6.7k, 7.4k, 7.95k, 10.2k or 12.2k\n"; +static const char *wb_bitrate_unsupported = + "bitrate not supported: use one of 6.6k, 8.85k, 12.65k, 14.25k, 15.85k, 18.25k, 19.85k, 23.05k, or 23.85k\n"; + +/* Common code for fixed and float version*/ +typedef struct AMR_bitrates +{ + int rate; + enum Mode mode; +} AMR_bitrates; + +/* Match desired bitrate */ +static int getBitrateMode(int bitrate) +{ + /* make the correspondance between bitrate and mode */ + AMR_bitrates rates[]={ {4750,MR475}, + {5150,MR515}, + {5900,MR59}, + {6700,MR67}, + {7400,MR74}, + {7950,MR795}, + {10200,MR102}, + {12200,MR122}, + }; + int i; + + for(i=0;i<8;i++) + { + if(rates[i].rate==bitrate) + { + return rates[i].mode; + } + } + /* no bitrate matching, return an error */ + return -1; +} + +static void amr_decode_fix_avctx(AVCodecContext * avctx) +{ + const int is_amr_wb = 1 + (avctx->codec_id == CODEC_ID_AMR_WB); + + if(avctx->sample_rate == 0) + { + avctx->sample_rate = 8000 * is_amr_wb; + } + + if(avctx->channels == 0) + { + avctx->channels = 1; + } + + avctx->frame_size = 160 * is_amr_wb; + avctx->sample_fmt = SAMPLE_FMT_S16; +} + +#ifdef CONFIG_LIBAMR_NB_FIXED +/* fixed point version*/ +/* frame size in serial bitstream file (frame type + serial stream + flags) */ +#define SERIAL_FRAMESIZE (1+MAX_SERIAL_SIZE+5) + +typedef struct AMRContext { + int frameCount; + Speech_Decode_FrameState *speech_decoder_state; + enum RXFrameType rx_type; + enum Mode mode; + Word16 reset_flag; + Word16 reset_flag_old; + + int enc_bitrate; + Speech_Encode_FrameState *enstate; + sid_syncState *sidstate; + enum TXFrameType tx_frametype; +} AMRContext; + +static int amr_nb_decode_init(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + s->frameCount=0; + s->speech_decoder_state=NULL; + s->rx_type = (enum RXFrameType)0; + s->mode= (enum Mode)0; + s->reset_flag=0; + s->reset_flag_old=1; + + if(Speech_Decode_Frame_init(&s->speech_decoder_state, "Decoder")) + { + av_log(avctx, AV_LOG_ERROR, "Speech_Decode_Frame_init error\n"); + return -1; + } + + amr_decode_fix_avctx(avctx); + + if(avctx->channels > 1) + { + av_log(avctx, AV_LOG_ERROR, "amr_nb: multichannel decoding not supported\n"); + return -1; + } + + return 0; +} + +static int amr_nb_encode_init(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + s->frameCount=0; + s->speech_decoder_state=NULL; + s->rx_type = (enum RXFrameType)0; + s->mode= (enum Mode)0; + s->reset_flag=0; + s->reset_flag_old=1; + + if(avctx->sample_rate!=8000) + { + av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n"); + return -1; + } + + if(avctx->channels!=1) + { + av_log(avctx, AV_LOG_ERROR, "Only mono supported\n"); + return -1; + } + + avctx->frame_size=160; + avctx->coded_frame= avcodec_alloc_frame(); + + if(Speech_Encode_Frame_init(&s->enstate, 0, "encoder") || sid_sync_init (&s->sidstate)) + { + av_log(avctx, AV_LOG_ERROR, "Speech_Encode_Frame_init error\n"); + return -1; + } + + if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0) + { + av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported); + return -1; + } + + return 0; +} + +static int amr_nb_encode_close(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + Speech_Encode_Frame_exit(&s->enstate); + sid_sync_exit (&s->sidstate); + av_freep(&avctx->coded_frame); + return 0; +} + +static int amr_nb_decode_close(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + Speech_Decode_Frame_exit(&s->speech_decoder_state); + return 0; +} + +static int amr_nb_decode_frame(AVCodecContext * avctx, + void *data, int *data_size, + uint8_t * buf, int buf_size) +{ + AMRContext *s = avctx->priv_data; + uint8_t*amrData=buf; + int offset=0; + UWord8 toc, q, ft; + Word16 serial[SERIAL_FRAMESIZE]; /* coded bits */ + Word16 *synth; + UWord8 *packed_bits; + static Word16 packed_size[16] = {12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0}; + int i; + + //printf("amr_decode_frame data_size=%i buf=0x%X buf_size=%d frameCount=%d!!\n",*data_size,buf,buf_size,s->frameCount); + + synth=data; + + toc=amrData[offset]; + /* read rest of the frame based on ToC byte */ + q = (toc >> 2) & 0x01; + ft = (toc >> 3) & 0x0F; + + //printf("offset=%d, packet_size=%d amrData= 0x%X %X %X %X\n",offset,packed_size[ft],amrData[offset],amrData[offset+1],amrData[offset+2],amrData[offset+3]); + + offset++; + + packed_bits=amrData+offset; + + offset+=packed_size[ft]; + + //Unsort and unpack bits + s->rx_type = UnpackBits(q, ft, packed_bits, &s->mode, &serial[1]); + + //We have a new frame + s->frameCount++; + + if (s->rx_type == RX_NO_DATA) + { + s->mode = s->speech_decoder_state->prev_mode; + } + else { + s->speech_decoder_state->prev_mode = s->mode; + } + + /* if homed: check if this frame is another homing frame */ + if (s->reset_flag_old == 1) + { + /* only check until end of first subframe */ + s->reset_flag = decoder_homing_frame_test_first(&serial[1], s->mode); + } + /* produce encoder homing frame if homed & input=decoder homing frame */ + if ((s->reset_flag != 0) && (s->reset_flag_old != 0)) + { + for (i = 0; i < L_FRAME; i++) + { + synth[i] = EHF_MASK; + } + } + else + { + /* decode frame */ + Speech_Decode_Frame(s->speech_decoder_state, s->mode, &serial[1], s->rx_type, synth); + } + + //Each AMR-frame results in 160 16-bit samples + *data_size=160*2; + + /* if not homed: check whether current frame is a homing frame */ + if (s->reset_flag_old == 0) + { + /* check whole frame */ + s->reset_flag = decoder_homing_frame_test(&serial[1], s->mode); + } + /* reset decoder if current frame is a homing frame */ + if (s->reset_flag != 0) + { + Speech_Decode_Frame_reset(s->speech_decoder_state); + } + s->reset_flag_old = s->reset_flag; + + return offset; +} + + +static int amr_nb_encode_frame(AVCodecContext *avctx, + unsigned char *frame/*out*/, int buf_size, void *data/*in*/) +{ + short serial_data[250] = {0}; + AMRContext *s = avctx->priv_data; + int written; + + s->reset_flag = encoder_homing_frame_test(data); + + Speech_Encode_Frame(s->enstate, s->enc_bitrate, data, &serial_data[1], &s->mode); + + /* add frame type and mode */ + sid_sync (s->sidstate, s->mode, &s->tx_frametype); + + written = PackBits(s->mode, s->enc_bitrate, s->tx_frametype, &serial_data[1], frame); + + if (s->reset_flag != 0) + { + Speech_Encode_Frame_reset(s->enstate); + sid_sync_reset(s->sidstate); + } + return written; +} + + +#elif defined(CONFIG_LIBAMR_NB) /* Float point version*/ + +typedef struct AMRContext { + int frameCount; + void * decState; + int *enstate; + int enc_bitrate; +} AMRContext; + +static int amr_nb_decode_init(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + s->frameCount=0; + s->decState=Decoder_Interface_init(); + if(!s->decState) + { + av_log(avctx, AV_LOG_ERROR, "Decoder_Interface_init error\r\n"); + return -1; + } + + amr_decode_fix_avctx(avctx); + + if(avctx->channels > 1) + { + av_log(avctx, AV_LOG_ERROR, "amr_nb: multichannel decoding not supported\n"); + return -1; + } + + return 0; +} + +static int amr_nb_encode_init(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + s->frameCount=0; + + if(avctx->sample_rate!=8000) + { + av_log(avctx, AV_LOG_ERROR, "Only 8000Hz sample rate supported\n"); + return -1; + } + + if(avctx->channels!=1) + { + av_log(avctx, AV_LOG_ERROR, "Only mono supported\n"); + return -1; + } + + avctx->frame_size=160; + avctx->coded_frame= avcodec_alloc_frame(); + + s->enstate=Encoder_Interface_init(0); + if(!s->enstate) + { + av_log(avctx, AV_LOG_ERROR, "Encoder_Interface_init error\n"); + return -1; + } + + if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0) + { + av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported); + return -1; + } + + return 0; +} + +static int amr_nb_decode_close(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + Decoder_Interface_exit(s->decState); + return 0; +} + +static int amr_nb_encode_close(AVCodecContext * avctx) +{ + AMRContext *s = avctx->priv_data; + + Encoder_Interface_exit(s->enstate); + av_freep(&avctx->coded_frame); + return 0; +} + +static int amr_nb_decode_frame(AVCodecContext * avctx, + void *data, int *data_size, + uint8_t * buf, int buf_size) +{ + AMRContext *s = avctx->priv_data; + uint8_t*amrData=buf; + static const uint8_t block_size[16]={ 12, 13, 15, 17, 19, 20, 26, 31, 5, 0, 0, 0, 0, 0, 0, 0 }; + enum Mode dec_mode; + int packet_size; + + /* av_log(NULL,AV_LOG_DEBUG,"amr_decode_frame buf=%p buf_size=%d frameCount=%d!!\n",buf,buf_size,s->frameCount); */ + + dec_mode = (buf[0] >> 3) & 0x000F; + packet_size = block_size[dec_mode]+1; + + if(packet_size > buf_size) { + av_log(avctx, AV_LOG_ERROR, "amr frame too short (%u, should be %u)\n", buf_size, packet_size); + return -1; + } + + s->frameCount++; + /* av_log(NULL,AV_LOG_DEBUG,"packet_size=%d amrData= 0x%X %X %X %X\n",packet_size,amrData[0],amrData[1],amrData[2],amrData[3]); */ + /* call decoder */ + Decoder_Interface_Decode(s->decState, amrData, data, 0); + *data_size=160*2; + + return packet_size; +} + +static int amr_nb_encode_frame(AVCodecContext *avctx, + unsigned char *frame/*out*/, int buf_size, void *data/*in*/) +{ + AMRContext *s = avctx->priv_data; + int written; + + if((s->enc_bitrate=getBitrateMode(avctx->bit_rate))<0) + { + av_log(avctx, AV_LOG_ERROR, nb_bitrate_unsupported); + return -1; + } + + written = Encoder_Interface_Encode(s->enstate, + s->enc_bitrate, + data, + frame, + 0); + /* av_log(NULL,AV_LOG_DEBUG,"amr_nb_encode_frame encoded %u bytes, bitrate %u, first byte was %#02x\n",written, s->enc_bitrate, frame[0] ); */ + + return written; +} + +#endif + +#if defined(CONFIG_LIBAMR_NB) || defined(CONFIG_LIBAMR_NB_FIXED) + +AVCodec libamr_nb_decoder = +{ + "libamr_nb", + CODEC_TYPE_AUDIO, + CODEC_ID_AMR_NB, + sizeof(AMRContext), + amr_nb_decode_init, + NULL, + amr_nb_decode_close, + amr_nb_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band"), +}; + +AVCodec libamr_nb_encoder = +{ + "libamr_nb", + CODEC_TYPE_AUDIO, + CODEC_ID_AMR_NB, + sizeof(AMRContext), + amr_nb_encode_init, + amr_nb_encode_frame, + amr_nb_encode_close, + NULL, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libamr-nb Adaptive Multi-Rate (AMR) Narrow-Band"), +}; + +#endif + +/* -----------AMR wideband ------------*/ +#ifdef CONFIG_LIBAMR_WB + +#ifdef _TYPEDEF_H +//To avoid duplicate typedefs from typedef in amr-nb +#define typedef_h +#endif + +#include +#include +#include + +/* Common code for fixed and float version*/ +typedef struct AMRWB_bitrates +{ + int rate; + int mode; +} AMRWB_bitrates; + +static int getWBBitrateMode(int bitrate) +{ + /* make the correspondance between bitrate and mode */ + AMRWB_bitrates rates[]={ {6600,0}, + {8850,1}, + {12650,2}, + {14250,3}, + {15850,4}, + {18250,5}, + {19850,6}, + {23050,7}, + {23850,8}, + }; + int i; + + for(i=0;i<9;i++) + { + if(rates[i].rate==bitrate) + { + return rates[i].mode; + } + } + /* no bitrate matching, return an error */ + return -1; +} + + +typedef struct AMRWBContext { + int frameCount; + void *state; + int mode; + Word16 allow_dtx; +} AMRWBContext; + +static int amr_wb_encode_init(AVCodecContext * avctx) +{ + AMRWBContext *s = avctx->priv_data; + + s->frameCount=0; + + if(avctx->sample_rate!=16000) + { + av_log(avctx, AV_LOG_ERROR, "Only 16000Hz sample rate supported\n"); + return -1; + } + + if(avctx->channels!=1) + { + av_log(avctx, AV_LOG_ERROR, "Only mono supported\n"); + return -1; + } + + if((s->mode=getWBBitrateMode(avctx->bit_rate))<0) + { + av_log(avctx, AV_LOG_ERROR, wb_bitrate_unsupported); + return -1; + } + + avctx->frame_size=320; + avctx->coded_frame= avcodec_alloc_frame(); + + s->state = E_IF_init(); + s->allow_dtx=0; + + return 0; +} + +static int amr_wb_encode_close(AVCodecContext * avctx) +{ + AMRWBContext *s = avctx->priv_data; + + E_IF_exit(s->state); + av_freep(&avctx->coded_frame); + s->frameCount++; + return 0; +} + +static int amr_wb_encode_frame(AVCodecContext *avctx, + unsigned char *frame/*out*/, int buf_size, void *data/*in*/) +{ + AMRWBContext *s = avctx->priv_data; + int size; + + if((s->mode=getWBBitrateMode(avctx->bit_rate))<0) + { + av_log(avctx, AV_LOG_ERROR, wb_bitrate_unsupported); + return -1; + } + size = E_IF_encode(s->state, s->mode, data, frame, s->allow_dtx); + return size; +} + +static int amr_wb_decode_init(AVCodecContext * avctx) +{ + AMRWBContext *s = avctx->priv_data; + + s->frameCount=0; + s->state = D_IF_init(); + + amr_decode_fix_avctx(avctx); + + if(avctx->channels > 1) + { + av_log(avctx, AV_LOG_ERROR, "amr_wb: multichannel decoding not supported\n"); + return -1; + } + + return 0; +} + +static int amr_wb_decode_frame(AVCodecContext * avctx, + void *data, int *data_size, + uint8_t * buf, int buf_size) +{ + AMRWBContext *s = avctx->priv_data; + uint8_t*amrData=buf; + int mode; + int packet_size; + static const uint8_t block_size[16] = {18, 23, 33, 37, 41, 47, 51, 59, 61, 6, 6, 0, 0, 0, 1, 1}; + + if(buf_size==0) { + /* nothing to do */ + return 0; + } + + mode = (amrData[0] >> 3) & 0x000F; + packet_size = block_size[mode]; + + if(packet_size > buf_size) { + av_log(avctx, AV_LOG_ERROR, "amr frame too short (%u, should be %u)\n", buf_size, packet_size+1); + return -1; + } + + s->frameCount++; + D_IF_decode( s->state, amrData, data, _good_frame); + *data_size=320*2; + return packet_size; +} + +static int amr_wb_decode_close(AVCodecContext * avctx) +{ + AMRWBContext *s = avctx->priv_data; + + D_IF_exit(s->state); + return 0; +} + +AVCodec libamr_wb_decoder = +{ + "libamr_wb", + CODEC_TYPE_AUDIO, + CODEC_ID_AMR_WB, + sizeof(AMRWBContext), + amr_wb_decode_init, + NULL, + amr_wb_decode_close, + amr_wb_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("libamr-wb Adaptive Multi-Rate (AMR) Wide-Band"), +}; + +AVCodec libamr_wb_encoder = +{ + "libamr_wb", + CODEC_TYPE_AUDIO, + CODEC_ID_AMR_WB, + sizeof(AMRWBContext), + amr_wb_encode_init, + amr_wb_encode_frame, + amr_wb_encode_close, + NULL, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libamr-wb Adaptive Multi-Rate (AMR) Wide-Band"), +}; + +#endif //CONFIG_LIBAMR_WB diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libdirac.h b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac.h new file mode 100644 index 0000000000..31cd5738d7 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac.h @@ -0,0 +1,49 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libdirac.h +* data structures common to libdiracenc.c and libdiracdec.c +*/ + +#ifndef FFMPEG_LIBDIRAC_H +#define FFMPEG_LIBDIRAC_H + +#include "config.h" + +#ifdef CONFIG_LIBDIRAC + +#include "avcodec.h" +#include + +/** +* Table providing a Dirac chroma format to FFmpeg pixel format mapping. +*/ +static const struct { + enum PixelFormat ff_pix_fmt; + dirac_chroma_t dirac_pix_fmt; +} ffmpeg_dirac_pixel_format_map[] = { + { PIX_FMT_YUV420P, format420 }, + { PIX_FMT_YUV422P, format422 }, + { PIX_FMT_YUV444P, format444 }, +}; + +#endif /* CONFIG_LIBDIRAC */ +#endif /* FFMPEG_LIBDIRAC_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.c b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.c new file mode 100644 index 0000000000..416eb59804 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.c @@ -0,0 +1,117 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libdirac_libschro.c +* functions common to libdirac and libschroedinger +*/ + +#include "libdirac_libschro.h" + +static const FfmpegDiracSchroVideoFormatInfo ff_dirac_schro_video_format_info[] = { + { 640, 480, 24000, 1001}, + { 176, 120, 15000, 1001}, + { 176, 144, 25, 2 }, + { 352, 240, 15000, 1001}, + { 352, 288, 25, 2 }, + { 704, 480, 15000, 1001}, + { 704, 576, 25, 2 }, + { 720, 480, 30000, 1001}, + { 720, 576, 25, 1 }, + { 1280, 720, 60000, 1001}, + { 1280, 720, 50, 1 }, + { 1920, 1080, 30000, 1001}, + { 1920, 1080, 25, 1 }, + { 1920, 1080, 60000, 1001}, + { 1920, 1080, 50, 1 }, + { 2048, 1080, 24, 1 }, + { 4096, 2160, 24, 1 }, +}; + +unsigned int ff_dirac_schro_get_video_format_idx (AVCodecContext *avccontext) +{ + unsigned int ret_idx = 0; + unsigned int idx; + unsigned int num_formats = sizeof(ff_dirac_schro_video_format_info) / + sizeof(ff_dirac_schro_video_format_info[0]); + + for (idx = 1 ; idx < num_formats; ++idx ) { + const FfmpegDiracSchroVideoFormatInfo *vf = + &ff_dirac_schro_video_format_info[idx]; + if (avccontext->width == vf->width && + avccontext->height == vf->height){ + ret_idx = idx; + if (avccontext->time_base.den == vf->frame_rate_num && + avccontext->time_base.num == vf->frame_rate_denom) { + return idx; + } + } + } + return ret_idx; +} + +void ff_dirac_schro_queue_init (FfmpegDiracSchroQueue *queue) +{ + queue->p_head = queue->p_tail = NULL; + queue->size = 0; +} + +void ff_dirac_schro_queue_free (FfmpegDiracSchroQueue *queue, + void (*free_func)(void *)) +{ + while (queue->p_head) { + free_func( ff_dirac_schro_queue_pop(queue) ); + } +} + +int ff_dirac_schro_queue_push_back (FfmpegDiracSchroQueue *queue, void *p_data) +{ + FfmpegDiracSchroQueueElement *p_new = + av_mallocz(sizeof(FfmpegDiracSchroQueueElement)); + + if (p_new == NULL) + return -1; + + p_new->data = p_data; + + if (queue->p_head == NULL) + queue->p_head = p_new; + else + queue->p_tail->next = p_new; + queue->p_tail = p_new; + + ++queue->size; + return 0; +} + +void *ff_dirac_schro_queue_pop (FfmpegDiracSchroQueue *queue) +{ + FfmpegDiracSchroQueueElement *top = queue->p_head; + + if (top != NULL) { + void *data = top->data; + queue->p_head = queue->p_head->next; + --queue->size; + av_freep (&top); + return data; + } + + return NULL; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.h b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.h new file mode 100644 index 0000000000..81a0fe4b3e --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libdirac_libschro.h @@ -0,0 +1,109 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libdirac_libschro.h +* data structures common to libdirac and libschroedinger +*/ + +#ifndef FFMPEG_LIBDIRAC_LIBSCHRO_H +#define FFMPEG_LIBDIRAC_LIBSCHRO_H + +#include "avcodec.h" + +typedef struct +{ + uint16_t width; + uint16_t height; + uint16_t frame_rate_num; + uint16_t frame_rate_denom; +} FfmpegDiracSchroVideoFormatInfo; + +/** +* Returns the index into the Dirac Schro common video format info table +*/ +unsigned int ff_dirac_schro_get_video_format_idx (AVCodecContext *avccontext); + +/** +* contains a single encoded frame returned from Dirac or Schroedinger +*/ +typedef struct FfmpegDiracSchroEncodedFrame +{ + /** encoded frame data */ + uint8_t *p_encbuf; + + /** encoded frame size */ + uint32_t size; + + /** encoded frame number. Will be used as pts */ + uint32_t frame_num; + + /** key frame flag. 1 : is key frame , 0 : in not key frame */ + uint16_t key_frame; +} FfmpegDiracSchroEncodedFrame; + +/** +* queue element +*/ +typedef struct FfmpegDiracSchroQueueElement +{ + /** Data to be stored in queue*/ + void *data; + /** Pointer to next element queue */ + struct FfmpegDiracSchroQueueElement *next; +} FfmpegDiracSchroQueueElement; + + +/** +* A simple queue implementation used in libdirac and libschroedinger +*/ +typedef struct FfmpegDiracSchroQueue +{ + /** Pointer to head of queue */ + FfmpegDiracSchroQueueElement *p_head; + /** Pointer to tail of queue */ + FfmpegDiracSchroQueueElement *p_tail; + /** Queue size*/ + int size; +} FfmpegDiracSchroQueue; + +/** +* Initialise the queue +*/ +void ff_dirac_schro_queue_init(FfmpegDiracSchroQueue *queue); + +/** +* Add an element to the end of the queue +*/ +int ff_dirac_schro_queue_push_back (FfmpegDiracSchroQueue *queue, void *p_data); + +/** +* Return the first element in the queue +*/ +void *ff_dirac_schro_queue_pop (FfmpegDiracSchroQueue *queue); + +/** +* Free the queue resources. free_func is a function supplied by the caller to +* free any resources allocated by the caller. The data field of the queue +* element is passed to it. +*/ +void ff_dirac_schro_queue_free(FfmpegDiracSchroQueue *queue, + void (*free_func)(void *)); +#endif /* FFMPEG_LIBDIRAC_LIBSCHRO_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libdiracdec.c b/src/add-ons/media/plugins/avcodec/libavcodec/libdiracdec.c new file mode 100644 index 0000000000..06830f76d9 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libdiracdec.c @@ -0,0 +1,209 @@ +/* + * Dirac decoder support via libdirac library + * Copyright (c) 2005 BBC, Andrew Kennedy + * Copyright (c) 2006-2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libdiracdec.c +* Dirac decoder support via libdirac library; more details about the Dirac +* project can be found at http://dirac.sourceforge.net/. +* The libdirac_decoder library implements Dirac specification version 2.2 +* (http://dirac.sourceforge.net/specification.html). +*/ + +#include "libdirac.h" + +#undef NDEBUG +#include + +#include + +/** contains a single frame returned from Dirac */ +typedef struct FfmpegDiracDecoderParams +{ + /** decoder handle */ + dirac_decoder_t* p_decoder; + + /** buffer to hold decoded frame */ + unsigned char* p_out_frame_buf; +} FfmpegDiracDecoderParams; + + +/** +* returns FFmpeg chroma format +*/ +static enum PixelFormat GetFfmpegChromaFormat(dirac_chroma_t dirac_pix_fmt) +{ + int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) / + sizeof(ffmpeg_dirac_pixel_format_map[0]); + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt == dirac_pix_fmt) { + return ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt; + } + } + return PIX_FMT_NONE; +} + +static int libdirac_decode_init(AVCodecContext *avccontext) +{ + + FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data ; + p_dirac_params->p_decoder = dirac_decoder_init(avccontext->debug); + + if (!p_dirac_params->p_decoder) + return -1; + + return 0 ; +} + +static int libdirac_decode_frame(AVCodecContext *avccontext, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + + FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data; + AVPicture *picture = data; + AVPicture pic; + int pict_size; + unsigned char *buffer[3]; + + *data_size = 0; + + if (buf_size>0) + /* set data to decode into buffer */ + dirac_buffer (p_dirac_params->p_decoder, buf, buf+buf_size); + + while (1) { + /* parse data and process result */ + DecoderState state = dirac_parse (p_dirac_params->p_decoder); + switch (state) + { + case STATE_BUFFER: + return buf_size; + + case STATE_SEQUENCE: + { + /* tell FFmpeg about sequence details */ + dirac_sourceparams_t *src_params = + &p_dirac_params->p_decoder->src_params; + + if (avcodec_check_dimensions(avccontext, src_params->width, + src_params->height) < 0) { + av_log(avccontext, AV_LOG_ERROR, "Invalid dimensions (%dx%d)\n", + src_params->width, src_params->height); + avccontext->height = avccontext->width = 0; + return -1; + } + + avccontext->height = src_params->height; + avccontext->width = src_params->width; + + avccontext->pix_fmt = GetFfmpegChromaFormat(src_params->chroma); + if (avccontext->pix_fmt == PIX_FMT_NONE) { + av_log (avccontext, AV_LOG_ERROR, + "Dirac chroma format %d not supported currently\n", + src_params->chroma); + return -1; + } + + avccontext->time_base.den = src_params->frame_rate.numerator; + avccontext->time_base.num = src_params->frame_rate.denominator; + + /* calculate output dimensions */ + avpicture_fill(&pic, NULL, avccontext->pix_fmt, + avccontext->width, avccontext->height); + + pict_size = avpicture_get_size(avccontext->pix_fmt, + avccontext->width, + avccontext->height); + + /* allocate output buffer */ + if (p_dirac_params->p_out_frame_buf == NULL) + p_dirac_params->p_out_frame_buf = av_malloc (pict_size); + buffer[0] = p_dirac_params->p_out_frame_buf; + buffer[1] = p_dirac_params->p_out_frame_buf + + pic.linesize[0] * avccontext->height; + buffer[2] = buffer[1] + + pic.linesize[1] * src_params->chroma_height; + + /* tell Dirac about output destination */ + dirac_set_buf(p_dirac_params->p_decoder, buffer, NULL); + break; + } + case STATE_SEQUENCE_END: + break; + + case STATE_PICTURE_AVAIL: + /* fill picture with current buffer data from Dirac */ + avpicture_fill(picture, p_dirac_params->p_out_frame_buf, + avccontext->pix_fmt, + avccontext->width, avccontext->height); + *data_size = sizeof(AVPicture); + return buf_size; + + case STATE_INVALID: + return -1; + + default: + break; + } + } + + return buf_size; +} + + +static int libdirac_decode_close(AVCodecContext *avccontext) +{ + FfmpegDiracDecoderParams *p_dirac_params = avccontext->priv_data; + dirac_decoder_close (p_dirac_params->p_decoder); + + av_freep(&p_dirac_params->p_out_frame_buf); + + return 0 ; +} + +static void libdirac_flush (AVCodecContext *avccontext) +{ + /* Got a seek request. We will need free memory held in the private + * context and free the current Dirac decoder handle and then open + * a new decoder handle. */ + libdirac_decode_close (avccontext); + libdirac_decode_init (avccontext); + return; +} + + + +AVCodec libdirac_decoder = { + "libdirac", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegDiracDecoderParams), + libdirac_decode_init, + NULL, + libdirac_decode_close, + libdirac_decode_frame, + CODEC_CAP_DELAY, + .flush = libdirac_flush, + .long_name = NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"), +} ; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libdiracenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/libdiracenc.c new file mode 100644 index 0000000000..ee827ce1ea --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libdiracenc.c @@ -0,0 +1,420 @@ +/* + * Dirac encoding support via libdirac library + * Copyright (c) 2005 BBC, Andrew Kennedy + * Copyright (c) 2006-2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libdiracenc.c +* Dirac encoding support via libdirac library; more details about the +* Dirac project can be found at http://dirac.sourceforge.net/. +* The libdirac_encoder library implements Dirac specification version 2.2 +* (http://dirac.sourceforge.net/specification.html). +*/ + +#include "libdirac_libschro.h" +#include "libdirac.h" + +#undef NDEBUG +#include + + +#include + +/** Dirac encoder private data */ +typedef struct FfmpegDiracEncoderParams +{ + /** Dirac encoder context */ + dirac_encoder_context_t enc_ctx; + + /** frame being encoded */ + AVFrame picture; + + /** frame size */ + int frame_size; + + /** Dirac encoder handle */ + dirac_encoder_t* p_encoder; + + /** input frame buffer */ + unsigned char *p_in_frame_buf; + + /** buffer to store encoder output before writing it to the frame queue */ + unsigned char *enc_buf; + + /** size of encoder buffer */ + int enc_buf_size; + + /** queue storing encoded frames */ + FfmpegDiracSchroQueue enc_frame_queue; + + /** end of sequence signalled by user, 0 - false, 1 - true */ + int eos_signalled; + + /** end of sequence returned by encoder, 0 - false, 1 - true */ + int eos_pulled; +} FfmpegDiracEncoderParams; + +/** +* Works out Dirac-compatible chroma format. +*/ +static dirac_chroma_t GetDiracChromaFormat(enum PixelFormat ff_pix_fmt) +{ + int num_formats = sizeof(ffmpeg_dirac_pixel_format_map) / + sizeof(ffmpeg_dirac_pixel_format_map[0]); + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_dirac_pixel_format_map[idx].ff_pix_fmt == ff_pix_fmt) { + return ffmpeg_dirac_pixel_format_map[idx].dirac_pix_fmt; + } + } + return formatNK; +} + +/** +* Dirac video preset table. Ensure that this tables matches up correctly +* with the ff_dirac_schro_video_format_info table in libdirac_libschro.c. +*/ +static const VideoFormat ff_dirac_video_formats[]={ + VIDEO_FORMAT_CUSTOM , + VIDEO_FORMAT_QSIF525 , + VIDEO_FORMAT_QCIF , + VIDEO_FORMAT_SIF525 , + VIDEO_FORMAT_CIF , + VIDEO_FORMAT_4SIF525 , + VIDEO_FORMAT_4CIF , + VIDEO_FORMAT_SD_480I60 , + VIDEO_FORMAT_SD_576I50 , + VIDEO_FORMAT_HD_720P60 , + VIDEO_FORMAT_HD_720P50 , + VIDEO_FORMAT_HD_1080I60 , + VIDEO_FORMAT_HD_1080I50 , + VIDEO_FORMAT_HD_1080P60 , + VIDEO_FORMAT_HD_1080P50 , + VIDEO_FORMAT_DIGI_CINEMA_2K24 , + VIDEO_FORMAT_DIGI_CINEMA_4K24 , +}; + +/** +* Returns the video format preset matching the input video dimensions and +* time base. +*/ +static VideoFormat GetDiracVideoFormatPreset (AVCodecContext *avccontext) +{ + unsigned int num_formats = sizeof(ff_dirac_video_formats) / + sizeof(ff_dirac_video_formats[0]); + + unsigned int idx = ff_dirac_schro_get_video_format_idx (avccontext); + + return (idx < num_formats) ? + ff_dirac_video_formats[idx] : VIDEO_FORMAT_CUSTOM; +} + +static int libdirac_encode_init(AVCodecContext *avccontext) +{ + + FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data; + int no_local = 1; + int verbose = avccontext->debug; + VideoFormat preset; + + /* get Dirac preset */ + preset = GetDiracVideoFormatPreset(avccontext); + + /* initialize the encoder context */ + dirac_encoder_context_init (&(p_dirac_params->enc_ctx), preset); + + p_dirac_params->enc_ctx.src_params.chroma = + GetDiracChromaFormat(avccontext->pix_fmt); + + if (p_dirac_params->enc_ctx.src_params.chroma == formatNK) { + av_log (avccontext, AV_LOG_ERROR, + "Unsupported pixel format %d. This codec supports only " + "Planar YUV formats (yuv420p, yuv422p, yuv444p\n", + avccontext->pix_fmt); + return -1; + } + + p_dirac_params->enc_ctx.src_params.frame_rate.numerator = + avccontext->time_base.den; + p_dirac_params->enc_ctx.src_params.frame_rate.denominator = + avccontext->time_base.num; + + p_dirac_params->enc_ctx.src_params.width = avccontext->width; + p_dirac_params->enc_ctx.src_params.height = avccontext->height; + + p_dirac_params->frame_size = avpicture_get_size(avccontext->pix_fmt, + avccontext->width, + avccontext->height); + + avccontext->coded_frame = &p_dirac_params->picture; + + if (no_local) { + p_dirac_params->enc_ctx.decode_flag = 0; + p_dirac_params->enc_ctx.instr_flag = 0; + } else { + p_dirac_params->enc_ctx.decode_flag = 1; + p_dirac_params->enc_ctx.instr_flag = 1; + } + + /* Intra-only sequence */ + if (avccontext->gop_size == 0 ) + p_dirac_params->enc_ctx.enc_params.num_L1 = 0; + else + avccontext->has_b_frames = 1; + + if (avccontext->flags & CODEC_FLAG_QSCALE) { + if (avccontext->global_quality != 0) { + p_dirac_params->enc_ctx.enc_params.qf = + avccontext->global_quality / (FF_QP2LAMBDA*10.0); + /* if it is not default bitrate then send target rate. */ + if (avccontext->bit_rate >= 1000 && + avccontext->bit_rate != 200000) { + p_dirac_params->enc_ctx.enc_params.trate = + avccontext->bit_rate / 1000; + } + } else + p_dirac_params->enc_ctx.enc_params.lossless = 1; + } else if (avccontext->bit_rate >= 1000) + p_dirac_params->enc_ctx.enc_params.trate = avccontext->bit_rate / 1000; + + if ((preset > VIDEO_FORMAT_QCIF || preset < VIDEO_FORMAT_QSIF525) && + avccontext->bit_rate == 200000) { + p_dirac_params->enc_ctx.enc_params.trate = 0; + } + + if (avccontext->flags & CODEC_FLAG_INTERLACED_ME) { + /* all material can be coded as interlaced or progressive + * irrespective of the type of source material */ + p_dirac_params->enc_ctx.enc_params.picture_coding_mode = 1; + } + + p_dirac_params->p_encoder = dirac_encoder_init (&(p_dirac_params->enc_ctx), + verbose ); + + if (!p_dirac_params->p_encoder) { + av_log(avccontext, AV_LOG_ERROR, + "Unrecoverable Error: dirac_encoder_init failed. "); + return EXIT_FAILURE; + } + + /* allocate enough memory for the incoming data */ + p_dirac_params->p_in_frame_buf = av_malloc(p_dirac_params->frame_size); + + /* initialize the encoded frame queue */ + ff_dirac_schro_queue_init(&p_dirac_params->enc_frame_queue); + + return 0 ; +} + +static void DiracFreeFrame (void *data) +{ + FfmpegDiracSchroEncodedFrame *enc_frame = data; + + av_freep (&(enc_frame->p_encbuf)); + av_free(enc_frame); +} + +static int libdirac_encode_frame(AVCodecContext *avccontext, + unsigned char *frame, + int buf_size, void *data) +{ + int enc_size = 0; + dirac_encoder_state_t state; + FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data; + FfmpegDiracSchroEncodedFrame* p_frame_output = NULL; + FfmpegDiracSchroEncodedFrame* p_next_output_frame = NULL; + int go = 1; + int last_frame_in_sequence = 0; + + if (data == NULL) { + /* push end of sequence if not already signalled */ + if (!p_dirac_params->eos_signalled) { + dirac_encoder_end_sequence( p_dirac_params->p_encoder ); + p_dirac_params->eos_signalled = 1; + } + } else { + + /* Allocate frame data to Dirac input buffer. + * Input line size may differ from what the codec supports, + * especially when transcoding from one format to another. + * So use avpicture_layout to copy the frame. */ + avpicture_layout ((AVPicture *)data, avccontext->pix_fmt, + avccontext->width, avccontext->height, + p_dirac_params->p_in_frame_buf, + p_dirac_params->frame_size); + + /* load next frame */ + if (dirac_encoder_load (p_dirac_params->p_encoder, + p_dirac_params->p_in_frame_buf, + p_dirac_params->frame_size ) < 0) { + av_log(avccontext, AV_LOG_ERROR, "Unrecoverable Encoder Error." + " dirac_encoder_load failed...\n"); + return -1; + } + } + + if (p_dirac_params->eos_pulled) + go = 0; + + while(go) { + p_dirac_params->p_encoder->enc_buf.buffer = frame; + p_dirac_params->p_encoder->enc_buf.size = buf_size; + /* process frame */ + state = dirac_encoder_output ( p_dirac_params->p_encoder ); + + switch (state) + { + case ENC_STATE_AVAIL: + case ENC_STATE_EOS: + assert (p_dirac_params->p_encoder->enc_buf.size > 0); + + /* All non-frame data is prepended to actual frame data to + * be able to set the pts correctly. So we don't write data + * to the frame output queue until we actually have a frame + */ + + p_dirac_params->enc_buf = av_realloc ( + p_dirac_params->enc_buf, + p_dirac_params->enc_buf_size + + p_dirac_params->p_encoder->enc_buf.size + ); + memcpy(p_dirac_params->enc_buf + p_dirac_params->enc_buf_size, + p_dirac_params->p_encoder->enc_buf.buffer, + p_dirac_params->p_encoder->enc_buf.size); + + p_dirac_params->enc_buf_size += + p_dirac_params->p_encoder->enc_buf.size; + + if (state == ENC_STATE_EOS) { + p_dirac_params->eos_pulled = 1; + go = 0; + } + + /* If non-frame data, don't output it until it we get an + * encoded frame back from the encoder. */ + if (p_dirac_params->p_encoder->enc_pparams.pnum == -1) + break; + + /* create output frame */ + p_frame_output = av_mallocz(sizeof(FfmpegDiracSchroEncodedFrame)); + /* set output data */ + p_frame_output->size = p_dirac_params->enc_buf_size; + p_frame_output->p_encbuf = p_dirac_params->enc_buf; + p_frame_output->frame_num = + p_dirac_params->p_encoder->enc_pparams.pnum; + + if (p_dirac_params->p_encoder->enc_pparams.ptype == INTRA_PICTURE && + p_dirac_params->p_encoder->enc_pparams.rtype == REFERENCE_PICTURE) + p_frame_output->key_frame = 1; + + ff_dirac_schro_queue_push_back (&p_dirac_params->enc_frame_queue, + p_frame_output); + + p_dirac_params->enc_buf_size = 0; + p_dirac_params->enc_buf = NULL; + break; + + case ENC_STATE_BUFFER: + go = 0; + break; + + case ENC_STATE_INVALID: + av_log(avccontext, AV_LOG_ERROR, + "Unrecoverable Dirac Encoder Error. Quitting...\n"); + return -1; + + default: + av_log(avccontext, AV_LOG_ERROR, "Unknown Dirac Encoder state\n"); + return -1; + } + } + + /* copy 'next' frame in queue */ + + if (p_dirac_params->enc_frame_queue.size == 1 && + p_dirac_params->eos_pulled) + last_frame_in_sequence = 1; + + p_next_output_frame = + ff_dirac_schro_queue_pop(&p_dirac_params->enc_frame_queue); + + if (p_next_output_frame == NULL) + return 0; + + memcpy(frame, p_next_output_frame->p_encbuf, p_next_output_frame->size); + avccontext->coded_frame->key_frame = p_next_output_frame->key_frame; + /* Use the frame number of the encoded frame as the pts. It is OK to do + * so since Dirac is a constant framerate codec. It expects input to be + * of constant framerate. */ + avccontext->coded_frame->pts = p_next_output_frame->frame_num; + enc_size = p_next_output_frame->size; + + /* Append the end of sequence information to the last frame in the + * sequence. */ + if (last_frame_in_sequence && p_dirac_params->enc_buf_size > 0) + { + memcpy (frame + enc_size, p_dirac_params->enc_buf, + p_dirac_params->enc_buf_size); + enc_size += p_dirac_params->enc_buf_size; + av_freep (&p_dirac_params->enc_buf); + p_dirac_params->enc_buf_size = 0; + } + + /* free frame */ + DiracFreeFrame(p_next_output_frame); + + return enc_size; +} + +static int libdirac_encode_close(AVCodecContext *avccontext) +{ + FfmpegDiracEncoderParams* p_dirac_params = avccontext->priv_data; + + /* close the encoder */ + dirac_encoder_close(p_dirac_params->p_encoder ); + + /* free data in the output frame queue */ + ff_dirac_schro_queue_free(&p_dirac_params->enc_frame_queue, + DiracFreeFrame); + + /* free the encoder buffer */ + if (p_dirac_params->enc_buf_size) + av_freep(&p_dirac_params->enc_buf); + + /* free the input frame buffer */ + av_freep(&p_dirac_params->p_in_frame_buf); + + return 0 ; +} + + +AVCodec libdirac_encoder = { + "libdirac", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegDiracEncoderParams), + libdirac_encode_init, + libdirac_encode_frame, + libdirac_encode_close, + .capabilities= CODEC_CAP_DELAY, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, -1}, + .long_name= NULL_IF_CONFIG_SMALL("libdirac Dirac 2.2"), +} ; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libfaac.c b/src/add-ons/media/plugins/avcodec/libavcodec/libfaac.c new file mode 100644 index 0000000000..2ed4f765f9 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libfaac.c @@ -0,0 +1,156 @@ +/* + * Interface to libfaac for aac encoding + * Copyright (c) 2002 Gildas Bazin + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file libfaac.c + * Interface to libfaac for aac encoding. + */ + +#include "avcodec.h" +#include + +typedef struct FaacAudioContext { + faacEncHandle faac_handle; +} FaacAudioContext; + +static av_cold int Faac_encode_init(AVCodecContext *avctx) +{ + FaacAudioContext *s = avctx->priv_data; + faacEncConfigurationPtr faac_cfg; + unsigned long samples_input, max_bytes_output; + + /* number of channels */ + if (avctx->channels < 1 || avctx->channels > 6) + return -1; + + s->faac_handle = faacEncOpen(avctx->sample_rate, + avctx->channels, + &samples_input, &max_bytes_output); + + /* check faac version */ + faac_cfg = faacEncGetCurrentConfiguration(s->faac_handle); + if (faac_cfg->version != FAAC_CFG_VERSION) { + av_log(avctx, AV_LOG_ERROR, "wrong libfaac version (compiled for: %d, using %d)\n", FAAC_CFG_VERSION, faac_cfg->version); + faacEncClose(s->faac_handle); + return -1; + } + + /* put the options in the configuration struct */ + switch(avctx->profile) { + case FF_PROFILE_AAC_MAIN: + faac_cfg->aacObjectType = MAIN; + break; + case FF_PROFILE_UNKNOWN: + case FF_PROFILE_AAC_LOW: + faac_cfg->aacObjectType = LOW; + break; + case FF_PROFILE_AAC_SSR: + faac_cfg->aacObjectType = SSR; + break; + case FF_PROFILE_AAC_LTP: + faac_cfg->aacObjectType = LTP; + break; + default: + av_log(avctx, AV_LOG_ERROR, "invalid AAC profile\n"); + faacEncClose(s->faac_handle); + return -1; + } + faac_cfg->mpegVersion = MPEG4; + faac_cfg->useTns = 0; + faac_cfg->allowMidside = 1; + faac_cfg->bitRate = avctx->bit_rate / avctx->channels; + faac_cfg->bandWidth = avctx->cutoff; + if(avctx->flags & CODEC_FLAG_QSCALE) { + faac_cfg->bitRate = 0; + faac_cfg->quantqual = avctx->global_quality / FF_QP2LAMBDA; + } + faac_cfg->outputFormat = 1; + faac_cfg->inputFormat = FAAC_INPUT_16BIT; + + avctx->frame_size = samples_input / avctx->channels; + + avctx->coded_frame= avcodec_alloc_frame(); + avctx->coded_frame->key_frame= 1; + + /* Set decoder specific info */ + avctx->extradata_size = 0; + if (avctx->flags & CODEC_FLAG_GLOBAL_HEADER) { + + unsigned char *buffer = NULL; + unsigned long decoder_specific_info_size; + + if (!faacEncGetDecoderSpecificInfo(s->faac_handle, &buffer, + &decoder_specific_info_size)) { + avctx->extradata = av_malloc(decoder_specific_info_size + FF_INPUT_BUFFER_PADDING_SIZE); + avctx->extradata_size = decoder_specific_info_size; + memcpy(avctx->extradata, buffer, avctx->extradata_size); + faac_cfg->outputFormat = 0; + } +#undef free + free(buffer); +#define free please_use_av_free + } + + if (!faacEncSetConfiguration(s->faac_handle, faac_cfg)) { + av_log(avctx, AV_LOG_ERROR, "libfaac doesn't support this output format!\n"); + return -1; + } + + return 0; +} + +static int Faac_encode_frame(AVCodecContext *avctx, + unsigned char *frame, int buf_size, void *data) +{ + FaacAudioContext *s = avctx->priv_data; + int bytes_written; + + bytes_written = faacEncEncode(s->faac_handle, + data, + avctx->frame_size * avctx->channels, + frame, + buf_size); + + return bytes_written; +} + +static av_cold int Faac_encode_close(AVCodecContext *avctx) +{ + FaacAudioContext *s = avctx->priv_data; + + av_freep(&avctx->coded_frame); + av_freep(&avctx->extradata); + + faacEncClose(s->faac_handle); + return 0; +} + +AVCodec libfaac_encoder = { + "libfaac", + CODEC_TYPE_AUDIO, + CODEC_ID_AAC, + sizeof(FaacAudioContext), + Faac_encode_init, + Faac_encode_frame, + Faac_encode_close, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libfaac AAC (Advanced Audio Codec)"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libfaad.c b/src/add-ons/media/plugins/avcodec/libavcodec/libfaad.c new file mode 100644 index 0000000000..3e7339d6f4 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libfaad.c @@ -0,0 +1,340 @@ +/* + * Faad decoder + * Copyright (c) 2003 Zdenek Kabelac. + * Copyright (c) 2004 Thomas Raivio. + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file faad.c + * AAC decoder. + * + * still a bit unfinished - but it plays something + */ + +#include "avcodec.h" +#include "faad.h" + +#ifndef FAADAPI +#define FAADAPI +#endif + +/* + * when CONFIG_LIBFAADBIN is defined the libfaad will be opened at runtime + */ +//#undef CONFIG_LIBFAADBIN +//#define CONFIG_LIBFAADBIN + +#ifdef CONFIG_LIBFAADBIN +#include +static const char* libfaadname = "libfaad.so"; +#else +#define dlopen(a) +#define dlclose(a) +#endif + +typedef struct { + void* handle; /* dlopen handle */ + void* faac_handle; /* FAAD library handle */ + int sample_size; + int init; + + /* faad calls */ + faacDecHandle FAADAPI (*faacDecOpen)(void); + faacDecConfigurationPtr FAADAPI (*faacDecGetCurrentConfiguration)(faacDecHandle hDecoder); +#ifndef FAAD2_VERSION + int FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder, + faacDecConfigurationPtr config); + int FAADAPI (*faacDecInit)(faacDecHandle hDecoder, + unsigned char *buffer, + unsigned long *samplerate, + unsigned long *channels); + int FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer, + unsigned long SizeOfDecoderSpecificInfo, + unsigned long *samplerate, unsigned long *channels); + int FAADAPI (*faacDecDecode)(faacDecHandle hDecoder, + unsigned char *buffer, + unsigned long *bytesconsumed, + short *sample_buffer, + unsigned long *samples); +#else + unsigned char FAADAPI (*faacDecSetConfiguration)(faacDecHandle hDecoder, + faacDecConfigurationPtr config); + long FAADAPI (*faacDecInit)(faacDecHandle hDecoder, + unsigned char *buffer, + unsigned long buffer_size, + unsigned long *samplerate, + unsigned char *channels); + char FAADAPI (*faacDecInit2)(faacDecHandle hDecoder, unsigned char *pBuffer, + unsigned long SizeOfDecoderSpecificInfo, + unsigned long *samplerate, unsigned char *channels); + void *FAADAPI (*faacDecDecode)(faacDecHandle hDecoder, + faacDecFrameInfo *hInfo, + unsigned char *buffer, + unsigned long buffer_size); + char* FAADAPI (*faacDecGetErrorMessage)(unsigned char errcode); +#endif + + void FAADAPI (*faacDecClose)(faacDecHandle hDecoder); + + +} FAACContext; + +static const unsigned long faac_srates[] = +{ + 96000, 88200, 64000, 48000, 44100, 32000, + 24000, 22050, 16000, 12000, 11025, 8000 +}; + +static void channel_setup(AVCodecContext *avctx) +{ +#ifdef FAAD2_VERSION + FAACContext *s = avctx->priv_data; + if (avctx->request_channels > 0 && avctx->request_channels == 2 && + avctx->request_channels < avctx->channels) { + faacDecConfigurationPtr faac_cfg; + avctx->channels = 2; + faac_cfg = s->faacDecGetCurrentConfiguration(s->faac_handle); + faac_cfg->downMatrix = 1; + s->faacDecSetConfiguration(s->faac_handle, faac_cfg); + } +#endif +} + +static int faac_init_mp4(AVCodecContext *avctx) +{ + FAACContext *s = avctx->priv_data; + unsigned long samplerate; +#ifndef FAAD2_VERSION + unsigned long channels; +#else + unsigned char channels; +#endif + int r = 0; + + if (avctx->extradata){ + r = s->faacDecInit2(s->faac_handle, (uint8_t*) avctx->extradata, + avctx->extradata_size, + &samplerate, &channels); + if (r < 0){ + av_log(avctx, AV_LOG_ERROR, + "faacDecInit2 failed r:%d sr:%ld ch:%ld s:%d\n", + r, samplerate, (long)channels, avctx->extradata_size); + } else { + avctx->sample_rate = samplerate; + avctx->channels = channels; + channel_setup(avctx); + s->init = 1; + } + } + + return r; +} + +static int faac_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) +{ + FAACContext *s = avctx->priv_data; +#ifndef FAAD2_VERSION + unsigned long bytesconsumed; + short *sample_buffer = NULL; + unsigned long samples; + int out; +#else + faacDecFrameInfo frame_info; + void *out; +#endif + if(buf_size == 0) + return 0; +#ifndef FAAD2_VERSION + out = s->faacDecDecode(s->faac_handle, + (unsigned char*)buf, + &bytesconsumed, + data, + &samples); + samples *= s->sample_size; + if (data_size) + *data_size = samples; + return (buf_size < (int)bytesconsumed) + ? buf_size : (int)bytesconsumed; +#else + + if(!s->init){ + unsigned long srate; + unsigned char channels; + int r = s->faacDecInit(s->faac_handle, buf, buf_size, &srate, &channels); + if(r < 0){ + av_log(avctx, AV_LOG_ERROR, "faac: codec init failed.\n"); + return -1; + } + avctx->sample_rate = srate; + avctx->channels = channels; + channel_setup(avctx); + s->init = 1; + } + + out = s->faacDecDecode(s->faac_handle, &frame_info, (unsigned char*)buf, (unsigned long)buf_size); + + if (frame_info.error > 0) { + av_log(avctx, AV_LOG_ERROR, "faac: frame decoding failed: %s\n", + s->faacDecGetErrorMessage(frame_info.error)); + return -1; + } + if (!avctx->frame_size) + avctx->frame_size = frame_info.samples/avctx->channels; + frame_info.samples *= s->sample_size; + memcpy(data, out, frame_info.samples); // CHECKME - can we cheat this one + + if (data_size) + *data_size = frame_info.samples; + + return (buf_size < (int)frame_info.bytesconsumed) + ? buf_size : (int)frame_info.bytesconsumed; +#endif +} + +static av_cold int faac_decode_end(AVCodecContext *avctx) +{ + FAACContext *s = avctx->priv_data; + + s->faacDecClose(s->faac_handle); + + dlclose(s->handle); + return 0; +} + +static av_cold int faac_decode_init(AVCodecContext *avctx) +{ + FAACContext *s = avctx->priv_data; + faacDecConfigurationPtr faac_cfg; + +#ifdef CONFIG_LIBFAADBIN + const char* err = 0; + + s->handle = dlopen(libfaadname, RTLD_LAZY); + if (!s->handle) + { + av_log(avctx, AV_LOG_ERROR, "FAAD library: %s could not be opened! \n%s\n", + libfaadname, dlerror()); + return -1; + } + +#define dfaac(a) do { \ + const char* n = AV_STRINGIFY(faacDec ## a); \ + if (!err && !(s->faacDec ## a = dlsym(s->handle, n))) { \ + err = n; \ + } \ + } while(0) +#else /* !CONFIG_LIBFAADBIN */ +#define dfaac(a) s->faacDec ## a = faacDec ## a +#endif /* CONFIG_LIBFAADBIN */ + + // resolve all needed function calls + dfaac(Open); + dfaac(Close); + dfaac(GetCurrentConfiguration); + dfaac(SetConfiguration); + dfaac(Init); + dfaac(Init2); + dfaac(Decode); +#ifdef FAAD2_VERSION + dfaac(GetErrorMessage); +#endif + +#undef dfaac + +#ifdef CONFIG_LIBFAADBIN + if (err) { + dlclose(s->handle); + av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot resolve %s in %s!\n", + err, libfaadname); + return -1; + } +#endif + + s->faac_handle = s->faacDecOpen(); + if (!s->faac_handle) { + av_log(avctx, AV_LOG_ERROR, "FAAD library: cannot create handler!\n"); + faac_decode_end(avctx); + return -1; + } + + + faac_cfg = s->faacDecGetCurrentConfiguration(s->faac_handle); + + if (faac_cfg) { + switch (avctx->bits_per_sample) { + case 8: av_log(avctx, AV_LOG_ERROR, "FAADlib unsupported bps %d\n", avctx->bits_per_sample); break; + default: + case 16: +#ifdef FAAD2_VERSION + faac_cfg->outputFormat = FAAD_FMT_16BIT; +#endif + s->sample_size = 2; + break; + case 24: +#ifdef FAAD2_VERSION + faac_cfg->outputFormat = FAAD_FMT_24BIT; +#endif + s->sample_size = 3; + break; + case 32: +#ifdef FAAD2_VERSION + faac_cfg->outputFormat = FAAD_FMT_32BIT; +#endif + s->sample_size = 4; + break; + } + + faac_cfg->defSampleRate = (!avctx->sample_rate) ? 44100 : avctx->sample_rate; + faac_cfg->defObjectType = LC; + } + + s->faacDecSetConfiguration(s->faac_handle, faac_cfg); + + faac_init_mp4(avctx); + + if(!s->init && avctx->channels > 0) + channel_setup(avctx); + + avctx->sample_fmt = SAMPLE_FMT_S16; + return 0; +} + +#define AAC_CODEC(id, name, long_name_) \ +AVCodec name ## _decoder = { \ + #name, \ + CODEC_TYPE_AUDIO, \ + id, \ + sizeof(FAACContext), \ + faac_decode_init, \ + NULL, \ + faac_decode_end, \ + faac_decode_frame, \ + .long_name = NULL_IF_CONFIG_SMALL(long_name_), \ +} + +// FIXME - raw AAC files - maybe just one entry will be enough +AAC_CODEC(CODEC_ID_AAC, libfaad, "libfaad AAC (Advanced Audio Codec)"); +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) +// If it's mp4 file - usually embeded into Qt Mov +AAC_CODEC(CODEC_ID_MPEG4AAC, mpeg4aac, "libfaad AAC (Advanced Audio Codec)"); +#endif + +#undef AAC_CODEC diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libgsm.c b/src/add-ons/media/plugins/avcodec/libavcodec/libgsm.c new file mode 100644 index 0000000000..09578b403d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libgsm.c @@ -0,0 +1,178 @@ +/* + * Interface to libgsm for gsm encoding/decoding + * Copyright (c) 2005 Alban Bedel + * Copyright (c) 2006, 2007 Michel Bardiaux + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file libgsm.c + * Interface to libgsm for gsm encoding/decoding + */ + +// The idiosyncrasies of GSM-in-WAV are explained at http://kbs.cs.tu-berlin.de/~jutta/toast.html + +#include "avcodec.h" +#include + +// gsm.h misses some essential constants +#define GSM_BLOCK_SIZE 33 +#define GSM_MS_BLOCK_SIZE 65 +#define GSM_FRAME_SIZE 160 + +static av_cold int libgsm_init(AVCodecContext *avctx) { + if (avctx->channels > 1) { + av_log(avctx, AV_LOG_ERROR, "Mono required for GSM, got %d channels\n", + avctx->channels); + return -1; + } + + if(avctx->codec->decode){ + if(!avctx->channels) + avctx->channels= 1; + + if(!avctx->sample_rate) + avctx->sample_rate= 8000; + + avctx->sample_fmt = SAMPLE_FMT_S16; + }else{ + if (avctx->sample_rate != 8000) { + av_log(avctx, AV_LOG_ERROR, "Sample rate 8000Hz required for GSM, got %dHz\n", + avctx->sample_rate); + if(avctx->strict_std_compliance > FF_COMPLIANCE_INOFFICIAL) + return -1; + } + if (avctx->bit_rate != 13000 /* Official */ && + avctx->bit_rate != 13200 /* Very common */ && + avctx->bit_rate != 0 /* Unknown; a.o. mov does not set bitrate when decoding */ ) { + av_log(avctx, AV_LOG_ERROR, "Bitrate 13000bps required for GSM, got %dbps\n", + avctx->bit_rate); + if(avctx->strict_std_compliance > FF_COMPLIANCE_INOFFICIAL) + return -1; + } + } + + avctx->priv_data = gsm_create(); + + switch(avctx->codec_id) { + case CODEC_ID_GSM: + avctx->frame_size = GSM_FRAME_SIZE; + avctx->block_align = GSM_BLOCK_SIZE; + break; + case CODEC_ID_GSM_MS: { + int one = 1; + gsm_option(avctx->priv_data, GSM_OPT_WAV49, &one); + avctx->frame_size = 2*GSM_FRAME_SIZE; + avctx->block_align = GSM_MS_BLOCK_SIZE; + } + } + + avctx->coded_frame= avcodec_alloc_frame(); + avctx->coded_frame->key_frame= 1; + + return 0; +} + +static av_cold int libgsm_close(AVCodecContext *avctx) { + gsm_destroy(avctx->priv_data); + avctx->priv_data = NULL; + return 0; +} + +static int libgsm_encode_frame(AVCodecContext *avctx, + unsigned char *frame, int buf_size, void *data) { + // we need a full block + if(buf_size < avctx->block_align) return 0; + + switch(avctx->codec_id) { + case CODEC_ID_GSM: + gsm_encode(avctx->priv_data,data,frame); + break; + case CODEC_ID_GSM_MS: + gsm_encode(avctx->priv_data,data,frame); + gsm_encode(avctx->priv_data,((short*)data)+GSM_FRAME_SIZE,frame+32); + } + return avctx->block_align; +} + + +AVCodec libgsm_encoder = { + "libgsm", + CODEC_TYPE_AUDIO, + CODEC_ID_GSM, + 0, + libgsm_init, + libgsm_encode_frame, + libgsm_close, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), +}; + +AVCodec libgsm_ms_encoder = { + "libgsm_ms", + CODEC_TYPE_AUDIO, + CODEC_ID_GSM_MS, + 0, + libgsm_init, + libgsm_encode_frame, + libgsm_close, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), +}; + +static int libgsm_decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + uint8_t *buf, int buf_size) { + *data_size = 0; /* In case of error */ + if(buf_size < avctx->block_align) return -1; + switch(avctx->codec_id) { + case CODEC_ID_GSM: + if(gsm_decode(avctx->priv_data,buf,data)) return -1; + *data_size = GSM_FRAME_SIZE*sizeof(int16_t); + break; + case CODEC_ID_GSM_MS: + if(gsm_decode(avctx->priv_data,buf,data) || + gsm_decode(avctx->priv_data,buf+33,((int16_t*)data)+GSM_FRAME_SIZE)) return -1; + *data_size = GSM_FRAME_SIZE*sizeof(int16_t)*2; + } + return avctx->block_align; +} + +AVCodec libgsm_decoder = { + "libgsm", + CODEC_TYPE_AUDIO, + CODEC_ID_GSM, + 0, + libgsm_init, + NULL, + libgsm_close, + libgsm_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM"), +}; + +AVCodec libgsm_ms_decoder = { + "libgsm_ms", + CODEC_TYPE_AUDIO, + CODEC_ID_GSM_MS, + 0, + libgsm_init, + NULL, + libgsm_close, + libgsm_decode_frame, + .long_name = NULL_IF_CONFIG_SMALL("libgsm GSM Microsoft variant"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libmp3lame.c b/src/add-ons/media/plugins/avcodec/libavcodec/libmp3lame.c new file mode 100644 index 0000000000..bccff00b0e --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libmp3lame.c @@ -0,0 +1,226 @@ +/* + * Interface to libmp3lame for mp3 encoding + * Copyright (c) 2002 Lennert Buytenhek + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file mp3lameaudio.c + * Interface to libmp3lame for mp3 encoding. + */ + +#include "avcodec.h" +#include "mpegaudio.h" +#include + +#define BUFFER_SIZE (7200 + MPA_FRAME_SIZE + MPA_FRAME_SIZE/4) +typedef struct Mp3AudioContext { + lame_global_flags *gfp; + int stereo; + uint8_t buffer[BUFFER_SIZE]; + int buffer_index; +} Mp3AudioContext; + +static av_cold int MP3lame_encode_init(AVCodecContext *avctx) +{ + Mp3AudioContext *s = avctx->priv_data; + + if (avctx->channels > 2) + return -1; + + s->stereo = avctx->channels > 1 ? 1 : 0; + + if ((s->gfp = lame_init()) == NULL) + goto err; + lame_set_in_samplerate(s->gfp, avctx->sample_rate); + lame_set_out_samplerate(s->gfp, avctx->sample_rate); + lame_set_num_channels(s->gfp, avctx->channels); + if(avctx->compression_level == FF_COMPRESSION_DEFAULT) { + lame_set_quality(s->gfp, 5); + } else { + lame_set_quality(s->gfp, avctx->compression_level); + } + /* lame 3.91 doesn't work in mono */ + lame_set_mode(s->gfp, JOINT_STEREO); + lame_set_brate(s->gfp, avctx->bit_rate/1000); + if(avctx->flags & CODEC_FLAG_QSCALE) { + lame_set_brate(s->gfp, 0); + lame_set_VBR(s->gfp, vbr_default); + lame_set_VBR_q(s->gfp, avctx->global_quality / (float)FF_QP2LAMBDA); + } + lame_set_bWriteVbrTag(s->gfp,0); + lame_set_disable_reservoir(s->gfp, avctx->flags2 & CODEC_FLAG2_BIT_RESERVOIR ? 0 : 1); + if (lame_init_params(s->gfp) < 0) + goto err_close; + + avctx->frame_size = lame_get_framesize(s->gfp); + + avctx->coded_frame= avcodec_alloc_frame(); + avctx->coded_frame->key_frame= 1; + + return 0; + +err_close: + lame_close(s->gfp); +err: + return -1; +} + +static const int sSampleRates[3] = { + 44100, 48000, 32000 +}; + +static const int sBitRates[2][3][15] = { + { { 0, 32, 64, 96,128,160,192,224,256,288,320,352,384,416,448}, + { 0, 32, 48, 56, 64, 80, 96,112,128,160,192,224,256,320,384}, + { 0, 32, 40, 48, 56, 64, 80, 96,112,128,160,192,224,256,320} + }, + { { 0, 32, 48, 56, 64, 80, 96,112,128,144,160,176,192,224,256}, + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160}, + { 0, 8, 16, 24, 32, 40, 48, 56, 64, 80, 96,112,128,144,160} + }, +}; + +static const int sSamplesPerFrame[2][3] = +{ + { 384, 1152, 1152 }, + { 384, 1152, 576 } +}; + +static const int sBitsPerSlot[3] = { + 32, + 8, + 8 +}; + +static int mp3len(void *data, int *samplesPerFrame, int *sampleRate) +{ + uint32_t header = AV_RB32(data); + int layerID = 3 - ((header >> 17) & 0x03); + int bitRateID = ((header >> 12) & 0x0f); + int sampleRateID = ((header >> 10) & 0x03); + int bitsPerSlot = sBitsPerSlot[layerID]; + int isPadded = ((header >> 9) & 0x01); + static int const mode_tab[4]= {2,3,1,0}; + int mode= mode_tab[(header >> 19) & 0x03]; + int mpeg_id= mode>0; + int temp0, temp1, bitRate; + + if ( (( header >> 21 ) & 0x7ff) != 0x7ff || mode == 3 || layerID==3 || sampleRateID==3) { + return -1; + } + + if(!samplesPerFrame) samplesPerFrame= &temp0; + if(!sampleRate ) sampleRate = &temp1; + +// *isMono = ((header >> 6) & 0x03) == 0x03; + + *sampleRate = sSampleRates[sampleRateID]>>mode; + bitRate = sBitRates[mpeg_id][layerID][bitRateID] * 1000; + *samplesPerFrame = sSamplesPerFrame[mpeg_id][layerID]; +//av_log(NULL, AV_LOG_DEBUG, "sr:%d br:%d spf:%d l:%d m:%d\n", *sampleRate, bitRate, *samplesPerFrame, layerID, mode); + + return *samplesPerFrame * bitRate / (bitsPerSlot * *sampleRate) + isPadded; +} + +static int MP3lame_encode_frame(AVCodecContext *avctx, + unsigned char *frame, int buf_size, void *data) +{ + Mp3AudioContext *s = avctx->priv_data; + int len; + int lame_result; + + /* lame 3.91 dies on '1-channel interleaved' data */ + + if(data){ + if (s->stereo) { + lame_result = lame_encode_buffer_interleaved( + s->gfp, + data, + avctx->frame_size, + s->buffer + s->buffer_index, + BUFFER_SIZE - s->buffer_index + ); + } else { + lame_result = lame_encode_buffer( + s->gfp, + data, + data, + avctx->frame_size, + s->buffer + s->buffer_index, + BUFFER_SIZE - s->buffer_index + ); + } + }else{ + lame_result= lame_encode_flush( + s->gfp, + s->buffer + s->buffer_index, + BUFFER_SIZE - s->buffer_index + ); + } + + if(lame_result==-1) { + /* output buffer too small */ + av_log(avctx, AV_LOG_ERROR, "lame: output buffer too small (buffer index: %d, free bytes: %d)\n", s->buffer_index, BUFFER_SIZE - s->buffer_index); + return 0; + } + + s->buffer_index += lame_result; + + if(s->buffer_index<4) + return 0; + + len= mp3len(s->buffer, NULL, NULL); +//av_log(avctx, AV_LOG_DEBUG, "in:%d packet-len:%d index:%d\n", avctx->frame_size, len, s->buffer_index); + if(len <= s->buffer_index){ + memcpy(frame, s->buffer, len); + s->buffer_index -= len; + + memmove(s->buffer, s->buffer+len, s->buffer_index); + //FIXME fix the audio codec API, so we do not need the memcpy() +/*for(i=0; ipriv_data; + + av_freep(&avctx->coded_frame); + + lame_close(s->gfp); + return 0; +} + + +AVCodec libmp3lame_encoder = { + "libmp3lame", + CODEC_TYPE_AUDIO, + CODEC_ID_MP3, + sizeof(Mp3AudioContext), + MP3lame_encode_init, + MP3lame_encode_frame, + MP3lame_encode_close, + .capabilities= CODEC_CAP_DELAY, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("libmp3lame MP3 (MPEG audio layer 3)"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.c b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.c new file mode 100644 index 0000000000..8c80c96aca --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedinger.c +* function definitions common to libschroedingerdec.c and libschroedingerenc.c +*/ + +#include "libdirac_libschro.h" +#include "libschroedinger.h" + +/** +* Schroedinger video preset table. Ensure that this tables matches up correctly +* with the ff_dirac_schro_video_format_info table in libdirac_libschro.c. +*/ +static const SchroVideoFormatEnum ff_schro_video_formats[]={ + SCHRO_VIDEO_FORMAT_CUSTOM , + SCHRO_VIDEO_FORMAT_QSIF , + SCHRO_VIDEO_FORMAT_QCIF , + SCHRO_VIDEO_FORMAT_SIF , + SCHRO_VIDEO_FORMAT_CIF , + SCHRO_VIDEO_FORMAT_4SIF , + SCHRO_VIDEO_FORMAT_4CIF , + SCHRO_VIDEO_FORMAT_SD480I_60 , + SCHRO_VIDEO_FORMAT_SD576I_50 , + SCHRO_VIDEO_FORMAT_HD720P_60 , + SCHRO_VIDEO_FORMAT_HD720P_50 , + SCHRO_VIDEO_FORMAT_HD1080I_60 , + SCHRO_VIDEO_FORMAT_HD1080I_50 , + SCHRO_VIDEO_FORMAT_HD1080P_60 , + SCHRO_VIDEO_FORMAT_HD1080P_50 , + SCHRO_VIDEO_FORMAT_DC2K_24 , + SCHRO_VIDEO_FORMAT_DC4K_24 , +}; + +SchroVideoFormatEnum ff_get_schro_video_format_preset(AVCodecContext *avccontext) +{ + unsigned int num_formats = sizeof(ff_schro_video_formats) / + sizeof(ff_schro_video_formats[0]); + + unsigned int idx = ff_dirac_schro_get_video_format_idx (avccontext); + + return (idx < num_formats) ? + ff_schro_video_formats[idx] : SCHRO_VIDEO_FORMAT_CUSTOM; +} + +int ff_get_schro_frame_format (SchroChromaFormat schro_pix_fmt, + SchroFrameFormat *schro_frame_fmt) +{ + unsigned int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) { + *schro_frame_fmt = + ffmpeg_schro_pixel_format_map[idx].schro_frame_fmt; + return 0; + } + } + return -1; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.h b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.h new file mode 100644 index 0000000000..7b5f7f2bcf --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedinger.h @@ -0,0 +1,61 @@ +/* + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedinger.h +* data structures common to libschroedingerdec.c and libschroedingerenc.c +*/ + +#ifndef FFMPEG_LIBSCHROEDINGER_H +#define FFMPEG_LIBSCHROEDINGER_H + +#include "config.h" + +#ifdef CONFIG_LIBSCHROEDINGER + +#include +#include +#include "avcodec.h" + +static const struct { + enum PixelFormat ff_pix_fmt; + SchroChromaFormat schro_pix_fmt; + SchroFrameFormat schro_frame_fmt; +} ffmpeg_schro_pixel_format_map[] = { + { PIX_FMT_YUV420P, SCHRO_CHROMA_420, SCHRO_FRAME_FORMAT_U8_420 }, + { PIX_FMT_YUV422P, SCHRO_CHROMA_422, SCHRO_FRAME_FORMAT_U8_422 }, + { PIX_FMT_YUV444P, SCHRO_CHROMA_444, SCHRO_FRAME_FORMAT_U8_444 }, +}; + +/** +* Returns the video format preset matching the input video dimensions and +* time base. +*/ +SchroVideoFormatEnum ff_get_schro_video_format_preset (AVCodecContext *avccontext); + +/** +* Sets the Schroedinger frame format corresponding to the Schro chroma format +* passed. Returns 0 on success, -1 on failure. +*/ +int ff_get_schro_frame_format (SchroChromaFormat schro_chroma_fmt, + SchroFrameFormat *schro_frame_fmt); + +#endif /* CONFIG_LIBSCHROEDINGER */ +#endif /* FFMPEG_LIBSCHROEDINGER_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerdec.c b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerdec.c new file mode 100644 index 0000000000..f9b4d2198a --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerdec.c @@ -0,0 +1,369 @@ +/* + * Dirac decoder support via Schroedinger libraries + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedingerdec.c +* Dirac decoder support via libschroedinger-1.0 libraries. More details about +* the Schroedinger project can be found at http://www.diracvideo.org/. +* The library implements Dirac Specification Version 2.2. +* (http://dirac.sourceforge.net/specification.html). +*/ + +#include "avcodec.h" +#include "libdirac_libschro.h" +#include "libschroedinger.h" + +#undef NDEBUG +#include + + +#include +#include +#include + +/** libschroedinger decoder private data */ +typedef struct FfmpegSchroDecoderParams +{ + /** Schroedinger video format */ + SchroVideoFormat *format; + + /** Schroedinger frame format */ + SchroFrameFormat frame_format; + + /** decoder handle */ + SchroDecoder* decoder; + + /** queue storing decoded frames */ + FfmpegDiracSchroQueue dec_frame_queue; + + /** end of sequence signalled */ + int eos_signalled; + + /** end of sequence pulled */ + int eos_pulled; + + /** decoded picture */ + AVPicture dec_pic; +} FfmpegSchroDecoderParams; + +typedef struct FfmpegSchroParseUnitContext +{ + const uint8_t *buf; + int buf_size; +} FfmpegSchroParseUnitContext; + + +static void libschroedinger_decode_buffer_free (SchroBuffer *schro_buf, + void *priv); + +static void FfmpegSchroParseContextInit (FfmpegSchroParseUnitContext *parse_ctx, + const uint8_t *buf, int buf_size) +{ + parse_ctx->buf = buf; + parse_ctx->buf_size = buf_size; +} + +static SchroBuffer* FfmpegFindNextSchroParseUnit (FfmpegSchroParseUnitContext *parse_ctx) +{ + SchroBuffer *enc_buf = NULL; + int next_pu_offset = 0; + unsigned char *in_buf; + + if (parse_ctx->buf_size < 13 || + parse_ctx->buf[0] != 'B' || + parse_ctx->buf[1] != 'B' || + parse_ctx->buf[2] != 'C' || + parse_ctx->buf[3] != 'D') + return NULL; + + next_pu_offset = (parse_ctx->buf[5] << 24) + + (parse_ctx->buf[6] << 16) + + (parse_ctx->buf[7] << 8) + + parse_ctx->buf[8]; + + if (next_pu_offset == 0 && + SCHRO_PARSE_CODE_IS_END_OF_SEQUENCE(parse_ctx->buf[4])) + next_pu_offset = 13; + + if (next_pu_offset <= 0 || parse_ctx->buf_size < next_pu_offset) + return NULL; + + in_buf = av_malloc(next_pu_offset); + memcpy (in_buf, parse_ctx->buf, next_pu_offset); + enc_buf = schro_buffer_new_with_data (in_buf, next_pu_offset); + enc_buf->free = libschroedinger_decode_buffer_free; + enc_buf->priv = in_buf; + + parse_ctx->buf += next_pu_offset; + parse_ctx->buf_size -= next_pu_offset; + + return enc_buf; +} + +/** +* Returns FFmpeg chroma format. +*/ +static enum PixelFormat GetFfmpegChromaFormat(SchroChromaFormat schro_pix_fmt) +{ + int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + int idx; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt == schro_pix_fmt) { + return ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt; + } + } + return PIX_FMT_NONE; +} + +static int libschroedinger_decode_init(AVCodecContext *avccontext) +{ + + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data ; + /* First of all, initialize our supporting libraries. */ + schro_init(); + + schro_debug_set_level(avccontext->debug); + p_schro_params->decoder = schro_decoder_new(); + schro_decoder_set_skip_ratio(p_schro_params->decoder, 1); + + if (!p_schro_params->decoder) + return -1; + + /* Initialize the decoded frame queue. */ + ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue); + return 0 ; +} + +static void libschroedinger_decode_buffer_free (SchroBuffer *schro_buf, + void *priv) +{ + av_freep(&priv); +} + +static void libschroedinger_decode_frame_free (void *frame) +{ + schro_frame_unref(frame); +} + +static void libschroedinger_handle_first_access_unit(AVCodecContext *avccontext) +{ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + SchroDecoder *decoder = p_schro_params->decoder; + + p_schro_params->format = schro_decoder_get_video_format (decoder); + + /* Tell FFmpeg about sequence details. */ + if(avcodec_check_dimensions(avccontext, p_schro_params->format->width, + p_schro_params->format->height) < 0) { + av_log(avccontext, AV_LOG_ERROR, "invalid dimensions (%dx%d)\n", + p_schro_params->format->width, p_schro_params->format->height); + avccontext->height = avccontext->width = 0; + return; + } + avccontext->height = p_schro_params->format->height; + avccontext->width = p_schro_params->format->width; + avccontext->pix_fmt = + GetFfmpegChromaFormat(p_schro_params->format->chroma_format); + + if (ff_get_schro_frame_format( p_schro_params->format->chroma_format, + &p_schro_params->frame_format) == -1) { + av_log (avccontext, AV_LOG_ERROR, + "This codec currently only supports planar YUV 4:2:0, 4:2:2 " + "and 4:4:4 formats.\n"); + return; + } + + avccontext->time_base.den = p_schro_params->format->frame_rate_numerator; + avccontext->time_base.num = p_schro_params->format->frame_rate_denominator; + + if (p_schro_params->dec_pic.data[0] == NULL) + { + avpicture_alloc(&p_schro_params->dec_pic, + avccontext->pix_fmt, + avccontext->width, + avccontext->height); + } +} + +static int libschroedinger_decode_frame(AVCodecContext *avccontext, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + SchroDecoder *decoder = p_schro_params->decoder; + SchroVideoFormat *format; + AVPicture *picture = data; + SchroBuffer *enc_buf; + SchroFrame* frame; + int state; + int go = 1; + int outer = 1; + FfmpegSchroParseUnitContext parse_ctx; + + *data_size = 0; + + FfmpegSchroParseContextInit (&parse_ctx, buf, buf_size); + if (buf_size == 0) { + if (!p_schro_params->eos_signalled) { + state = schro_decoder_push_end_of_stream(decoder); + p_schro_params->eos_signalled = 1; + } + } + + /* Loop through all the individual parse units in the input buffer */ + do { + if ((enc_buf = FfmpegFindNextSchroParseUnit(&parse_ctx))) { + /* Push buffer into decoder. */ + state = schro_decoder_push (decoder, enc_buf); + if (state == SCHRO_DECODER_FIRST_ACCESS_UNIT) + libschroedinger_handle_first_access_unit(avccontext); + go = 1; + } + else + outer = 0; + format = p_schro_params->format; + + while (go) { + /* Parse data and process result. */ + state = schro_decoder_wait (decoder); + switch (state) + { + case SCHRO_DECODER_FIRST_ACCESS_UNIT: + libschroedinger_handle_first_access_unit (avccontext); + break; + + case SCHRO_DECODER_NEED_BITS: + /* Need more input data - stop iterating over what we have. */ + go = 0; + break; + + case SCHRO_DECODER_NEED_FRAME: + /* Decoder needs a frame - create one and push it in. */ + + frame = schro_frame_new_and_alloc(NULL, + p_schro_params->frame_format, + format->width, + format->height); + schro_decoder_add_output_picture (decoder, frame); + break; + + case SCHRO_DECODER_OK: + /* Pull a frame out of the decoder. */ + frame = schro_decoder_pull (decoder); + + if (frame) { + ff_dirac_schro_queue_push_back( + &p_schro_params->dec_frame_queue, + frame); + } + break; + case SCHRO_DECODER_EOS: + go = 0; + p_schro_params->eos_pulled = 1; + schro_decoder_reset (decoder); + outer = 0; + break; + + case SCHRO_DECODER_ERROR: + return -1; + break; + } + } + } while(outer); + + /* Grab next frame to be returned from the top of the queue. */ + frame = ff_dirac_schro_queue_pop(&p_schro_params->dec_frame_queue); + + if (frame != NULL) { + memcpy (p_schro_params->dec_pic.data[0], + frame->components[0].data, + frame->components[0].length); + + memcpy (p_schro_params->dec_pic.data[1], + frame->components[1].data, + frame->components[1].length); + + memcpy (p_schro_params->dec_pic.data[2], + frame->components[2].data, + frame->components[2].length); + + /* Fill picture with current buffer data from Schroedinger. */ + avpicture_fill(picture, p_schro_params->dec_pic.data[0], + avccontext->pix_fmt, + avccontext->width, avccontext->height); + + *data_size = sizeof(AVPicture); + + /* Now free the frame resources. */ + libschroedinger_decode_frame_free (frame); + } + return buf_size; +} + + +static int libschroedinger_decode_close(AVCodecContext *avccontext) +{ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + /* Free the decoder. */ + schro_decoder_free (p_schro_params->decoder); + av_freep(&p_schro_params->format); + + avpicture_free (&p_schro_params->dec_pic); + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue, + libschroedinger_decode_frame_free); + + return 0 ; +} + +static void libschroedinger_flush (AVCodecContext *avccontext) +{ + /* Got a seek request. Free the decoded frames queue and then reset + * the decoder */ + FfmpegSchroDecoderParams *p_schro_params = avccontext->priv_data; + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->dec_frame_queue, + libschroedinger_decode_frame_free); + + ff_dirac_schro_queue_init (&p_schro_params->dec_frame_queue); + schro_decoder_reset(p_schro_params->decoder); + p_schro_params->eos_pulled = 0; + p_schro_params->eos_signalled = 0; +} + +AVCodec libschroedinger_decoder = { + "libschroedinger", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegSchroDecoderParams), + libschroedinger_decode_init, + NULL, + libschroedinger_decode_close, + libschroedinger_decode_frame, + CODEC_CAP_DELAY, + .flush = libschroedinger_flush, + .long_name = NULL_IF_CONFIG_SMALL("libschroedinger Dirac 2.2"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerenc.c new file mode 100644 index 0000000000..03d9312e54 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libschroedingerenc.c @@ -0,0 +1,433 @@ +/* + * Dirac encoder support via Schroedinger libraries + * Copyright (c) 2008 BBC, Anuradha Suraparaju + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** +* @file libschroedingerenc.c +* Dirac encoder support via libschroedinger-1.0 libraries. More details about +* the Schroedinger project can be found at http://www.diracvideo.org/. +* The library implements Dirac Specification Version 2.2 +* (http://dirac.sourceforge.net/specification.html). +*/ + +#undef NDEBUG +#include + +#include +#include +#include + +#include "avcodec.h" +#include "libdirac_libschro.h" +#include "libschroedinger.h" + + +/** libschroedinger encoder private data */ +typedef struct FfmpegSchroEncoderParams +{ + /** Schroedinger video format */ + SchroVideoFormat *format; + + /** Schroedinger frame format */ + SchroFrameFormat frame_format; + + /** frame being encoded */ + AVFrame picture; + + /** frame size */ + int frame_size; + + /** Schroedinger encoder handle*/ + SchroEncoder* encoder; + + /** buffer to store encoder output before writing it to the frame queue*/ + unsigned char *enc_buf; + + /** Size of encoder buffer*/ + int enc_buf_size; + + /** queue storing encoded frames */ + FfmpegDiracSchroQueue enc_frame_queue; + + /** end of sequence signalled */ + int eos_signalled; + + /** end of sequence pulled */ + int eos_pulled; +} FfmpegSchroEncoderParams; + +/** +* Works out Schro-compatible chroma format. +*/ +static int SetSchroChromaFormat(AVCodecContext *avccontext) +{ + int num_formats = sizeof(ffmpeg_schro_pixel_format_map) / + sizeof(ffmpeg_schro_pixel_format_map[0]); + int idx; + + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + + for (idx = 0; idx < num_formats; ++idx) { + if (ffmpeg_schro_pixel_format_map[idx].ff_pix_fmt == + avccontext->pix_fmt) { + p_schro_params->format->chroma_format = + ffmpeg_schro_pixel_format_map[idx].schro_pix_fmt; + return 0; + } + } + + av_log (avccontext, AV_LOG_ERROR, + "This codec currently only supports planar YUV 4:2:0, 4:2:2" + " and 4:4:4 formats.\n"); + + return -1; +} + +static int libschroedinger_encode_init(AVCodecContext *avccontext) +{ + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroVideoFormatEnum preset; + + /* Initialize the libraries that libschroedinger depends on. */ + schro_init(); + + /* Create an encoder object. */ + p_schro_params->encoder = schro_encoder_new(); + + if (!p_schro_params->encoder) { + av_log(avccontext, AV_LOG_ERROR, + "Unrecoverable Error: schro_encoder_new failed. "); + return -1; + } + + /* Initialize the format. */ + preset = ff_get_schro_video_format_preset(avccontext); + p_schro_params->format = + schro_encoder_get_video_format(p_schro_params->encoder); + schro_video_format_set_std_video_format (p_schro_params->format, preset); + p_schro_params->format->width = avccontext->width; + p_schro_params->format->height = avccontext->height; + + if (SetSchroChromaFormat(avccontext) == -1) + return -1; + + if (ff_get_schro_frame_format(p_schro_params->format->chroma_format, + &p_schro_params->frame_format) == -1) { + av_log (avccontext, AV_LOG_ERROR, + "This codec currently supports only planar YUV 4:2:0, 4:2:2" + " and 4:4:4 formats.\n"); + return -1; + } + + p_schro_params->format->frame_rate_numerator = avccontext->time_base.den; + p_schro_params->format->frame_rate_denominator = avccontext->time_base.num; + + p_schro_params->frame_size = avpicture_get_size(avccontext->pix_fmt, + avccontext->width, + avccontext->height); + + avccontext->coded_frame = &p_schro_params->picture; + + if (avccontext->gop_size == 0){ + schro_encoder_setting_set_double (p_schro_params->encoder, + "gop_structure", + SCHRO_ENCODER_GOP_INTRA_ONLY); + } + else { + schro_encoder_setting_set_double (p_schro_params->encoder, + "gop_structure", + SCHRO_ENCODER_GOP_BIREF); + avccontext->has_b_frames = 1; + } + + /* FIXME - Need to handle SCHRO_ENCODER_RATE_CONTROL_LOW_DELAY. */ + if (avccontext->flags & CODEC_FLAG_QSCALE) { + if (avccontext->global_quality == 0) { + /* lossless coding */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_LOSSLESS); + } else { + int noise_threshold; + schro_encoder_setting_set_double (p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_CONSTANT_NOISE_THRESHOLD); + + noise_threshold = avccontext->global_quality/FF_QP2LAMBDA; + if (noise_threshold > 100) + noise_threshold = 100; + schro_encoder_setting_set_double (p_schro_params->encoder, + "noise_threshold", + noise_threshold); + } + } + else { + schro_encoder_setting_set_double ( p_schro_params->encoder, + "rate_control", + SCHRO_ENCODER_RATE_CONTROL_CONSTANT_BITRATE); + + schro_encoder_setting_set_double (p_schro_params->encoder, + "bitrate", + avccontext->bit_rate); + + } + + if (avccontext->flags & CODEC_FLAG_INTERLACED_ME) { + /* All material can be coded as interlaced or progressive + irrespective of the type of source material. */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "interlaced_coding", 1); + } + + /* FIXME: Signal range hardcoded to 8-bit data until both libschroedinger + * and libdirac support other bit-depth data. */ + schro_video_format_set_std_signal_range(p_schro_params->format, + SCHRO_SIGNAL_RANGE_8BIT_VIDEO); + + + /* Hardcode motion vector precision to quarter pixel. */ + schro_encoder_setting_set_double (p_schro_params->encoder, + "mv_precision", 2); + + /* Set the encoder format. */ + schro_encoder_set_video_format(p_schro_params->encoder, + p_schro_params->format); + + /* Set the debug level. */ + schro_debug_set_level (avccontext->debug); + + schro_encoder_start (p_schro_params->encoder); + + /* Initialize the encoded frame queue. */ + ff_dirac_schro_queue_init (&p_schro_params->enc_frame_queue); + return 0 ; +} + +static SchroFrame *libschroedinger_frame_from_data (AVCodecContext *avccontext, + void *in_data) +{ + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroFrame *in_frame; + /* Input line size may differ from what the codec supports. Especially + * when transcoding from one format to another. So use avpicture_layout + * to copy the frame. */ + in_frame = schro_frame_new_and_alloc (NULL, + p_schro_params->frame_format, + p_schro_params->format->width, + p_schro_params->format->height); + + avpicture_layout ((AVPicture *)in_data, avccontext->pix_fmt, + avccontext->width, avccontext->height, + in_frame->components[0].data, + p_schro_params->frame_size); + + return in_frame; +} + +static void SchroedingerFreeFrame(void *data) +{ + FfmpegDiracSchroEncodedFrame *enc_frame = data; + + av_freep (&(enc_frame->p_encbuf)); + av_free(enc_frame); +} + +static int libschroedinger_encode_frame(AVCodecContext *avccontext, + unsigned char *frame, + int buf_size, void *data) +{ + int enc_size = 0; + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + SchroEncoder *encoder = p_schro_params->encoder; + struct FfmpegDiracSchroEncodedFrame* p_frame_output = NULL; + int go = 1; + SchroBuffer *enc_buf; + int presentation_frame; + int parse_code; + int last_frame_in_sequence = 0; + + if(data == NULL) { + /* Push end of sequence if not already signalled. */ + if (!p_schro_params->eos_signalled) { + schro_encoder_end_of_stream(encoder); + p_schro_params->eos_signalled = 1; + } + } else { + /* Allocate frame data to schro input buffer. */ + SchroFrame *in_frame = libschroedinger_frame_from_data (avccontext, + data); + /* Load next frame. */ + schro_encoder_push_frame(encoder, in_frame); + } + + if (p_schro_params->eos_pulled) + go = 0; + + /* Now check to see if we have any output from the encoder. */ + while (go) { + SchroStateEnum state; + state = schro_encoder_wait(encoder); + switch (state) + { + case SCHRO_STATE_HAVE_BUFFER: + case SCHRO_STATE_END_OF_STREAM: + enc_buf = schro_encoder_pull (encoder, + &presentation_frame); + assert (enc_buf->length > 0); + assert (enc_buf->length <= buf_size); + parse_code = enc_buf->data[4]; + + /* All non-frame data is prepended to actual frame data to + * be able to set the pts correctly. So we don't write data + * to the frame output queue until we actually have a frame + */ + p_schro_params->enc_buf = av_realloc ( + p_schro_params->enc_buf, + p_schro_params->enc_buf_size + enc_buf->length + ); + + memcpy(p_schro_params->enc_buf+p_schro_params->enc_buf_size, + enc_buf->data, enc_buf->length); + p_schro_params->enc_buf_size += enc_buf->length; + + + if (state == SCHRO_STATE_END_OF_STREAM) { + p_schro_params->eos_pulled = 1; + go = 0; + } + + if (!SCHRO_PARSE_CODE_IS_PICTURE(parse_code)) { + schro_buffer_unref (enc_buf); + break; + } + + /* Create output frame. */ + p_frame_output = av_mallocz(sizeof(FfmpegDiracSchroEncodedFrame)); + /* Set output data. */ + p_frame_output->size = p_schro_params->enc_buf_size; + p_frame_output->p_encbuf = p_schro_params->enc_buf; + if (SCHRO_PARSE_CODE_IS_INTRA(parse_code) && + SCHRO_PARSE_CODE_IS_REFERENCE(parse_code)) { + p_frame_output->key_frame = 1; + } + + /* Parse the coded frame number from the bitstream. Bytes 14 + * through 17 represesent the frame number. */ + p_frame_output->frame_num = (enc_buf->data[13] << 24) + + (enc_buf->data[14] << 16) + + (enc_buf->data[15] << 8) + + enc_buf->data[16]; + + ff_dirac_schro_queue_push_back (&p_schro_params->enc_frame_queue, + p_frame_output); + p_schro_params->enc_buf_size = 0; + p_schro_params->enc_buf = NULL; + + schro_buffer_unref (enc_buf); + + break; + + case SCHRO_STATE_NEED_FRAME: + go = 0; + break; + + case SCHRO_STATE_AGAIN: + break; + + default: + av_log(avccontext, AV_LOG_ERROR, "Unknown Schro Encoder state\n"); + return -1; + } + } + + /* Copy 'next' frame in queue. */ + + if (p_schro_params->enc_frame_queue.size == 1 && + p_schro_params->eos_pulled) + last_frame_in_sequence = 1; + + p_frame_output = + ff_dirac_schro_queue_pop (&p_schro_params->enc_frame_queue); + + if (p_frame_output == NULL) + return 0; + + memcpy(frame, p_frame_output->p_encbuf, p_frame_output->size); + avccontext->coded_frame->key_frame = p_frame_output->key_frame; + /* Use the frame number of the encoded frame as the pts. It is OK to + * do so since Dirac is a constant frame rate codec. It expects input + * to be of constant frame rate. */ + avccontext->coded_frame->pts = p_frame_output->frame_num; + enc_size = p_frame_output->size; + + /* Append the end of sequence information to the last frame in the + * sequence. */ + if (last_frame_in_sequence && p_schro_params->enc_buf_size > 0) + { + memcpy (frame + enc_size, p_schro_params->enc_buf, + p_schro_params->enc_buf_size); + enc_size += p_schro_params->enc_buf_size; + av_freep (&p_schro_params->enc_buf); + p_schro_params->enc_buf_size = 0; + } + + /* free frame */ + SchroedingerFreeFrame (p_frame_output); + + return enc_size; +} + + +static int libschroedinger_encode_close(AVCodecContext *avccontext) +{ + + FfmpegSchroEncoderParams* p_schro_params = avccontext->priv_data; + + /* Close the encoder. */ + schro_encoder_free(p_schro_params->encoder); + + /* Free data in the output frame queue. */ + ff_dirac_schro_queue_free (&p_schro_params->enc_frame_queue, + SchroedingerFreeFrame); + + + /* Free the encoder buffer. */ + if (p_schro_params->enc_buf_size) + av_freep(&p_schro_params->enc_buf); + + /* Free the video format structure. */ + av_freep(&p_schro_params->format); + + return 0 ; +} + + +AVCodec libschroedinger_encoder = { + "libschroedinger", + CODEC_TYPE_VIDEO, + CODEC_ID_DIRAC, + sizeof(FfmpegSchroEncoderParams), + libschroedinger_encode_init, + libschroedinger_encode_frame, + libschroedinger_encode_close, + .capabilities= CODEC_CAP_DELAY, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_YUV422P, PIX_FMT_YUV444P, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("libschroedinger Dirac 2.2"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libtheoraenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/libtheoraenc.c new file mode 100644 index 0000000000..d7f635ca79 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libtheoraenc.c @@ -0,0 +1,281 @@ +/* + * Copyright (c) 2006 Paul Richards + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/*! + * \file theoraenc.c + * \brief Theora encoder using libtheora. + * \author Paul Richards + * + * A lot of this is copy / paste from other output codecs in + * libavcodec or pure guesswork (or both). + * + * I have used t_ prefixes on variables which are libtheora types + * and o_ prefixes on variables which are libogg types. + */ + +/* FFmpeg includes */ +#include "libavutil/log.h" +#include "avcodec.h" + +/* libtheora includes */ +#include + +typedef struct TheoraContext{ + theora_state t_state; +} TheoraContext; + +/*! + Concatenates an ogg_packet into the extradata. +*/ +static int concatenate_packet(unsigned int* offset, AVCodecContext* avc_context, const ogg_packet* packet) +{ + char* message = NULL; + uint8_t* newdata = NULL; + int newsize = avc_context->extradata_size + 2 + packet->bytes; + + if (packet->bytes < 0) { + message = "ogg_packet has negative size"; + } else if (packet->bytes > 0xffff) { + message = "ogg_packet is larger than 65535 bytes"; + } else if (newsize < avc_context->extradata_size) { + message = "extradata_size would overflow"; + } else { + newdata = av_realloc(avc_context->extradata, newsize); + if (newdata == NULL) { + message = "av_realloc failed"; + } + } + if (message != NULL) { + av_log(avc_context, AV_LOG_ERROR, "concatenate_packet failed: %s\n", message); + return -1; + } + + avc_context->extradata = newdata; + avc_context->extradata_size = newsize; + AV_WB16(avc_context->extradata + (*offset), packet->bytes); + *offset += 2; + memcpy( avc_context->extradata + (*offset), packet->packet, packet->bytes ); + (*offset) += packet->bytes; + return 0; +} + +static int encode_init(AVCodecContext* avc_context) +{ + theora_info t_info; + theora_comment t_comment; + ogg_packet o_packet; + unsigned int offset; + TheoraContext *h = avc_context->priv_data; + + /* Set up the theora_info struct */ + theora_info_init( &t_info ); + t_info.width = avc_context->width; + t_info.height = avc_context->height; + t_info.frame_width = avc_context->width; + t_info.frame_height = avc_context->height; + t_info.offset_x = 0; + t_info.offset_y = 0; + /* Swap numerator and denominator as time_base in AVCodecContext gives the + * time period between frames, but theora_info needs the framerate. */ + t_info.fps_numerator = avc_context->time_base.den; + t_info.fps_denominator = avc_context->time_base.num; + if (avc_context->sample_aspect_ratio.num != 0) { + t_info.aspect_numerator = avc_context->sample_aspect_ratio.num; + t_info.aspect_denominator = avc_context->sample_aspect_ratio.den; + } else { + t_info.aspect_numerator = 1; + t_info.aspect_denominator = 1; + } + t_info.colorspace = OC_CS_UNSPECIFIED; + t_info.pixelformat = OC_PF_420; + t_info.target_bitrate = avc_context->bit_rate; + t_info.keyframe_frequency = avc_context->gop_size; + t_info.keyframe_frequency_force = avc_context->gop_size; + t_info.keyframe_mindistance = avc_context->keyint_min; + t_info.quality = 0; + + t_info.quick_p = 1; + t_info.dropframes_p = 0; + t_info.keyframe_auto_p = 1; + t_info.keyframe_data_target_bitrate = t_info.target_bitrate * 1.5; + t_info.keyframe_auto_threshold = 80; + t_info.noise_sensitivity = 1; + t_info.sharpness = 0; + + /* Now initialise libtheora */ + if (theora_encode_init( &(h->t_state), &t_info ) != 0) { + av_log(avc_context, AV_LOG_ERROR, "theora_encode_init failed\n"); + return -1; + } + + /* Clear up theora_info struct */ + theora_info_clear( &t_info ); + + /* + Output first header packet consisting of theora + header, comment, and tables. + + Each one is prefixed with a 16bit size, then they + are concatenated together into ffmpeg's extradata. + */ + offset = 0; + + /* Header */ + theora_encode_header( &(h->t_state), &o_packet ); + if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { + return -1; + } + + /* Comment */ + theora_comment_init( &t_comment ); + theora_encode_comment( &t_comment, &o_packet ); + if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { + return -1; + } + + /* Tables */ + theora_encode_tables( &(h->t_state), &o_packet ); + if (concatenate_packet( &offset, avc_context, &o_packet ) != 0) { + return -1; + } + + /* Clear up theora_comment struct */ + theora_comment_clear( &t_comment ); + + /* Set up the output AVFrame */ + avc_context->coded_frame= avcodec_alloc_frame(); + + return 0; +} + +static int encode_frame( + AVCodecContext* avc_context, + uint8_t *outbuf, + int buf_size, + void *data) +{ + yuv_buffer t_yuv_buffer; + TheoraContext *h = avc_context->priv_data; + AVFrame *frame = data; + ogg_packet o_packet; + int result; + + assert(avc_context->pix_fmt == PIX_FMT_YUV420P); + + /* Copy planes to the theora yuv_buffer */ + if (frame->linesize[1] != frame->linesize[2]) { + av_log(avc_context, AV_LOG_ERROR, "U and V stride differ\n"); + return -1; + } + + t_yuv_buffer.y_width = avc_context->width; + t_yuv_buffer.y_height = avc_context->height; + t_yuv_buffer.y_stride = frame->linesize[0]; + t_yuv_buffer.uv_width = t_yuv_buffer.y_width / 2; + t_yuv_buffer.uv_height = t_yuv_buffer.y_height / 2; + t_yuv_buffer.uv_stride = frame->linesize[1]; + + t_yuv_buffer.y = frame->data[0]; + t_yuv_buffer.u = frame->data[1]; + t_yuv_buffer.v = frame->data[2]; + + /* Now call into theora_encode_YUVin */ + result = theora_encode_YUVin( &(h->t_state), &t_yuv_buffer ); + if (result != 0) { + const char* message; + switch (result) { + case -1: + message = "differing frame sizes"; + break; + case OC_EINVAL: + message = "encoder is not ready or is finished"; + break; + default: + message = "unknown reason"; + break; + } + av_log(avc_context, AV_LOG_ERROR, "theora_encode_YUVin failed (%s) [%d]\n", message, result); + return -1; + } + + /* Pick up returned ogg_packet */ + result = theora_encode_packetout( &(h->t_state), 0, &o_packet ); + switch (result) { + case 0: + /* No packet is ready */ + return 0; + case 1: + /* Success, we have a packet */ + break; + default: + av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed [%d]\n", result); + return -1; + } + + /* Copy ogg_packet content out to buffer */ + if (buf_size < o_packet.bytes) { + av_log(avc_context, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + memcpy(outbuf, o_packet.packet, o_packet.bytes); + + return o_packet.bytes; +} + +static int encode_close(AVCodecContext* avc_context) +{ + ogg_packet o_packet; + TheoraContext *h = avc_context->priv_data; + int result; + const char* message; + + result = theora_encode_packetout( &(h->t_state), 1, &o_packet ); + theora_clear( &(h->t_state) ); + switch (result) { + case 0:/* No packet is ready */ + case -1:/* Encoding finished */ + return 0; + case 1: + /* We have a packet */ + message = "gave us a packet"; + break; + default: + message = "unknown reason"; + break; + } + av_log(avc_context, AV_LOG_ERROR, "theora_encode_packetout failed (%s) [%d]\n", message, result); + return -1; +} + +static const enum PixelFormat supported_pixel_formats[] = { PIX_FMT_YUV420P, PIX_FMT_NONE }; + +/*! AVCodec struct exposed to libavcodec */ +AVCodec libtheora_encoder = +{ + .name = "libtheora", + .type = CODEC_TYPE_VIDEO, + .id = CODEC_ID_THEORA, + .priv_data_size = sizeof(TheoraContext), + .init = encode_init, + .close = encode_close, + .encode = encode_frame, + .pix_fmts = supported_pixel_formats, + .long_name = NULL_IF_CONFIG_SMALL("libtheora Theora"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libvorbis.c b/src/add-ons/media/plugins/avcodec/libavcodec/libvorbis.c new file mode 100644 index 0000000000..ce796a05f7 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libvorbis.c @@ -0,0 +1,222 @@ +/* + * copyright (c) 2002 Mark Hills + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file oggvorbis.c + * Ogg Vorbis codec support via libvorbisenc. + * @author Mark Hills + */ + +#include + +#include "avcodec.h" +#include "bytestream.h" + +#undef NDEBUG +#include + +#define OGGVORBIS_FRAME_SIZE 64 + +#define BUFFER_SIZE (1024*64) + +typedef struct OggVorbisContext { + vorbis_info vi ; + vorbis_dsp_state vd ; + vorbis_block vb ; + uint8_t buffer[BUFFER_SIZE]; + int buffer_index; + + /* decoder */ + vorbis_comment vc ; + ogg_packet op; +} OggVorbisContext ; + + +static int oggvorbis_init_encoder(vorbis_info *vi, AVCodecContext *avccontext) { + double cfreq; + + if(avccontext->flags & CODEC_FLAG_QSCALE) { + /* variable bitrate */ + if(vorbis_encode_setup_vbr(vi, avccontext->channels, + avccontext->sample_rate, + avccontext->global_quality / (float)FF_QP2LAMBDA)) + return -1; + } else { + /* constant bitrate */ + if(vorbis_encode_setup_managed(vi, avccontext->channels, + avccontext->sample_rate, -1, avccontext->bit_rate, -1)) + return -1; + +#ifdef OGGVORBIS_VBR_BY_ESTIMATE + /* variable bitrate by estimate */ + if(vorbis_encode_ctl(vi, OV_ECTL_RATEMANAGE_AVG, NULL)) + return -1; +#endif + } + + /* cutoff frequency */ + if(avccontext->cutoff > 0) { + cfreq = avccontext->cutoff / 1000.0; + if(vorbis_encode_ctl(vi, OV_ECTL_LOWPASS_SET, &cfreq)) + return -1; + } + + return vorbis_encode_setup_init(vi); +} + +static av_cold int oggvorbis_encode_init(AVCodecContext *avccontext) { + OggVorbisContext *context = avccontext->priv_data ; + ogg_packet header, header_comm, header_code; + uint8_t *p; + unsigned int offset, len; + + vorbis_info_init(&context->vi) ; + if(oggvorbis_init_encoder(&context->vi, avccontext) < 0) { + av_log(avccontext, AV_LOG_ERROR, "oggvorbis_encode_init: init_encoder failed") ; + return -1 ; + } + vorbis_analysis_init(&context->vd, &context->vi) ; + vorbis_block_init(&context->vd, &context->vb) ; + + vorbis_comment_init(&context->vc); + vorbis_comment_add_tag(&context->vc, "encoder", LIBAVCODEC_IDENT) ; + + vorbis_analysis_headerout(&context->vd, &context->vc, &header, + &header_comm, &header_code); + + len = header.bytes + header_comm.bytes + header_code.bytes; + avccontext->extradata_size= 64 + len + len/255; + p = avccontext->extradata= av_mallocz(avccontext->extradata_size); + p[0] = 2; + offset = 1; + offset += av_xiphlacing(&p[offset], header.bytes); + offset += av_xiphlacing(&p[offset], header_comm.bytes); + memcpy(&p[offset], header.packet, header.bytes); + offset += header.bytes; + memcpy(&p[offset], header_comm.packet, header_comm.bytes); + offset += header_comm.bytes; + memcpy(&p[offset], header_code.packet, header_code.bytes); + offset += header_code.bytes; + avccontext->extradata_size = offset; + avccontext->extradata= av_realloc(avccontext->extradata, avccontext->extradata_size); + +/* vorbis_block_clear(&context->vb); + vorbis_dsp_clear(&context->vd); + vorbis_info_clear(&context->vi);*/ + vorbis_comment_clear(&context->vc); + + avccontext->frame_size = OGGVORBIS_FRAME_SIZE ; + + avccontext->coded_frame= avcodec_alloc_frame(); + avccontext->coded_frame->key_frame= 1; + + return 0 ; +} + + +static int oggvorbis_encode_frame(AVCodecContext *avccontext, + unsigned char *packets, + int buf_size, void *data) +{ + OggVorbisContext *context = avccontext->priv_data ; + float **buffer ; + ogg_packet op ; + signed short *audio = data ; + int l, samples = data ? OGGVORBIS_FRAME_SIZE : 0; + + buffer = vorbis_analysis_buffer(&context->vd, samples) ; + + if(context->vi.channels == 1) { + for(l = 0 ; l < samples ; l++) + buffer[0][l]=audio[l]/32768.f; + } else { + for(l = 0 ; l < samples ; l++){ + buffer[0][l]=audio[l*2]/32768.f; + buffer[1][l]=audio[l*2+1]/32768.f; + } + } + + vorbis_analysis_wrote(&context->vd, samples) ; + + while(vorbis_analysis_blockout(&context->vd, &context->vb) == 1) { + vorbis_analysis(&context->vb, NULL); + vorbis_bitrate_addblock(&context->vb) ; + + while(vorbis_bitrate_flushpacket(&context->vd, &op)) { + /* i'd love to say the following line is a hack, but sadly it's + * not, apparently the end of stream decision is in libogg. */ + if(op.bytes==1) + continue; + memcpy(context->buffer + context->buffer_index, &op, sizeof(ogg_packet)); + context->buffer_index += sizeof(ogg_packet); + memcpy(context->buffer + context->buffer_index, op.packet, op.bytes); + context->buffer_index += op.bytes; +// av_log(avccontext, AV_LOG_DEBUG, "e%d / %d\n", context->buffer_index, op.bytes); + } + } + + l=0; + if(context->buffer_index){ + ogg_packet *op2= (ogg_packet*)context->buffer; + op2->packet = context->buffer + sizeof(ogg_packet); + + l= op2->bytes; + avccontext->coded_frame->pts= av_rescale_q(op2->granulepos, (AVRational){1, avccontext->sample_rate}, avccontext->time_base); + //FIXME we should reorder the user supplied pts and not assume that they are spaced by 1/sample_rate + + memcpy(packets, op2->packet, l); + context->buffer_index -= l + sizeof(ogg_packet); + memcpy(context->buffer, context->buffer + l + sizeof(ogg_packet), context->buffer_index); +// av_log(avccontext, AV_LOG_DEBUG, "E%d\n", l); + } + + return l; +} + + +static av_cold int oggvorbis_encode_close(AVCodecContext *avccontext) { + OggVorbisContext *context = avccontext->priv_data ; +/* ogg_packet op ; */ + + vorbis_analysis_wrote(&context->vd, 0) ; /* notify vorbisenc this is EOF */ + + vorbis_block_clear(&context->vb); + vorbis_dsp_clear(&context->vd); + vorbis_info_clear(&context->vi); + + av_freep(&avccontext->coded_frame); + av_freep(&avccontext->extradata); + + return 0 ; +} + + +AVCodec libvorbis_encoder = { + "libvorbis", + CODEC_TYPE_AUDIO, + CODEC_ID_VORBIS, + sizeof(OggVorbisContext), + oggvorbis_encode_init, + oggvorbis_encode_frame, + oggvorbis_encode_close, + .capabilities= CODEC_CAP_DELAY, + .sample_fmts = (enum SampleFormat[]){SAMPLE_FMT_S16,SAMPLE_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("libvorbis Vorbis"), +} ; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libx264.c b/src/add-ons/media/plugins/avcodec/libavcodec/libx264.c new file mode 100644 index 0000000000..e885f074f5 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libx264.c @@ -0,0 +1,305 @@ +/* + * H.264 encoding using the x264 library + * Copyright (C) 2005 Mans Rullgard + * + * 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 "avcodec.h" +#include +#include +#include +#include +#include + +typedef struct X264Context { + x264_param_t params; + x264_t *enc; + x264_picture_t pic; + AVFrame out_pic; +} X264Context; + +static void +X264_log(void *p, int level, const char *fmt, va_list args) +{ + static const int level_map[] = { + [X264_LOG_ERROR] = AV_LOG_ERROR, + [X264_LOG_WARNING] = AV_LOG_WARNING, + [X264_LOG_INFO] = AV_LOG_INFO, + [X264_LOG_DEBUG] = AV_LOG_DEBUG + }; + + if(level < 0 || level > X264_LOG_DEBUG) + return; + + av_vlog(p, level_map[level], fmt, args); +} + + +static int +encode_nals(uint8_t *buf, int size, x264_nal_t *nals, int nnal) +{ + uint8_t *p = buf; + int i; + + for(i = 0; i < nnal; i++){ + int s = x264_nal_encode(p, &size, 1, nals + i); + if(s < 0) + return -1; + p += s; + } + + return p - buf; +} + +static int +X264_frame(AVCodecContext *ctx, uint8_t *buf, int bufsize, void *data) +{ + X264Context *x4 = ctx->priv_data; + AVFrame *frame = data; + x264_nal_t *nal; + int nnal, i; + x264_picture_t pic_out; + + x4->pic.img.i_csp = X264_CSP_I420; + x4->pic.img.i_plane = 3; + + if (frame) { + for(i = 0; i < 3; i++){ + x4->pic.img.plane[i] = frame->data[i]; + x4->pic.img.i_stride[i] = frame->linesize[i]; + } + + x4->pic.i_pts = frame->pts; + x4->pic.i_type = X264_TYPE_AUTO; + } + + if(x264_encoder_encode(x4->enc, &nal, &nnal, frame? &x4->pic: NULL, + &pic_out)) + return -1; + + bufsize = encode_nals(buf, bufsize, nal, nnal); + if(bufsize < 0) + return -1; + + /* FIXME: dts */ + x4->out_pic.pts = pic_out.i_pts; + + switch(pic_out.i_type){ + case X264_TYPE_IDR: + case X264_TYPE_I: + x4->out_pic.pict_type = FF_I_TYPE; + break; + case X264_TYPE_P: + x4->out_pic.pict_type = FF_P_TYPE; + break; + case X264_TYPE_B: + case X264_TYPE_BREF: + x4->out_pic.pict_type = FF_B_TYPE; + break; + } + + x4->out_pic.key_frame = pic_out.i_type == X264_TYPE_IDR; + x4->out_pic.quality = (pic_out.i_qpplus1 - 1) * FF_QP2LAMBDA; + + return bufsize; +} + +static av_cold int +X264_close(AVCodecContext *avctx) +{ + X264Context *x4 = avctx->priv_data; + + if(x4->enc) + x264_encoder_close(x4->enc); + + return 0; +} + +static av_cold int +X264_init(AVCodecContext *avctx) +{ + X264Context *x4 = avctx->priv_data; + + x264_param_default(&x4->params); + + x4->params.pf_log = X264_log; + x4->params.p_log_private = avctx; + + x4->params.i_keyint_max = avctx->gop_size; + x4->params.rc.i_bitrate = avctx->bit_rate / 1000; + x4->params.rc.i_vbv_buffer_size = avctx->rc_buffer_size / 1000; + x4->params.rc.i_vbv_max_bitrate = avctx->rc_max_rate / 1000; + x4->params.rc.b_stat_write = avctx->flags & CODEC_FLAG_PASS1; + if(avctx->flags & CODEC_FLAG_PASS2) x4->params.rc.b_stat_read = 1; + else{ + if(avctx->crf){ + x4->params.rc.i_rc_method = X264_RC_CRF; + x4->params.rc.f_rf_constant = avctx->crf; + }else if(avctx->cqp > -1){ + x4->params.rc.i_rc_method = X264_RC_CQP; + x4->params.rc.i_qp_constant = avctx->cqp; + } + } + + // if neither crf nor cqp modes are selected we have to enable the RC + // we do it this way because we cannot check if the bitrate has been set + if(!(avctx->crf || (avctx->cqp > -1))) x4->params.rc.i_rc_method = X264_RC_ABR; + + x4->params.i_bframe = avctx->max_b_frames; + x4->params.b_cabac = avctx->coder_type == FF_CODER_TYPE_AC; + x4->params.b_bframe_adaptive = avctx->b_frame_strategy; + x4->params.i_bframe_bias = avctx->bframebias; + x4->params.b_bframe_pyramid = avctx->flags2 & CODEC_FLAG2_BPYRAMID; + avctx->has_b_frames= avctx->flags2 & CODEC_FLAG2_BPYRAMID ? 2 : !!avctx->max_b_frames; + + x4->params.i_keyint_min = avctx->keyint_min; + if(x4->params.i_keyint_min > x4->params.i_keyint_max) + x4->params.i_keyint_min = x4->params.i_keyint_max; + + x4->params.i_scenecut_threshold = avctx->scenechange_threshold; + + x4->params.b_deblocking_filter = avctx->flags & CODEC_FLAG_LOOP_FILTER; + x4->params.i_deblocking_filter_alphac0 = avctx->deblockalpha; + x4->params.i_deblocking_filter_beta = avctx->deblockbeta; + + x4->params.rc.i_qp_min = avctx->qmin; + x4->params.rc.i_qp_max = avctx->qmax; + x4->params.rc.i_qp_step = avctx->max_qdiff; + + x4->params.rc.f_qcompress = avctx->qcompress; /* 0.0 => cbr, 1.0 => constant qp */ + x4->params.rc.f_qblur = avctx->qblur; /* temporally blur quants */ + x4->params.rc.f_complexity_blur = avctx->complexityblur; + + x4->params.i_frame_reference = avctx->refs; + + x4->params.i_width = avctx->width; + x4->params.i_height = avctx->height; + x4->params.vui.i_sar_width = avctx->sample_aspect_ratio.num; + x4->params.vui.i_sar_height = avctx->sample_aspect_ratio.den; + x4->params.i_fps_num = avctx->time_base.den; + x4->params.i_fps_den = avctx->time_base.num; + + x4->params.analyse.inter = 0; + if(avctx->partitions){ + if(avctx->partitions & X264_PART_I4X4) + x4->params.analyse.inter |= X264_ANALYSE_I4x4; + if(avctx->partitions & X264_PART_I8X8) + x4->params.analyse.inter |= X264_ANALYSE_I8x8; + if(avctx->partitions & X264_PART_P8X8) + x4->params.analyse.inter |= X264_ANALYSE_PSUB16x16; + if(avctx->partitions & X264_PART_P4X4) + x4->params.analyse.inter |= X264_ANALYSE_PSUB8x8; + if(avctx->partitions & X264_PART_B8X8) + x4->params.analyse.inter |= X264_ANALYSE_BSUB16x16; + } + + x4->params.analyse.i_direct_mv_pred = avctx->directpred; + + x4->params.analyse.b_weighted_bipred = avctx->flags2 & CODEC_FLAG2_WPRED; + + if(avctx->me_method == ME_EPZS) + x4->params.analyse.i_me_method = X264_ME_DIA; + else if(avctx->me_method == ME_HEX) + x4->params.analyse.i_me_method = X264_ME_HEX; + else if(avctx->me_method == ME_UMH) + x4->params.analyse.i_me_method = X264_ME_UMH; + else if(avctx->me_method == ME_FULL) + x4->params.analyse.i_me_method = X264_ME_ESA; + else if(avctx->me_method == ME_TESA) + x4->params.analyse.i_me_method = X264_ME_TESA; + else x4->params.analyse.i_me_method = X264_ME_HEX; + + x4->params.analyse.i_me_range = avctx->me_range; + x4->params.analyse.i_subpel_refine = avctx->me_subpel_quality; + + x4->params.analyse.b_bidir_me = avctx->bidir_refine > 0; + x4->params.analyse.b_bframe_rdo = avctx->flags2 & CODEC_FLAG2_BRDO; + x4->params.analyse.b_mixed_references = + avctx->flags2 & CODEC_FLAG2_MIXED_REFS; + x4->params.analyse.b_chroma_me = avctx->me_cmp & FF_CMP_CHROMA; + x4->params.analyse.b_transform_8x8 = avctx->flags2 & CODEC_FLAG2_8X8DCT; + x4->params.analyse.b_fast_pskip = avctx->flags2 & CODEC_FLAG2_FASTPSKIP; + + x4->params.analyse.i_trellis = avctx->trellis; + x4->params.analyse.i_noise_reduction = avctx->noise_reduction; + + if(avctx->level > 0) x4->params.i_level_idc = avctx->level; + + x4->params.rc.f_rate_tolerance = + (float)avctx->bit_rate_tolerance/avctx->bit_rate; + + if((avctx->rc_buffer_size != 0) && + (avctx->rc_initial_buffer_occupancy <= avctx->rc_buffer_size)){ + x4->params.rc.f_vbv_buffer_init = + (float)avctx->rc_initial_buffer_occupancy/avctx->rc_buffer_size; + } + else x4->params.rc.f_vbv_buffer_init = 0.9; + + x4->params.rc.f_ip_factor = 1/fabs(avctx->i_quant_factor); + x4->params.rc.f_pb_factor = avctx->b_quant_factor; + x4->params.analyse.i_chroma_qp_offset = avctx->chromaoffset; + x4->params.rc.psz_rc_eq = avctx->rc_eq; + + x4->params.analyse.b_psnr = avctx->flags & CODEC_FLAG_PSNR; + x4->params.i_log_level = X264_LOG_DEBUG; + + x4->params.b_aud = avctx->flags2 & CODEC_FLAG2_AUD; + + x4->params.i_threads = avctx->thread_count; + + x4->params.b_interlaced = avctx->flags & CODEC_FLAG_INTERLACED_DCT; + + if(avctx->flags & CODEC_FLAG_GLOBAL_HEADER){ + x4->params.b_repeat_headers = 0; + } + + x4->enc = x264_encoder_open(&x4->params); + if(!x4->enc) + return -1; + + avctx->coded_frame = &x4->out_pic; + + if(avctx->flags & CODEC_FLAG_GLOBAL_HEADER){ + x264_nal_t *nal; + int nnal, i, s = 0; + + x264_encoder_headers(x4->enc, &nal, &nnal); + + /* 5 bytes NAL header + worst case escaping */ + for(i = 0; i < nnal; i++) + s += 5 + nal[i].i_payload * 4 / 3; + + avctx->extradata = av_malloc(s); + avctx->extradata_size = encode_nals(avctx->extradata, s, nal, nnal); + } + + return 0; +} + +AVCodec libx264_encoder = { + .name = "libx264", + .type = CODEC_TYPE_VIDEO, + .id = CODEC_ID_H264, + .priv_data_size = sizeof(X264Context), + .init = X264_init, + .encode = X264_frame, + .close = X264_close, + .capabilities = CODEC_CAP_DELAY, + .pix_fmts = (enum PixelFormat[]) { PIX_FMT_YUV420P, PIX_FMT_NONE }, + .long_name = NULL_IF_CONFIG_SMALL("libx264 H.264 / AVC / MPEG-4 AVC / MPEG-4 part 10"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_internal.h b/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_internal.h new file mode 100644 index 0000000000..bce30cebf2 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_internal.h @@ -0,0 +1,32 @@ +/* + * copyright (C) 2006 Corey Hickey + * + * 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 FFMPEG_LIBXVID_INTERNAL_H +#define FFMPEG_LIBXVID_INTERNAL_H + +/** + * @file libxvid_internal.h + * common functions for use with the Xvid wrappers + */ + + +int av_tempfile(char *prefix, char **filename); + +#endif /* FFMPEG_LIBXVID_INTERNAL_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_rc.c b/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_rc.c new file mode 100644 index 0000000000..c161ba7101 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libxvid_rc.c @@ -0,0 +1,148 @@ +/* + * Xvid rate control wrapper for lavc video encoders + * + * Copyright (c) 2006 Michael Niedermayer + * + * 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 +#include +#include "avcodec.h" +#include "libxvid_internal.h" +//#include "dsputil.h" +#include "mpegvideo.h" + +#undef NDEBUG +#include + +extern unsigned int xvid_debug; + +int ff_xvid_rate_control_init(MpegEncContext *s){ + char *tmp_name; + int fd, i; + xvid_plg_create_t xvid_plg_create; + xvid_plugin_2pass2_t xvid_2pass2; + +//xvid_debug=-1; + + fd=av_tempfile("xvidrc.", &tmp_name); + if (fd == -1) { + av_log(NULL, AV_LOG_ERROR, "Can't create temporary pass2 file.\n"); + return -1; + } + + for(i=0; irc_context.num_entries; i++){ + static const char *frame_types = " ipbs"; + char tmp[256]; + RateControlEntry *rce; + + rce= &s->rc_context.entry[i]; + + snprintf(tmp, sizeof(tmp), "%c %d %d %d %d %d %d\n", + frame_types[rce->pict_type], (int)lrintf(rce->qscale / FF_QP2LAMBDA), rce->i_count, s->mb_num - rce->i_count - rce->skip_count, + rce->skip_count, (rce->i_tex_bits + rce->p_tex_bits + rce->misc_bits+7)/8, (rce->header_bits+rce->mv_bits+7)/8); + +//av_log(NULL, AV_LOG_ERROR, "%s\n", tmp); + write(fd, tmp, strlen(tmp)); + } + + close(fd); + + memset(&xvid_2pass2, 0, sizeof(xvid_2pass2)); + xvid_2pass2.version= XVID_MAKE_VERSION(1,1,0); + xvid_2pass2.filename= tmp_name; + xvid_2pass2.bitrate= s->avctx->bit_rate; + xvid_2pass2.vbv_size= s->avctx->rc_buffer_size; + xvid_2pass2.vbv_maxrate= s->avctx->rc_max_rate; + xvid_2pass2.vbv_initial= s->avctx->rc_initial_buffer_occupancy; + + memset(&xvid_plg_create, 0, sizeof(xvid_plg_create)); + xvid_plg_create.version= XVID_MAKE_VERSION(1,1,0); + xvid_plg_create.fbase= s->avctx->time_base.den; + xvid_plg_create.fincr= s->avctx->time_base.num; + xvid_plg_create.param= &xvid_2pass2; + + if(xvid_plugin_2pass2(NULL, XVID_PLG_CREATE, &xvid_plg_create, &s->rc_context.non_lavc_opaque)<0){ + av_log(NULL, AV_LOG_ERROR, "xvid_plugin_2pass2 failed\n"); + return -1; + } + return 0; +} + +float ff_xvid_rate_estimate_qscale(MpegEncContext *s, int dry_run){ + xvid_plg_data_t xvid_plg_data; + + memset(&xvid_plg_data, 0, sizeof(xvid_plg_data)); + xvid_plg_data.version= XVID_MAKE_VERSION(1,1,0); + xvid_plg_data.width = s->width; + xvid_plg_data.height= s->height; + xvid_plg_data.mb_width = s->mb_width; + xvid_plg_data.mb_height= s->mb_height; + xvid_plg_data.fbase= s->avctx->time_base.den; + xvid_plg_data.fincr= s->avctx->time_base.num; + xvid_plg_data.min_quant[0]= s->avctx->qmin; + xvid_plg_data.min_quant[1]= s->avctx->qmin; + xvid_plg_data.min_quant[2]= s->avctx->qmin; //FIXME i/b factor & offset + xvid_plg_data.max_quant[0]= s->avctx->qmax; + xvid_plg_data.max_quant[1]= s->avctx->qmax; + xvid_plg_data.max_quant[2]= s->avctx->qmax; //FIXME i/b factor & offset + xvid_plg_data.bquant_offset = 0; // 100 * s->avctx->b_quant_offset; + xvid_plg_data.bquant_ratio = 100; // * s->avctx->b_quant_factor; + +#if 0 + xvid_plg_data.stats.hlength= X +#endif + + if(!s->rc_context.dry_run_qscale){ + if(s->picture_number){ + xvid_plg_data.length= + xvid_plg_data.stats.length= (s->frame_bits + 7)/8; + xvid_plg_data.frame_num= s->rc_context.last_picture_number; + xvid_plg_data.quant= s->qscale; + + xvid_plg_data.type= s->last_pict_type; + if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_AFTER, &xvid_plg_data, NULL)){ + av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_AFTER, ...) FAILED\n"); + return -1; + } + } + s->rc_context.last_picture_number= + xvid_plg_data.frame_num= s->picture_number; + xvid_plg_data.quant= 0; + if(xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_BEFORE, &xvid_plg_data, NULL)){ + av_log(s->avctx, AV_LOG_ERROR, "xvid_plugin_2pass2(handle, XVID_PLG_BEFORE, ...) FAILED\n"); + return -1; + } + s->rc_context.dry_run_qscale= xvid_plg_data.quant; + } + xvid_plg_data.quant= s->rc_context.dry_run_qscale; + if(!dry_run) + s->rc_context.dry_run_qscale= 0; + + if(s->pict_type == FF_B_TYPE) //FIXME this is not exactly identical to xvid + return xvid_plg_data.quant * FF_QP2LAMBDA * s->avctx->b_quant_factor + s->avctx->b_quant_offset; + else + return xvid_plg_data.quant * FF_QP2LAMBDA; +} + +void ff_xvid_rate_control_uninit(MpegEncContext *s){ + xvid_plg_destroy_t xvid_plg_destroy; + + xvid_plugin_2pass2(s->rc_context.non_lavc_opaque, XVID_PLG_DESTROY, &xvid_plg_destroy, NULL); +} + diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/libxvidff.c b/src/add-ons/media/plugins/avcodec/libavcodec/libxvidff.c new file mode 100644 index 0000000000..aa55bf338c --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/libxvidff.c @@ -0,0 +1,782 @@ +/* + * Interface to xvidcore for mpeg4 encoding + * Copyright (c) 2004 Adam Thayer + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file xvidmpeg4.c + * Interface to xvidcore for MPEG-4 compliant encoding. + * @author Adam Thayer (krevnik@comcast.net) + */ + +#include +#include +#include "avcodec.h" +#include "libxvid_internal.h" + +/** + * Buffer management macros. + */ +#define BUFFER_SIZE 1024 +#define BUFFER_REMAINING(x) (BUFFER_SIZE - strlen(x)) +#define BUFFER_CAT(x) (&((x)[strlen(x)])) + +/* For PPC Use */ +extern int has_altivec(void); + +/** + * Structure for the private Xvid context. + * This stores all the private context for the codec. + */ +typedef struct xvid_context { + void *encoder_handle; /** Handle for Xvid encoder */ + int xsize, ysize; /** Frame size */ + int vop_flags; /** VOP flags for Xvid encoder */ + int vol_flags; /** VOL flags for Xvid encoder */ + int me_flags; /** Motion Estimation flags */ + int qscale; /** Do we use constant scale? */ + int quicktime_format; /** Are we in a QT-based format? */ + AVFrame encoded_picture; /** Encoded frame information */ + char *twopassbuffer; /** Character buffer for two-pass */ + char *old_twopassbuffer; /** Old character buffer (two-pass) */ + char *twopassfile; /** second pass temp file name */ + unsigned char *intra_matrix; /** P-Frame Quant Matrix */ + unsigned char *inter_matrix; /** I-Frame Quant Matrix */ +} xvid_context_t; + +/** + * Structure for the private first-pass plugin. + */ +typedef struct xvid_ff_pass1 { + int version; /** Xvid version */ + xvid_context_t *context; /** Pointer to private context */ +} xvid_ff_pass1_t; + +/* Prototypes - See function implementation for details */ +int xvid_strip_vol_header(AVCodecContext *avctx, unsigned char *frame, unsigned int header_len, unsigned int frame_len); +int xvid_ff_2pass(void *ref, int opt, void *p1, void *p2); +void xvid_correct_framerate(AVCodecContext *avctx); + +/** + * Creates the private context for the encoder. + * All buffers are allocated, settings are loaded from the user, + * and the encoder context created. + * + * @param avctx AVCodecContext pointer to context + * @return Returns 0 on success, -1 on failure + */ +av_cold int ff_xvid_encode_init(AVCodecContext *avctx) { + int xerr, i; + int xvid_flags = avctx->flags; + xvid_context_t *x = avctx->priv_data; + uint16_t *intra, *inter; + int fd; + + xvid_plugin_single_t single; + xvid_ff_pass1_t rc2pass1; + xvid_plugin_2pass2_t rc2pass2; + xvid_gbl_init_t xvid_gbl_init; + xvid_enc_create_t xvid_enc_create; + xvid_enc_plugin_t plugins[7]; + + /* Bring in VOP flags from ffmpeg command-line */ + x->vop_flags = XVID_VOP_HALFPEL; /* Bare minimum quality */ + if( xvid_flags & CODEC_FLAG_4MV ) + x->vop_flags |= XVID_VOP_INTER4V; /* Level 3 */ + if( avctx->trellis +#if LIBAVCODEC_VERSION_INT < ((52<<16)+(0<<8)+0) + || xvid_flags & CODEC_FLAG_TRELLIS_QUANT +#endif + ) + x->vop_flags |= XVID_VOP_TRELLISQUANT; /* Level 5 */ + if( xvid_flags & CODEC_FLAG_AC_PRED ) + x->vop_flags |= XVID_VOP_HQACPRED; /* Level 6 */ + if( xvid_flags & CODEC_FLAG_GRAY ) + x->vop_flags |= XVID_VOP_GREYSCALE; + + /* Decide which ME quality setting to use */ + x->me_flags = 0; + switch( avctx->me_method ) { + case ME_FULL: /* Quality 6 */ + x->me_flags |= XVID_ME_EXTSEARCH16 + | XVID_ME_EXTSEARCH8; + + case ME_EPZS: /* Quality 4 */ + x->me_flags |= XVID_ME_ADVANCEDDIAMOND8 + | XVID_ME_HALFPELREFINE8 + | XVID_ME_CHROMA_PVOP + | XVID_ME_CHROMA_BVOP; + + case ME_LOG: /* Quality 2 */ + case ME_PHODS: + case ME_X1: + x->me_flags |= XVID_ME_ADVANCEDDIAMOND16 + | XVID_ME_HALFPELREFINE16; + + case ME_ZERO: /* Quality 0 */ + default: + break; + } + + /* Decide how we should decide blocks */ + switch( avctx->mb_decision ) { + case 2: + x->vop_flags |= XVID_VOP_MODEDECISION_RD; + x->me_flags |= XVID_ME_HALFPELREFINE8_RD + | XVID_ME_QUARTERPELREFINE8_RD + | XVID_ME_EXTSEARCH_RD + | XVID_ME_CHECKPREDICTION_RD; + case 1: + if( !(x->vop_flags & XVID_VOP_MODEDECISION_RD) ) + x->vop_flags |= XVID_VOP_FAST_MODEDECISION_RD; + x->me_flags |= XVID_ME_HALFPELREFINE16_RD + | XVID_ME_QUARTERPELREFINE16_RD; + + default: + break; + } + + /* Bring in VOL flags from ffmpeg command-line */ + x->vol_flags = 0; + if( xvid_flags & CODEC_FLAG_GMC ) { + x->vol_flags |= XVID_VOL_GMC; + x->me_flags |= XVID_ME_GME_REFINE; + } + if( xvid_flags & CODEC_FLAG_QPEL ) { + x->vol_flags |= XVID_VOL_QUARTERPEL; + x->me_flags |= XVID_ME_QUARTERPELREFINE16; + if( x->vop_flags & XVID_VOP_INTER4V ) + x->me_flags |= XVID_ME_QUARTERPELREFINE8; + } + + memset(&xvid_gbl_init, 0, sizeof(xvid_gbl_init)); + xvid_gbl_init.version = XVID_VERSION; + xvid_gbl_init.debug = 0; + +#ifdef ARCH_POWERPC + /* Xvid's PPC support is borked, use libavcodec to detect */ +#ifdef HAVE_ALTIVEC + if( has_altivec() ) { + xvid_gbl_init.cpu_flags = XVID_CPU_FORCE | XVID_CPU_ALTIVEC; + } else +#endif + xvid_gbl_init.cpu_flags = XVID_CPU_FORCE; +#else + /* Xvid can detect on x86 */ + xvid_gbl_init.cpu_flags = 0; +#endif + + /* Initialize */ + xvid_global(NULL, XVID_GBL_INIT, &xvid_gbl_init, NULL); + + /* Create the encoder reference */ + memset(&xvid_enc_create, 0, sizeof(xvid_enc_create)); + xvid_enc_create.version = XVID_VERSION; + + /* Store the desired frame size */ + xvid_enc_create.width = x->xsize = avctx->width; + xvid_enc_create.height = x->ysize = avctx->height; + + /* Xvid can determine the proper profile to use */ + /* xvid_enc_create.profile = XVID_PROFILE_S_L3; */ + + /* We don't use zones */ + xvid_enc_create.zones = NULL; + xvid_enc_create.num_zones = 0; + + xvid_enc_create.num_threads = avctx->thread_count; + + xvid_enc_create.plugins = plugins; + xvid_enc_create.num_plugins = 0; + + /* Initialize Buffers */ + x->twopassbuffer = NULL; + x->old_twopassbuffer = NULL; + x->twopassfile = NULL; + + if( xvid_flags & CODEC_FLAG_PASS1 ) { + memset(&rc2pass1, 0, sizeof(xvid_ff_pass1_t)); + rc2pass1.version = XVID_VERSION; + rc2pass1.context = x; + x->twopassbuffer = av_malloc(BUFFER_SIZE); + x->old_twopassbuffer = av_malloc(BUFFER_SIZE); + if( x->twopassbuffer == NULL || x->old_twopassbuffer == NULL ) { + av_log(avctx, AV_LOG_ERROR, + "Xvid: Cannot allocate 2-pass log buffers\n"); + return -1; + } + x->twopassbuffer[0] = x->old_twopassbuffer[0] = 0; + + plugins[xvid_enc_create.num_plugins].func = xvid_ff_2pass; + plugins[xvid_enc_create.num_plugins].param = &rc2pass1; + xvid_enc_create.num_plugins++; + } else if( xvid_flags & CODEC_FLAG_PASS2 ) { + memset(&rc2pass2, 0, sizeof(xvid_plugin_2pass2_t)); + rc2pass2.version = XVID_VERSION; + rc2pass2.bitrate = avctx->bit_rate; + + fd = av_tempfile("xvidff.", &(x->twopassfile)); + if( fd == -1 ) { + av_log(avctx, AV_LOG_ERROR, + "Xvid: Cannot write 2-pass pipe\n"); + return -1; + } + + if( avctx->stats_in == NULL ) { + av_log(avctx, AV_LOG_ERROR, + "Xvid: No 2-pass information loaded for second pass\n"); + return -1; + } + + if( strlen(avctx->stats_in) > + write(fd, avctx->stats_in, strlen(avctx->stats_in)) ) { + close(fd); + av_log(avctx, AV_LOG_ERROR, + "Xvid: Cannot write to 2-pass pipe\n"); + return -1; + } + + close(fd); + rc2pass2.filename = x->twopassfile; + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_2pass2; + plugins[xvid_enc_create.num_plugins].param = &rc2pass2; + xvid_enc_create.num_plugins++; + } else if( !(xvid_flags & CODEC_FLAG_QSCALE) ) { + /* Single Pass Bitrate Control! */ + memset(&single, 0, sizeof(xvid_plugin_single_t)); + single.version = XVID_VERSION; + single.bitrate = avctx->bit_rate; + + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_single; + plugins[xvid_enc_create.num_plugins].param = &single; + xvid_enc_create.num_plugins++; + } + + /* Luminance Masking */ + if( 0.0 != avctx->lumi_masking ) { + plugins[xvid_enc_create.num_plugins].func = xvid_plugin_lumimasking; + plugins[xvid_enc_create.num_plugins].param = NULL; + xvid_enc_create.num_plugins++; + } + + /* Frame Rate and Key Frames */ + xvid_correct_framerate(avctx); + xvid_enc_create.fincr = avctx->time_base.num; + xvid_enc_create.fbase = avctx->time_base.den; + if( avctx->gop_size > 0 ) + xvid_enc_create.max_key_interval = avctx->gop_size; + else + xvid_enc_create.max_key_interval = 240; /* Xvid's best default */ + + /* Quants */ + if( xvid_flags & CODEC_FLAG_QSCALE ) x->qscale = 1; + else x->qscale = 0; + + xvid_enc_create.min_quant[0] = avctx->qmin; + xvid_enc_create.min_quant[1] = avctx->qmin; + xvid_enc_create.min_quant[2] = avctx->qmin; + xvid_enc_create.max_quant[0] = avctx->qmax; + xvid_enc_create.max_quant[1] = avctx->qmax; + xvid_enc_create.max_quant[2] = avctx->qmax; + + /* Quant Matrices */ + x->intra_matrix = x->inter_matrix = NULL; + if( avctx->mpeg_quant ) + x->vol_flags |= XVID_VOL_MPEGQUANT; + if( (avctx->intra_matrix || avctx->inter_matrix) ) { + x->vol_flags |= XVID_VOL_MPEGQUANT; + + if( avctx->intra_matrix ) { + intra = avctx->intra_matrix; + x->intra_matrix = av_malloc(sizeof(unsigned char) * 64); + } else + intra = NULL; + if( avctx->inter_matrix ) { + inter = avctx->inter_matrix; + x->inter_matrix = av_malloc(sizeof(unsigned char) * 64); + } else + inter = NULL; + + for( i = 0; i < 64; i++ ) { + if( intra ) + x->intra_matrix[i] = (unsigned char)intra[i]; + if( inter ) + x->inter_matrix[i] = (unsigned char)inter[i]; + } + } + + /* Misc Settings */ + xvid_enc_create.frame_drop_ratio = 0; + xvid_enc_create.global = 0; + if( xvid_flags & CODEC_FLAG_CLOSED_GOP ) + xvid_enc_create.global |= XVID_GLOBAL_CLOSED_GOP; + + /* Determines which codec mode we are operating in */ + avctx->extradata = NULL; + avctx->extradata_size = 0; + if( xvid_flags & CODEC_FLAG_GLOBAL_HEADER ) { + /* In this case, we are claiming to be MPEG4 */ + x->quicktime_format = 1; + avctx->codec_id = CODEC_ID_MPEG4; + } else { + /* We are claiming to be Xvid */ + x->quicktime_format = 0; + if(!avctx->codec_tag) + avctx->codec_tag = ff_get_fourcc("xvid"); + } + + /* Bframes */ + xvid_enc_create.max_bframes = avctx->max_b_frames; + xvid_enc_create.bquant_offset = 100 * avctx->b_quant_offset; + xvid_enc_create.bquant_ratio = 100 * avctx->b_quant_factor; + if( avctx->max_b_frames > 0 && !x->quicktime_format ) xvid_enc_create.global |= XVID_GLOBAL_PACKED; + + /* Create encoder context */ + xerr = xvid_encore(NULL, XVID_ENC_CREATE, &xvid_enc_create, NULL); + if( xerr ) { + av_log(avctx, AV_LOG_ERROR, "Xvid: Could not create encoder reference\n"); + return -1; + } + + x->encoder_handle = xvid_enc_create.handle; + avctx->coded_frame = &x->encoded_picture; + + return 0; +} + +/** + * Encodes a single frame. + * + * @param avctx AVCodecContext pointer to context + * @param frame Pointer to encoded frame buffer + * @param buf_size Size of encoded frame buffer + * @param data Pointer to AVFrame of unencoded frame + * @return Returns 0 on success, -1 on failure + */ +int ff_xvid_encode_frame(AVCodecContext *avctx, + unsigned char *frame, int buf_size, void *data) { + int xerr, i; + char *tmp; + xvid_context_t *x = avctx->priv_data; + AVFrame *picture = data; + AVFrame *p = &(x->encoded_picture); + + xvid_enc_frame_t xvid_enc_frame; + xvid_enc_stats_t xvid_enc_stats; + + /* Start setting up the frame */ + memset(&xvid_enc_frame, 0, sizeof(xvid_enc_frame)); + xvid_enc_frame.version = XVID_VERSION; + memset(&xvid_enc_stats, 0, sizeof(xvid_enc_stats)); + xvid_enc_stats.version = XVID_VERSION; + *p = *picture; + + /* Let Xvid know where to put the frame. */ + xvid_enc_frame.bitstream = frame; + xvid_enc_frame.length = buf_size; + + /* Initialize input image fields */ + if( avctx->pix_fmt != PIX_FMT_YUV420P ) { + av_log(avctx, AV_LOG_ERROR, "Xvid: Color spaces other than 420p not supported\n"); + return -1; + } + + xvid_enc_frame.input.csp = XVID_CSP_PLANAR; /* YUV420P */ + + for( i = 0; i < 4; i++ ) { + xvid_enc_frame.input.plane[i] = picture->data[i]; + xvid_enc_frame.input.stride[i] = picture->linesize[i]; + } + + /* Encoder Flags */ + xvid_enc_frame.vop_flags = x->vop_flags; + xvid_enc_frame.vol_flags = x->vol_flags; + xvid_enc_frame.motion = x->me_flags; + xvid_enc_frame.type = XVID_TYPE_AUTO; + + /* Pixel aspect ratio setting */ + if (avctx->sample_aspect_ratio.num < 1 || avctx->sample_aspect_ratio.num > 255 || + avctx->sample_aspect_ratio.den < 1 || avctx->sample_aspect_ratio.den > 255) { + av_log(avctx, AV_LOG_ERROR, "Invalid pixel aspect ratio %i/%i\n", + avctx->sample_aspect_ratio.num, avctx->sample_aspect_ratio.den); + return -1; + } + xvid_enc_frame.par = XVID_PAR_EXT; + xvid_enc_frame.par_width = avctx->sample_aspect_ratio.num; + xvid_enc_frame.par_height = avctx->sample_aspect_ratio.den; + + /* Quant Setting */ + if( x->qscale ) xvid_enc_frame.quant = picture->quality / FF_QP2LAMBDA; + else xvid_enc_frame.quant = 0; + + /* Matrices */ + xvid_enc_frame.quant_intra_matrix = x->intra_matrix; + xvid_enc_frame.quant_inter_matrix = x->inter_matrix; + + /* Encode */ + xerr = xvid_encore(x->encoder_handle, XVID_ENC_ENCODE, + &xvid_enc_frame, &xvid_enc_stats); + + /* Two-pass log buffer swapping */ + avctx->stats_out = NULL; + if( x->twopassbuffer ) { + tmp = x->old_twopassbuffer; + x->old_twopassbuffer = x->twopassbuffer; + x->twopassbuffer = tmp; + x->twopassbuffer[0] = 0; + if( x->old_twopassbuffer[0] != 0 ) { + avctx->stats_out = x->old_twopassbuffer; + } + } + + if( 0 <= xerr ) { + p->quality = xvid_enc_stats.quant * FF_QP2LAMBDA; + if( xvid_enc_stats.type == XVID_TYPE_PVOP ) + p->pict_type = FF_P_TYPE; + else if( xvid_enc_stats.type == XVID_TYPE_BVOP ) + p->pict_type = FF_B_TYPE; + else if( xvid_enc_stats.type == XVID_TYPE_SVOP ) + p->pict_type = FF_S_TYPE; + else + p->pict_type = FF_I_TYPE; + if( xvid_enc_frame.out_flags & XVID_KEYFRAME ) { + p->key_frame = 1; + if( x->quicktime_format ) + return xvid_strip_vol_header(avctx, frame, + xvid_enc_stats.hlength, xerr); + } else + p->key_frame = 0; + + return xerr; + } else { + av_log(avctx, AV_LOG_ERROR, "Xvid: Encoding Error Occurred: %i\n", xerr); + return -1; + } +} + +/** + * Destroys the private context for the encoder. + * All buffers are freed, and the Xvid encoder context is destroyed. + * + * @param avctx AVCodecContext pointer to context + * @return Returns 0, success guaranteed + */ +av_cold int ff_xvid_encode_close(AVCodecContext *avctx) { + xvid_context_t *x = avctx->priv_data; + + xvid_encore(x->encoder_handle, XVID_ENC_DESTROY, NULL, NULL); + + if( avctx->extradata != NULL ) + av_free(avctx->extradata); + if( x->twopassbuffer != NULL ) { + av_free(x->twopassbuffer); + av_free(x->old_twopassbuffer); + } + if( x->twopassfile != NULL ) + av_free(x->twopassfile); + if( x->intra_matrix != NULL ) + av_free(x->intra_matrix); + if( x->inter_matrix != NULL ) + av_free(x->inter_matrix); + + return 0; +} + +/** + * Routine to create a global VO/VOL header for MP4 container. + * What we do here is extract the header from the Xvid bitstream + * as it is encoded. We also strip the repeated headers from the + * bitstream when a global header is requested for MPEG-4 ISO + * compliance. + * + * @param avctx AVCodecContext pointer to context + * @param frame Pointer to encoded frame data + * @param header_len Length of header to search + * @param frame_len Length of encoded frame data + * @return Returns new length of frame data + */ +int xvid_strip_vol_header(AVCodecContext *avctx, + unsigned char *frame, + unsigned int header_len, + unsigned int frame_len) { + int vo_len = 0, i; + + for( i = 0; i < header_len - 3; i++ ) { + if( frame[i] == 0x00 && + frame[i+1] == 0x00 && + frame[i+2] == 0x01 && + frame[i+3] == 0xB6 ) { + vo_len = i; + break; + } + } + + if( vo_len > 0 ) { + /* We need to store the header, so extract it */ + if( avctx->extradata == NULL ) { + avctx->extradata = av_malloc(vo_len); + memcpy(avctx->extradata, frame, vo_len); + avctx->extradata_size = vo_len; + } + /* Less dangerous now, memmove properly copies the two + chunks of overlapping data */ + memmove(frame, &(frame[vo_len]), frame_len - vo_len); + return frame_len - vo_len; + } else + return frame_len; +} + +/** + * Routine to correct a possibly erroneous framerate being fed to us. + * Xvid currently chokes on framerates where the ticks per frame is + * extremely large. This function works to correct problems in this area + * by estimating a new framerate and taking the simpler fraction of + * the two presented. + * + * @param avctx Context that contains the framerate to correct. + */ +void xvid_correct_framerate(AVCodecContext *avctx) { + int frate, fbase; + int est_frate, est_fbase; + int gcd; + float est_fps, fps; + + frate = avctx->time_base.den; + fbase = avctx->time_base.num; + + gcd = ff_gcd(frate, fbase); + if( gcd > 1 ) { + frate /= gcd; + fbase /= gcd; + } + + if( frate <= 65000 && fbase <= 65000 ) { + avctx->time_base.den = frate; + avctx->time_base.num = fbase; + return; + } + + fps = (float)frate / (float)fbase; + est_fps = roundf(fps * 1000.0) / 1000.0; + + est_frate = (int)est_fps; + if( est_fps > (int)est_fps ) { + est_frate = (est_frate + 1) * 1000; + est_fbase = (int)roundf((float)est_frate / est_fps); + } else + est_fbase = 1; + + gcd = ff_gcd(est_frate, est_fbase); + if( gcd > 1 ) { + est_frate /= gcd; + est_fbase /= gcd; + } + + if( fbase > est_fbase ) { + avctx->time_base.den = est_frate; + avctx->time_base.num = est_fbase; + av_log(avctx, AV_LOG_DEBUG, + "Xvid: framerate re-estimated: %.2f, %.3f%% correction\n", + est_fps, (((est_fps - fps)/fps) * 100.0)); + } else { + avctx->time_base.den = frate; + avctx->time_base.num = fbase; + } +} + +/* + * Xvid 2-Pass Kludge Section + * + * Xvid's default 2-pass doesn't allow us to create data as we need to, so + * this section spends time replacing the first pass plugin so we can write + * statistic information as libavcodec requests in. We have another kludge + * that allows us to pass data to the second pass in Xvid without a custom + * rate-control plugin. + */ + +/** + * Initializes the two-pass plugin and context. + * + * @param param Input construction parameter structure + * @param handle Private context handle + * @return Returns XVID_ERR_xxxx on failure, or 0 on success. + */ +static int xvid_ff_2pass_create(xvid_plg_create_t * param, + void ** handle) { + xvid_ff_pass1_t *x = (xvid_ff_pass1_t *)param->param; + char *log = x->context->twopassbuffer; + + /* Do a quick bounds check */ + if( log == NULL ) + return XVID_ERR_FAIL; + + /* We use snprintf() */ + /* This is because we can safely prevent a buffer overflow */ + log[0] = 0; + snprintf(log, BUFFER_REMAINING(log), + "# ffmpeg 2-pass log file, using xvid codec\n"); + snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log), + "# Do not modify. libxvidcore version: %d.%d.%d\n\n", + XVID_VERSION_MAJOR(XVID_VERSION), + XVID_VERSION_MINOR(XVID_VERSION), + XVID_VERSION_PATCH(XVID_VERSION)); + + *handle = x->context; + return 0; +} + +/** + * Destroys the two-pass plugin context. + * + * @param ref Context pointer for the plugin + * @param param Destrooy context + * @return Returns 0, success guaranteed + */ +static int xvid_ff_2pass_destroy(xvid_context_t *ref, + xvid_plg_destroy_t *param) { + /* Currently cannot think of anything to do on destruction */ + /* Still, the framework should be here for reference/use */ + if( ref->twopassbuffer != NULL ) + ref->twopassbuffer[0] = 0; + return 0; +} + +/** + * Enables fast encode mode during the first pass. + * + * @param ref Context pointer for the plugin + * @param param Frame data + * @return Returns 0, success guaranteed + */ +static int xvid_ff_2pass_before(xvid_context_t *ref, + xvid_plg_data_t *param) { + int motion_remove; + int motion_replacements; + int vop_remove; + + /* Nothing to do here, result is changed too much */ + if( param->zone && param->zone->mode == XVID_ZONE_QUANT ) + return 0; + + /* We can implement a 'turbo' first pass mode here */ + param->quant = 2; + + /* Init values */ + motion_remove = ~XVID_ME_CHROMA_PVOP & + ~XVID_ME_CHROMA_BVOP & + ~XVID_ME_EXTSEARCH16 & + ~XVID_ME_ADVANCEDDIAMOND16; + motion_replacements = XVID_ME_FAST_MODEINTERPOLATE | + XVID_ME_SKIP_DELTASEARCH | + XVID_ME_FASTREFINE16 | + XVID_ME_BFRAME_EARLYSTOP; + vop_remove = ~XVID_VOP_MODEDECISION_RD & + ~XVID_VOP_FAST_MODEDECISION_RD & + ~XVID_VOP_TRELLISQUANT & + ~XVID_VOP_INTER4V & + ~XVID_VOP_HQACPRED; + + param->vol_flags &= ~XVID_VOL_GMC; + param->vop_flags &= vop_remove; + param->motion_flags &= motion_remove; + param->motion_flags |= motion_replacements; + + return 0; +} + +/** + * Captures statistic data and writes it during first pass. + * + * @param ref Context pointer for the plugin + * @param param Statistic data + * @return Returns XVID_ERR_xxxx on failure, or 0 on success + */ +static int xvid_ff_2pass_after(xvid_context_t *ref, + xvid_plg_data_t *param) { + char *log = ref->twopassbuffer; + char *frame_types = " ipbs"; + char frame_type; + + /* Quick bounds check */ + if( log == NULL ) + return XVID_ERR_FAIL; + + /* Convert the type given to us into a character */ + if( param->type < 5 && param->type > 0 ) { + frame_type = frame_types[param->type]; + } else { + return XVID_ERR_FAIL; + } + + snprintf(BUFFER_CAT(log), BUFFER_REMAINING(log), + "%c %d %d %d %d %d %d\n", + frame_type, param->stats.quant, param->stats.kblks, param->stats.mblks, + param->stats.ublks, param->stats.length, param->stats.hlength); + + return 0; +} + +/** + * Dispatch function for our custom plugin. + * This handles the dispatch for the Xvid plugin. It passes data + * on to other functions for actual processing. + * + * @param ref Context pointer for the plugin + * @param cmd The task given for us to complete + * @param p1 First parameter (varies) + * @param p2 Second parameter (varies) + * @return Returns XVID_ERR_xxxx on failure, or 0 on success + */ +int xvid_ff_2pass(void *ref, int cmd, void *p1, void *p2) { + switch( cmd ) { + case XVID_PLG_INFO: + case XVID_PLG_FRAME: + return 0; + + case XVID_PLG_BEFORE: + return xvid_ff_2pass_before(ref, p1); + + case XVID_PLG_CREATE: + return xvid_ff_2pass_create(p1, p2); + + case XVID_PLG_AFTER: + return xvid_ff_2pass_after(ref, p1); + + case XVID_PLG_DESTROY: + return xvid_ff_2pass_destroy(ref, p1); + + default: + return XVID_ERR_FAIL; + } +} + +/** + * Xvid codec definition for libavcodec. + */ +AVCodec libxvid_encoder = { + "libxvid", + CODEC_TYPE_VIDEO, + CODEC_ID_XVID, + sizeof(xvid_context_t), + ff_xvid_encode_init, + ff_xvid_encode_frame, + ff_xvid_encode_close, + .pix_fmts= (enum PixelFormat[]){PIX_FMT_YUV420P, PIX_FMT_NONE}, + .long_name= NULL_IF_CONFIG_SMALL("libxvidcore MPEG-4 part 2"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/ljpegenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/ljpegenc.c new file mode 100644 index 0000000000..7ac013e3fa --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/ljpegenc.c @@ -0,0 +1,198 @@ +/* + * lossless JPEG encoder + * Copyright (c) 2000, 2001 Fabrice Bellard. + * Copyright (c) 2003 Alex Beregszaszi + * Copyright (c) 2003-2004 Michael Niedermayer + * + * Support for external huffman table, various fixes (AVID workaround), + * aspecting, new decode_frame mechanism and apple mjpeg-b support + * by Alex Beregszaszi + * + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +/** + * @file ljpegenc.c + * lossless JPEG encoder. + */ + +#include "avcodec.h" +#include "dsputil.h" +#include "mpegvideo.h" +#include "mjpeg.h" +#include "mjpegenc.h" + + +static int encode_picture_lossless(AVCodecContext *avctx, unsigned char *buf, int buf_size, void *data){ + MpegEncContext * const s = avctx->priv_data; + MJpegContext * const m = s->mjpeg_ctx; + AVFrame *pict = data; + const int width= s->width; + const int height= s->height; + AVFrame * const p= (AVFrame*)&s->current_picture; + const int predictor= avctx->prediction_method+1; + + init_put_bits(&s->pb, buf, buf_size); + + *p = *pict; + p->pict_type= FF_I_TYPE; + p->key_frame= 1; + + ff_mjpeg_encode_picture_header(s); + + s->header_bits= put_bits_count(&s->pb); + + if(avctx->pix_fmt == PIX_FMT_RGB32){ + int x, y, i; + const int linesize= p->linesize[0]; + uint16_t (*buffer)[4]= (void *) s->rd_scratchpad; + int left[3], top[3], topleft[3]; + + for(i=0; i<3; i++){ + buffer[0][i]= 1 << (9 - 1); + } + + for(y = 0; y < height; y++) { + const int modified_predictor= y ? predictor : 1; + uint8_t *ptr = p->data[0] + (linesize * y); + + if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < width*3*4){ + av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + + for(i=0; i<3; i++){ + top[i]= left[i]= topleft[i]= buffer[0][i]; + } + for(x = 0; x < width; x++) { + buffer[x][1] = ptr[4*x+0] - ptr[4*x+1] + 0x100; + buffer[x][2] = ptr[4*x+2] - ptr[4*x+1] + 0x100; + buffer[x][0] = (ptr[4*x+0] + 2*ptr[4*x+1] + ptr[4*x+2])>>2; + + for(i=0;i<3;i++) { + int pred, diff; + + PREDICT(pred, topleft[i], top[i], left[i], modified_predictor); + + topleft[i]= top[i]; + top[i]= buffer[x+1][i]; + + left[i]= buffer[x][i]; + + diff= ((left[i] - pred + 0x100)&0x1FF) - 0x100; + + if(i==0) + ff_mjpeg_encode_dc(s, diff, m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly + else + ff_mjpeg_encode_dc(s, diff, m->huff_size_dc_chrominance, m->huff_code_dc_chrominance); + } + } + } + }else{ + int mb_x, mb_y, i; + const int mb_width = (width + s->mjpeg_hsample[0] - 1) / s->mjpeg_hsample[0]; + const int mb_height = (height + s->mjpeg_vsample[0] - 1) / s->mjpeg_vsample[0]; + + for(mb_y = 0; mb_y < mb_height; mb_y++) { + if(s->pb.buf_end - s->pb.buf - (put_bits_count(&s->pb)>>3) < mb_width * 4 * 3 * s->mjpeg_hsample[0] * s->mjpeg_vsample[0]){ + av_log(s->avctx, AV_LOG_ERROR, "encoded frame too large\n"); + return -1; + } + for(mb_x = 0; mb_x < mb_width; mb_x++) { + if(mb_x==0 || mb_y==0){ + for(i=0;i<3;i++) { + uint8_t *ptr; + int x, y, h, v, linesize; + h = s->mjpeg_hsample[i]; + v = s->mjpeg_vsample[i]; + linesize= p->linesize[i]; + + for(y=0; ydata[i] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap + if(y==0 && mb_y==0){ + if(x==0 && mb_x==0){ + pred= 128; + }else{ + pred= ptr[-1]; + } + }else{ + if(x==0 && mb_x==0){ + pred= ptr[-linesize]; + }else{ + PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor); + } + } + + if(i==0) + ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly + else + ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_chrominance, m->huff_code_dc_chrominance); + } + } + } + }else{ + for(i=0;i<3;i++) { + uint8_t *ptr; + int x, y, h, v, linesize; + h = s->mjpeg_hsample[i]; + v = s->mjpeg_vsample[i]; + linesize= p->linesize[i]; + + for(y=0; ydata[i] + (linesize * (v * mb_y + y)) + (h * mb_x + x); //FIXME optimize this crap +//printf("%d %d %d %d %8X\n", mb_x, mb_y, x, y, ptr); + PREDICT(pred, ptr[-linesize-1], ptr[-linesize], ptr[-1], predictor); + + if(i==0) + ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_luminance, m->huff_code_dc_luminance); //FIXME ugly + else + ff_mjpeg_encode_dc(s, (int8_t)(*ptr - pred), m->huff_size_dc_chrominance, m->huff_code_dc_chrominance); + } + } + } + } + } + } + } + + emms_c(); + + ff_mjpeg_encode_picture_trailer(s); + s->picture_number++; + + flush_put_bits(&s->pb); + return pbBufPtr(&s->pb) - s->pb.buf; +// return (put_bits_count(&f->pb)+7)/8; +} + + +AVCodec ljpeg_encoder = { //FIXME avoid MPV_* lossless JPEG should not need them + "ljpeg", + CODEC_TYPE_VIDEO, + CODEC_ID_LJPEG, + sizeof(MpegEncContext), + MPV_encode_init, + encode_picture_lossless, + MPV_encode_end, + .long_name = NULL_IF_CONFIG_SMALL("Lossless JPEG"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/loco.c b/src/add-ons/media/plugins/avcodec/libavcodec/loco.c new file mode 100644 index 0000000000..ad5737ec5b --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/loco.c @@ -0,0 +1,286 @@ +/* + * LOCO codec + * Copyright (c) 2005 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 + */ + +/** + * @file loco.c + * LOCO codec. + */ + +#include "avcodec.h" +#include "bitstream.h" +#include "golomb.h" + +enum LOCO_MODE {LOCO_UNKN=0, LOCO_CYUY2=-1, LOCO_CRGB=-2, LOCO_CRGBA=-3, LOCO_CYV12=-4, + LOCO_YUY2=1, LOCO_UYVY=2, LOCO_RGB=3, LOCO_RGBA=4, LOCO_YV12=5}; + +typedef struct LOCOContext{ + AVCodecContext *avctx; + AVFrame pic; + int lossy; + int mode; +} LOCOContext; + +typedef struct RICEContext{ + GetBitContext gb; + int save, run, run2; /* internal rice decoder state */ + int sum, count; /* sum and count for getting rice parameter */ + int lossy; +}RICEContext; + +static int loco_get_rice_param(RICEContext *r) +{ + int cnt = 0; + int val = r->count; + + while(r->sum > val && cnt < 9) { + val <<= 1; + cnt++; + } + + return cnt; +} + +static inline void loco_update_rice_param(RICEContext *r, int val) +{ + r->sum += val; + r->count++; + + if(r->count == 16) { + r->sum >>= 1; + r->count >>= 1; + } +} + +static inline int loco_get_rice(RICEContext *r) +{ + int v; + if (r->run > 0) { /* we have zero run */ + r->run--; + loco_update_rice_param(r, 0); + return 0; + } + v = get_ur_golomb_jpegls(&r->gb, loco_get_rice_param(r), INT_MAX, 0); + loco_update_rice_param(r, (v+1)>>1); + if (!v) { + if (r->save >= 0) { + r->run = get_ur_golomb_jpegls(&r->gb, 2, INT_MAX, 0); + if(r->run > 1) + r->save += r->run + 1; + else + r->save -= 3; + } + else + r->run2++; + } else { + v = ((v>>1) + r->lossy) ^ -(v&1); + if (r->run2 > 0) { + if (r->run2 > 2) + r->save += r->run2; + else + r->save -= 3; + r->run2 = 0; + } + } + + return v; +} + +/* LOCO main predictor - LOCO-I/JPEG-LS predictor */ +static inline int loco_predict(uint8_t* data, int stride, int step) +{ + int a, b, c; + + a = data[-stride]; + b = data[-step]; + c = data[-stride - step]; + + return mid_pred(a, a + b - c, b); +} + +static int loco_decode_plane(LOCOContext *l, uint8_t *data, int width, int height, + int stride, const uint8_t *buf, int buf_size, int step) +{ + RICEContext rc; + int val; + int i, j; + + init_get_bits(&rc.gb, buf, buf_size*8); + rc.save = 0; + rc.run = 0; + rc.run2 = 0; + rc.lossy = l->lossy; + + rc.sum = 8; + rc.count = 1; + + /* restore top left pixel */ + val = loco_get_rice(&rc); + data[0] = 128 + val; + /* restore top line */ + for (i = 1; i < width; i++) { + val = loco_get_rice(&rc); + data[i * step] = data[i * step - step] + val; + } + data += stride; + for (j = 1; j < height; j++) { + /* restore left column */ + val = loco_get_rice(&rc); + data[0] = data[-stride] + val; + /* restore all other pixels */ + for (i = 1; i < width; i++) { + val = loco_get_rice(&rc); + data[i * step] = loco_predict(&data[i * step], stride, step) + val; + } + data += stride; + } + + return (get_bits_count(&rc.gb) + 7) >> 3; +} + +static int decode_frame(AVCodecContext *avctx, + void *data, int *data_size, + const uint8_t *buf, int buf_size) +{ + LOCOContext * const l = avctx->priv_data; + AVFrame * const p= (AVFrame*)&l->pic; + int decoded; + + if(p->data[0]) + avctx->release_buffer(avctx, p); + + p->reference = 0; + if(avctx->get_buffer(avctx, p) < 0){ + av_log(avctx, AV_LOG_ERROR, "get_buffer() failed\n"); + return -1; + } + p->key_frame = 1; + + switch(l->mode) { + case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height, + p->linesize[1], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height, + p->linesize[2], buf, buf_size, 1); + break; + case LOCO_CYV12: case LOCO_YV12: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[2], avctx->width / 2, avctx->height / 2, + p->linesize[2], buf, buf_size, 1); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[1], avctx->width / 2, avctx->height / 2, + p->linesize[1], buf, buf_size, 1); + break; + case LOCO_CRGB: case LOCO_RGB: + decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1), avctx->width, avctx->height, + -p->linesize[0], buf, buf_size, 3); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 1, avctx->width, avctx->height, + -p->linesize[0], buf, buf_size, 3); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + p->linesize[0]*(avctx->height-1) + 2, avctx->width, avctx->height, + -p->linesize[0], buf, buf_size, 3); + break; + case LOCO_RGBA: + decoded = loco_decode_plane(l, p->data[0], avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 1, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 2, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + buf += decoded; buf_size -= decoded; + decoded = loco_decode_plane(l, p->data[0] + 3, avctx->width, avctx->height, + p->linesize[0], buf, buf_size, 4); + break; + } + + *data_size = sizeof(AVFrame); + *(AVFrame*)data = l->pic; + + return buf_size; +} + +static av_cold int decode_init(AVCodecContext *avctx){ + LOCOContext * const l = avctx->priv_data; + int version; + + l->avctx = avctx; + if (avctx->extradata_size < 12) { + av_log(avctx, AV_LOG_ERROR, "Extradata size must be >= 12 instead of %i\n", + avctx->extradata_size); + return -1; + } + version = AV_RL32(avctx->extradata); + switch(version) { + case 1: + l->lossy = 0; + break; + case 2: + l->lossy = AV_RL32(avctx->extradata + 8); + break; + default: + l->lossy = AV_RL32(avctx->extradata + 8); + av_log(avctx, AV_LOG_INFO, "This is LOCO codec version %i, please upload file for study\n", version); + } + + l->mode = AV_RL32(avctx->extradata + 4); + switch(l->mode) { + case LOCO_CYUY2: case LOCO_YUY2: case LOCO_UYVY: + avctx->pix_fmt = PIX_FMT_YUV422P; + break; + case LOCO_CRGB: case LOCO_RGB: + avctx->pix_fmt = PIX_FMT_BGR24; + break; + case LOCO_CYV12: case LOCO_YV12: + avctx->pix_fmt = PIX_FMT_YUV420P; + break; + case LOCO_CRGBA: case LOCO_RGBA: + avctx->pix_fmt = PIX_FMT_RGB32; + break; + default: + av_log(avctx, AV_LOG_INFO, "Unknown colorspace, index = %i\n", l->mode); + return -1; + } + if(avctx->debug & FF_DEBUG_PICT_INFO) + av_log(avctx, AV_LOG_INFO, "lossy:%i, version:%i, mode: %i\n", l->lossy, version, l->mode); + + return 0; +} + +AVCodec loco_decoder = { + "loco", + CODEC_TYPE_VIDEO, + CODEC_ID_LOCO, + sizeof(LOCOContext), + decode_init, + NULL, + NULL, + decode_frame, + CODEC_CAP_DR1, + .long_name = NULL_IF_CONFIG_SMALL("LOCO"), +}; diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.c b/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.c new file mode 100644 index 0000000000..7159a1ee02 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.c @@ -0,0 +1,129 @@ +/* + * Lowpass IIR filter + * Copyright (c) 2008 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 + */ + +/** + * @file lowpass.c + * lowpass filter implementation + */ + +#include "lowpass.h" + +/********************** + * TODO: + * support filters with order != 4 + * calculate coefficients for filter instead of taking approximate ones from the table + *********************/ + +/** filter order */ +#define LOWPASS_FILTER_ORDER 4 + +/** + * IIR filter global parameters + */ +typedef struct FFLPFilterCoeffs{ + float gain; + float c[LOWPASS_FILTER_ORDER]; +}FFLPFilterCoeffs; + +/** + * filter data for 4th order IIR lowpass Butterworth filter + */ +static const FFLPFilterCoeffs lp_filter_coeffs[] = { + { 9.398085e-01, { -0.0176648009, 0.0000000000, -0.4860288221, 0.0000000000 } }, + { 6.816645e-01, { -0.4646665999, -2.2127207402, -3.9912017501, -3.2380429984 } }, + { 4.998150e-01, { -0.2498216698, -1.3392807613, -2.7693097862, -2.6386277439 } }, + { 3.103469e-01, { -0.0965076902, -0.5977763360, -1.4972580903, -1.7740085241 } }, + { 2.346995e-01, { -0.0557639007, -0.3623690447, -1.0304538354, -1.3066051440 } }, + { 1.528432e-01, { -0.0261686639, -0.1473794606, -0.6204721225, -0.6514716536 } }, + { 6.917529e-02, { -0.0202414073, 0.0780167640, -0.5277442247, 0.3631641670 } }, + { 6.178391e-02, { -0.0223681543, 0.1069446609, -0.5615167033, 0.4883976841 } }, + { 5.298685e-02, { -0.0261686639, 0.1473794606, -0.6204721225, 0.6514716536 } }, + { 2.229030e-02, { -0.0647354087, 0.4172275190, -1.1412129810, 1.4320761385 } }, + { 1.693903e-02, { -0.0823177861, 0.5192354923, -1.3444768251, 1.6365345642 } }, + { 7.374053e-03, { -0.1481421788, 0.8650973862, -1.9894244796, 2.1544844308 } }, + { 5.541768e-03, { -0.1742301048, 0.9921936565, -2.2090801108, 2.3024482658 } }, +}; + +/** cutoff ratios for lp_filter_data[] */ +static const float lp_cutoff_ratios[] = { + 0.5000000000, 0.4535147392, 0.4166666667, 0.3628117914, + 0.3333333333, 0.2916666667, 0.2267573696, 0.2187500000, + 0.2083333333, 0.1587301587, 0.1458333333, 0.1133786848, + 0.1041666667, +}; + +/** + * IIR filter state + */ +typedef struct FFLPFilterState{ + float x[LOWPASS_FILTER_ORDER]; +}FFLPFilterState; + +const struct FFLPFilterCoeffs* ff_lowpass_filter_init_coeffs(int order, float cutoff_ratio) +{ + int i, size; + + //we can create only order-4 filters with cutoff ratio <= 0.5 for now + if(order != LOWPASS_FILTER_ORDER) return NULL; + + size = sizeof(lp_cutoff_ratios) / sizeof(lp_cutoff_ratios[0]); + if(cutoff_ratio > lp_cutoff_ratios[0]) + return NULL; + for(i = 0; i < size; i++){ + if(cutoff_ratio >= lp_cutoff_ratios[i]) + break; + } + if(i == size) + i = size - 1; + return &lp_filter_coeffs[i]; +} + +struct FFLPFilterState* ff_lowpass_filter_init_state(int order) +{ + if(order != LOWPASS_FILTER_ORDER) return NULL; + return av_mallocz(sizeof(FFLPFilterState)); +} + +#define FILTER(i0, i1, i2, i3) \ + in = *src * c->gain \ + + c->c[0]*s->x[i0] + c->c[1]*s->x[i1] \ + + c->c[2]*s->x[i2] + c->c[3]*s->x[i3]; \ + res = (s->x[i0] + in )*1 \ + + (s->x[i1] + s->x[i3])*4 \ + + s->x[i2] *6; \ + *dst = av_clip_int16(lrintf(res)); \ + s->x[i0] = in; \ + src += sstep; \ + dst += dstep; \ + +void ff_lowpass_filter(const struct FFLPFilterCoeffs *c, struct FFLPFilterState *s, int size, int16_t *src, int sstep, int16_t *dst, int dstep) +{ + int i; + + for(i = 0; i < size; i += 4){ + float in, res; + + FILTER(0, 1, 2, 3); + FILTER(1, 2, 3, 0); + FILTER(2, 3, 0, 1); + FILTER(3, 0, 1, 2); + } +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.h b/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.h new file mode 100644 index 0000000000..6a77907746 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lowpass.h @@ -0,0 +1,83 @@ +/* + * Lowpass IIR filter + * Copyright (c) 2008 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 + */ + +/** + * @file lowpass.h + * lowpass filter interface + */ + +#ifndef FFMPEG_LOWPASS_H +#define FFMPEG_LOWPASS_H + +#include "avcodec.h" + +struct FFLPFilterCoeffs; +struct FFLPFilterState; + +/** + * Initialize filter coefficients. + * + * @param order filter order + * @param cutoff_ratio cutoff to input frequency ratio + * + * @return pointer to filter coefficients structure or NULL if filter cannot be created + */ +const struct FFLPFilterCoeffs* ff_lowpass_filter_init_coeffs(int order, float cutoff_ratio); + +/** + * Create new filter state. + * + * @param order filter order + * + * @return pointer to new filter state or NULL if state creation fails + */ +struct FFLPFilterState* ff_lowpass_filter_init_state(int order); + +#if 0 //enable with arbitrary order filter implementation, use av_free() for filter state only for now +/** + * Free filter coefficients. + * + * @param coeffs pointer allocated with ff_lowpass_filter_init_coeffs() + */ +void ff_lowpass_filter_free_coeffs(struct FFLPFilterCoeffs *coeffs); + +/** + * Free filter state. + * + * @param state pointer allocated with ff_lowpass_filter_init_state() + */ +void ff_lowpass_filter_free_state(struct FFLPFilterState *state); +#endif + +/** + * Perform lowpass filtering on input samples. + * + * @param coeffs pointer to filter coefficients + * @param state pointer to filter state + * @param size input length + * @param src source samples + * @param sstep source stride + * @param dst filtered samples (destination may be the same as input) + * @param dstep destination stride + */ +void ff_lowpass_filter(const struct FFLPFilterCoeffs *coeffs, struct FFLPFilterState *state, int size, int16_t *src, int sstep, int16_t *dst, int dstep); + +#endif /* FFMPEG_LOWPASS_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lpc.c b/src/add-ons/media/plugins/avcodec/libavcodec/lpc.c new file mode 100644 index 0000000000..4f3a07ba3b --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lpc.c @@ -0,0 +1,205 @@ +/** + * LPC utility code + * Copyright (c) 2006 Justin Ruggles + * + * 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 "lls.h" +#include "dsputil.h" +#include "lpc.h" + + +/** + * Levinson-Durbin recursion. + * Produces LPC coefficients from autocorrelation data. + */ +static void compute_lpc_coefs(const double *autoc, int max_order, + double lpc[][MAX_LPC_ORDER], double *ref) +{ + int i, j, i2; + double r, err, tmp; + double lpc_tmp[MAX_LPC_ORDER]; + + for(i=0; i> 1); + lpc_tmp[i] = r; + for(j=0; j qmax) && (sh > 0)) { + sh--; + } + + /* since negative shift values are unsupported in decoder, scale down + coefficients instead */ + if(sh == 0 && cmax > qmax) { + double scale = ((double)qmax) / cmax; + for(i=0; i=min_order-1; i--) { + if(ref[i] > 0.10) { + est = i+1; + break; + } + } + return est; +} + +/** + * Calculate LPC coefficients for multiple orders + */ +int ff_lpc_calc_coefs(DSPContext *s, + const int32_t *samples, int blocksize, int min_order, + int max_order, int precision, + int32_t coefs[][MAX_LPC_ORDER], int *shift, int use_lpc, + int omethod, int max_shift, int zero_shift) +{ + double autoc[MAX_LPC_ORDER+1]; + double ref[MAX_LPC_ORDER]; + double lpc[MAX_LPC_ORDER][MAX_LPC_ORDER]; + int i, j, pass; + int opt_order; + + assert(max_order >= MIN_LPC_ORDER && max_order <= MAX_LPC_ORDER); + + if(use_lpc == 1){ + s->flac_compute_autocorr(samples, blocksize, max_order, autoc); + + compute_lpc_coefs(autoc, max_order, lpc, ref); + }else{ + LLSModel m[2]; + double var[MAX_LPC_ORDER+1], weight; + + for(pass=0; pass>pass) + fabs(eval - var[0]); + inv = 1/eval; + rinv = sqrt(inv); + for(j=0; j<=max_order; j++) + var[j] *= rinv; + weight += inv; + }else + weight++; + + av_update_lls(&m[pass&1], var, 1.0); + } + av_solve_lls(&m[pass&1], 0.001, 0); + } + + for(i=0; i0; i--) + ref[i] = ref[i-1] - ref[i]; + } + opt_order = max_order; + + if(omethod == ORDER_METHOD_EST) { + opt_order = estimate_best_order(ref, min_order, max_order); + i = opt_order-1; + quantize_lpc_coefs(lpc[i], i+1, precision, coefs[i], &shift[i], max_shift, zero_shift); + } else { + for(i=min_order-1; i + * + * 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 FFMPEG_LPC_H +#define FFMPEG_LPC_H + +#include +#include "dsputil.h" + +#define ORDER_METHOD_EST 0 +#define ORDER_METHOD_2LEVEL 1 +#define ORDER_METHOD_4LEVEL 2 +#define ORDER_METHOD_8LEVEL 3 +#define ORDER_METHOD_SEARCH 4 +#define ORDER_METHOD_LOG 5 + +#define MIN_LPC_ORDER 1 +#define MAX_LPC_ORDER 32 + + +/** + * Calculate LPC coefficients for multiple orders + */ +int ff_lpc_calc_coefs(DSPContext *s, + const int32_t *samples, int blocksize, int min_order, + int max_order, int precision, + int32_t coefs[][MAX_LPC_ORDER], int *shift, int use_lpc, + int omethod, int max_shift, int zero_shift); + +#endif /* FFMPEG_LPC_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lsp.c b/src/add-ons/media/plugins/avcodec/libavcodec/lsp.c new file mode 100644 index 0000000000..e1b1d4139d --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lsp.c @@ -0,0 +1,120 @@ +/* + * LSP routines for ACELP-based codecs + * + * Copyright (c) 2008 Vladimir Voroshilov + * + * 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 + +#include "avcodec.h" +#define FRAC_BITS 14 +#include "mathops.h" +#include "lsp.h" +#include "acelp_math.h" + +void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max, int lp_order) +{ + int i, j; + + /* sort lsfq in ascending order. float bubble agorithm, + O(n) if data already sorted, O(n^2) - otherwise */ + for(i=0; i=0 && lsfq[j] > lsfq[j+1]; j--) + FFSWAP(int16_t, lsfq[j], lsfq[j+1]); + + for(i=0; i> 15); // divide by PI and (0,13) -> (0,14) +} + +/** + * \brief decodes polynomial coefficients from LSP + * \param f [out] decoded polynomial coefficients (-0x20000000 <= (3.22) <= 0x1fffffff) + * \param lsp LSP coefficients (-0x8000 <= (0.15) <= 0x7fff) + */ +static void lsp2poly(int* f, const int16_t* lsp, int lp_half_order) +{ + int i, j; + + f[0] = 0x400000; // 1.0 in (3.22) + f[1] = -lsp[0] << 8; // *2 and (0.15) -> (3.22) + + for(i=2; i<=lp_half_order; i++) + { + f[i] = f[i-2]; + for(j=i; j>1; j--) + f[j] -= MULL(f[j-1], lsp[2*i-2]) - f[j-2]; // (3.22) * (0.15) * 2 -> (3.22) + + f[1] -= lsp[2*i-2] << 8; + } +} + +void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order) +{ + int i; + int f1[lp_half_order+1]; // (3.22) + int f2[lp_half_order+1]; // (3.22) + + lsp2poly(f1, lsp , lp_half_order); + lsp2poly(f2, lsp+1, lp_half_order); + + /* 3.2.6 of G.729, Equations 25 and 26*/ + lp[0] = 4096; + for(i=1; i> 11; // divide by 2 and (3.22) -> (3.12) + lp[(lp_half_order << 1) + 1 - i] = (ff1 - ff2) >> 11; // divide by 2 and (3.22) -> (3.12) + } +} + +void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev, int lp_order) +{ + int16_t lsp_1st[lp_order]; // (0.15) + int i; + + /* LSP values for first subframe (3.2.5 of G.729, Equation 24)*/ + for(i=0; i> 1) + (lsp_prev[i] >> 1); +#else + lsp_1st[i] = (lsp_2nd[i] + lsp_prev[i]) >> 1; +#endif + + ff_acelp_lsp2lpc(lp_1st, lsp_1st, lp_order >> 1); + + /* LSP values for second subframe (3.2.5 of G.729)*/ + ff_acelp_lsp2lpc(lp_2nd, lsp_2nd, lp_order >> 1); +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lsp.h b/src/add-ons/media/plugins/avcodec/libavcodec/lsp.h new file mode 100644 index 0000000000..d4bc4957db --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lsp.h @@ -0,0 +1,70 @@ +/* + * LSP computing for ACELP-based codecs + * + * Copyright (c) 2008 Vladimir Voroshilov + * + * 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 FFMPEG_LSP_H +#define FFMPEG_LSP_H + +#include + +/** + (I.F) means fixed-point value with F fractional and I integer bits +*/ + +/** + * \brief ensure a minimum distance between LSFs + * \param lsfq [in/out] LSF to check and adjust + * \param lsfq_min_distance minimum distance between LSFs + * \param lsfq_min minimum allowed LSF value + * \param lsfq_max maximum allowed LSF value + * \param lp_order LP filter order + */ +void ff_acelp_reorder_lsf(int16_t* lsfq, int lsfq_min_distance, int lsfq_min, int lsfq_max, int lp_order); + +/** + * \brief Convert LSF to LSP + * \param lsp [out] LSP coefficients (-0x8000 <= (0.15) < 0x8000) + * \param lsf normalized LSF coefficients (0 <= (2.13) < 0x2000 * PI) + * \param lp_order LP filter order + * + * \remark It is safe to pass the same array into the lsf and lsp parameters. + */ +void ff_acelp_lsf2lsp(int16_t *lsp, const int16_t *lsf, int lp_order); + +/** + * \brief LSP to LP conversion (3.2.6 of G.729) + * \param lp [out] decoded LP coefficients (-0x8000 <= (3.12) < 0x8000) + * \param lsp LSP coefficients (-0x8000 <= (0.15) < 0x8000) + * \param lp_half_order LP filter order, divided by 2 + */ +void ff_acelp_lsp2lpc(int16_t* lp, const int16_t* lsp, int lp_half_order); + +/** + * \brief Interpolate LSP for the first subframe and convert LSP -> LP for both subframes (3.2.5 and 3.2.6 of G.729) + * \param lp_1st [out] decoded LP coefficients for first subframe (-0x8000 <= (3.12) < 0x8000) + * \param lp_2nd [out] decoded LP coefficients for second subframe (-0x8000 <= (3.12) < 0x8000) + * \param lsp_2nd LSP coefficients of the second subframe (-0x8000 <= (0.15) < 0x8000) + * \param lsp_prev LSP coefficients from the second subframe of the previous frame (-0x8000 <= (0.15) < 0x8000) + * \param lp_order LP filter order + */ +void ff_acelp_lp_decode(int16_t* lp_1st, int16_t* lp_2nd, const int16_t* lsp_2nd, const int16_t* lsp_prev, int lp_order); + +#endif /* FFMPEG_LSP_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lzw.c b/src/add-ons/media/plugins/avcodec/libavcodec/lzw.c new file mode 100644 index 0000000000..7bdc89a37c --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lzw.c @@ -0,0 +1,229 @@ +/* + * LZW decoder + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2006 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 + */ + +/** + * @file lzw.c + * @brief LZW decoding routines + * @author Fabrice Bellard + * Modified for use in TIFF by Konstantin Shishkov + */ + +#include "avcodec.h" +#include "lzw.h" + +#define LZW_MAXBITS 12 +#define LZW_SIZTABLE (1<mode == FF_LZW_GIF) { + while (s->bbits < s->cursize) { + if (!s->bs) { + s->bs = *s->pbuf++; + } + s->bbuf |= (*s->pbuf++) << s->bbits; + s->bbits += 8; + s->bs--; + } + c = s->bbuf; + s->bbuf >>= s->cursize; + } else { // TIFF + while (s->bbits < s->cursize) { + s->bbuf = (s->bbuf << 8) | (*s->pbuf++); + s->bbits += 8; + } + c = s->bbuf >> (s->bbits - s->cursize); + } + s->bbits -= s->cursize; + return c & s->curmask; +} + +const uint8_t* ff_lzw_cur_ptr(LZWState *p) +{ + return ((struct LZWState*)p)->pbuf; +} + +void ff_lzw_decode_tail(LZWState *p) +{ + struct LZWState *s = (struct LZWState *)p; + + if(s->mode == FF_LZW_GIF) { + while(s->pbuf < s->ebuf && s->bs>0){ + s->pbuf += s->bs; + s->bs = *s->pbuf++; + } + }else + s->pbuf= s->ebuf; +} + +av_cold void ff_lzw_decode_open(LZWState **p) +{ + *p = av_mallocz(sizeof(struct LZWState)); +} + +av_cold void ff_lzw_decode_close(LZWState **p) +{ + av_freep(p); +} + +/** + * Initialize LZW decoder + * @param s LZW context + * @param csize initial code size in bits + * @param buf input data + * @param buf_size input data size + * @param mode decoder working mode - either GIF or TIFF + */ +int ff_lzw_decode_init(LZWState *p, int csize, const uint8_t *buf, int buf_size, int mode) +{ + struct LZWState *s = (struct LZWState *)p; + + if(csize < 1 || csize >= LZW_MAXBITS) + return -1; + /* read buffer */ + s->pbuf = buf; + s->ebuf = s->pbuf + buf_size; + s->bbuf = 0; + s->bbits = 0; + s->bs = 0; + + /* decoder */ + s->codesize = csize; + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->top_slot = 1 << s->cursize; + s->clear_code = 1 << s->codesize; + s->end_code = s->clear_code + 1; + s->slot = s->newcodes = s->clear_code + 2; + s->oc = s->fc = -1; + s->sp = s->stack; + + s->mode = mode; + s->extra_slot = s->mode == FF_LZW_TIFF; + return 0; +} + +/** + * Decode given number of bytes + * NOTE: the algorithm here is inspired from the LZW GIF decoder + * written by Steven A. Bennett in 1987. + * + * @param s LZW context + * @param buf output buffer + * @param len number of bytes to decode + * @return number of bytes decoded + */ +int ff_lzw_decode(LZWState *p, uint8_t *buf, int len){ + int l, c, code, oc, fc; + uint8_t *sp; + struct LZWState *s = (struct LZWState *)p; + + if (s->end_code < 0) + return 0; + + l = len; + sp = s->sp; + oc = s->oc; + fc = s->fc; + + for (;;) { + while (sp > s->stack) { + *buf++ = *(--sp); + if ((--l) == 0) + goto the_end; + } + c = lzw_get_code(s); + if (c == s->end_code) { + break; + } else if (c == s->clear_code) { + s->cursize = s->codesize + 1; + s->curmask = mask[s->cursize]; + s->slot = s->newcodes; + s->top_slot = 1 << s->cursize; + fc= oc= -1; + } else { + code = c; + if (code == s->slot && fc>=0) { + *sp++ = fc; + code = oc; + }else if(code >= s->slot) + break; + while (code >= s->newcodes) { + *sp++ = s->suffix[code]; + code = s->prefix[code]; + } + *sp++ = code; + if (s->slot < s->top_slot && oc>=0) { + s->suffix[s->slot] = code; + s->prefix[s->slot++] = oc; + } + fc = code; + oc = c; + if (s->slot >= s->top_slot - s->extra_slot) { + if (s->cursize < LZW_MAXBITS) { + s->top_slot <<= 1; + s->curmask = mask[++s->cursize]; + } + } + } + } + s->end_code = -1; + the_end: + s->sp = sp; + s->oc = oc; + s->fc = fc; + return len - l; +} diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lzw.h b/src/add-ons/media/plugins/avcodec/libavcodec/lzw.h new file mode 100644 index 0000000000..161f0dce56 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lzw.h @@ -0,0 +1,59 @@ +/* + * LZW decoder + * Copyright (c) 2003 Fabrice Bellard. + * Copyright (c) 2006 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 + */ + +/** + * @file lzw.h + * @brief LZW decoding routines + * @author Fabrice Bellard + * Modified for use in TIFF by Konstantin Shishkov + */ + +#ifndef FFMPEG_LZW_H +#define FFMPEG_LZW_H + +#include "bitstream.h" + +enum FF_LZW_MODES{ + FF_LZW_GIF, + FF_LZW_TIFF +}; + +/* clients should not know what LZWState is */ +typedef void LZWState; + +/* first two functions de/allocate memory for LZWState */ +void ff_lzw_decode_open(LZWState **p); +void ff_lzw_decode_close(LZWState **p); +int ff_lzw_decode_init(LZWState *s, int csize, const uint8_t *buf, int buf_size, int mode); +int ff_lzw_decode(LZWState *s, uint8_t *buf, int len); +const uint8_t* ff_lzw_cur_ptr(LZWState *lzw); +void ff_lzw_decode_tail(LZWState *lzw); + +/** LZW encode state */ +struct LZWEncodeState; +extern const int ff_lzw_encode_state_size; + +void ff_lzw_encode_init(struct LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits); +int ff_lzw_encode(struct LZWEncodeState * s, const uint8_t * inbuf, int insize); +int ff_lzw_encode_flush(struct LZWEncodeState * s); + +#endif /* FFMPEG_LZW_H */ diff --git a/src/add-ons/media/plugins/avcodec/libavcodec/lzwenc.c b/src/add-ons/media/plugins/avcodec/libavcodec/lzwenc.c new file mode 100644 index 0000000000..3a24af3471 --- /dev/null +++ b/src/add-ons/media/plugins/avcodec/libavcodec/lzwenc.c @@ -0,0 +1,262 @@ +/* + * LZW encoder + * Copyright (c) 2007 Bartlomiej Wolowiec + * + * 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 + */ + +/** + * LZW encoder + * @file lzwenc.c + * @author Bartlomiej Wolowiec + */ + +#include "avcodec.h" +#include "bitstream.h" +#include "lzw.h" + +#define LZW_MAXBITS 12 +#define LZW_SIZTABLE (1<= LZW_HASH_SIZE) + head -= LZW_HASH_SIZE; + assert(head >= 0 && head < LZW_HASH_SIZE); + return head; +} + +/** + * Hash function calculates next hash value + * @param head Actual hash code + * @param offset Offset calculated by hashOffset + * @return New hash value + */ +static inline int hashNext(int head, const int offset) +{ + head -= offset; + if(head < 0) + head += LZW_HASH_SIZE; + return head; +} + +/** + * Hash function calculates hash offset + * @param head Actual hash code + * @return Hash offset + */ +static inline int hashOffset(const int head) +{ + return head ? LZW_HASH_SIZE - head : 1; +} + +/** + * Write one code to stream + * @param s LZW state + * @param c code to write + */ +static inline void writeCode(LZWEncodeState * s, int c) +{ + assert(0 <= c && c < 1 << s->bits); + put_bits(&s->pb, s->bits, c); +} + + +/** + * Find LZW code for block + * @param s LZW state + * @param c Last character in block + * @param hash_prefix LZW code for prefix + * @return LZW code for block or -1 if not found in table + */ +static inline int findCode(LZWEncodeState * s, uint8_t c, int hash_prefix) +{ + int h = hash(FFMAX(hash_prefix, 0), c); + int hash_offset = hashOffset(h); + + while (s->tab[h].hash_prefix != LZW_PREFIX_FREE) { + if ((s->tab[h].suffix == c) + && (s->tab[h].hash_prefix == hash_prefix)) + return h; + h = hashNext(h, hash_offset); + } + + return h; +} + +/** + * Add block to LZW code table + * @param s LZW state + * @param c Last character in block + * @param hash_prefix LZW code for prefix + * @param hash_code LZW code for bytes block + */ +static inline void addCode(LZWEncodeState * s, uint8_t c, int hash_prefix, int hash_code) +{ + s->tab[hash_code].code = s->tabsize; + s->tab[hash_code].suffix = c; + s->tab[hash_code].hash_prefix = hash_prefix; + + s->tabsize++; + + if (s->tabsize >= 1 << s->bits) + s->bits++; +} + +/** + * Clear LZW code table + * @param s LZW state + */ +static void clearTable(LZWEncodeState * s) +{ + int i, h; + + writeCode(s, s->clear_code); + s->bits = 9; + for (i = 0; i < LZW_HASH_SIZE; i++) { + s->tab[i].hash_prefix = LZW_PREFIX_FREE; + } + for (i = 0; i < 256; i++) { + h = hash(0, i); + s->tab[h].code = i; + s->tab[h].suffix = i; + s->tab[h].hash_prefix = LZW_PREFIX_EMPTY; + } + s->tabsize = 258; +} + +/** + * Calculate number of bytes written + * @param s LZW encode state + * @return Number of bytes written + */ +static int writtenBytes(LZWEncodeState *s){ + int ret = put_bits_count(&s->pb) >> 3; + ret -= s->output_bytes; + s->output_bytes += ret; + return ret; +} + +/** + * Initialize LZW encoder. Please set s->clear_code, s->end_code and s->maxbits before run. + * @param s LZW state + * @param outbuf Output buffer + * @param outsize Size of output buffer + * @param maxbits Maximum length of code + */ +void ff_lzw_encode_init(LZWEncodeState * s, uint8_t * outbuf, int outsize, int maxbits) +{ + s->clear_code = 256; + s->end_code = 257; + s->maxbits = maxbits; + init_put_bits(&s->pb, outbuf, outsize); + s->bufsize = outsize; + assert(9 <= s->maxbits && s->maxbits <= s->maxbits); + s->maxcode = 1 << s->maxbits; + s->output_bytes = 0; + s->last_code = LZW_PREFIX_EMPTY; + s->bits = 9; +} + +/** + * LZW main compress function + * @param s LZW state + * @param inbuf Input buffer + * @param insize Size of input buffer + * @return Number of bytes written or -1 on error + */ +int ff_lzw_encode(LZWEncodeState * s, const uint8_t * inbuf, int insize) +{ + int i; + + if(insize * 3 > (s->bufsize - s->output_bytes) * 2){ + return -1; + } + + if (s->last_code == LZW_PREFIX_EMPTY) + clearTable(s); + + for (i = 0; i < insize; i++) { + uint8_t c = *inbuf++; + int code = findCode(s, c, s->last_code); + if (s->tab[code].hash_prefix == LZW_PREFIX_FREE) { + writeCode(s, s->last_code); + addCode(s, c, s->last_code, code); + code= hash(0, c); + } + s->last_code = s->tab[code].code; + if (s->tabsize >= s->maxcode - 1) { + clearTable(s); + } + } + + return writtenBytes(s); +} + +/** + * Write end code and flush bitstream + * @param s LZW state + * @return Number of bytes written or -1 on error + */ +int ff_lzw_encode_flush(LZWEncodeState * s) +{ + if (s->last_code != -1) + writeCode(s, s->last_code); + writeCode(s, s->end_code); + flush_put_bits(&s->pb); + s->last_code = -1; + + return writtenBytes(s); +}