From: Shaun Ren sren@codeweavers.com
The decoder logic is based on the indeo5 codec in FFmpeg.
15-bit RGB is used by games such as Zwei: The Arges Adventure. --- configure | 29 + configure.ac | 2 + dlls/ir50_32/Makefile.in | 3 +- dlls/ir50_32/ir50.c | 241 ++++- dlls/ir50_32/ir50_compat.h | 27 - libs/ffmpegindeo/COPYING | 502 ++++++++++ libs/ffmpegindeo/Makefile.in | 7 + libs/ffmpegindeo/get_bits.h | 443 +++++++++ libs/ffmpegindeo/indeo5.c | 825 ++++++++++++++++ libs/ffmpegindeo/indeo5.h | 9 + libs/ffmpegindeo/indeo_compat.h | 96 ++ libs/ffmpegindeo/ivi.c | 1572 +++++++++++++++++++++++++++++++ libs/ffmpegindeo/ivi.h | 321 +++++++ libs/ffmpegindeo/ivi_dsp.c | 551 +++++++++++ libs/ffmpegindeo/ivi_dsp.h | 244 +++++ libs/ffmpegindeo/vlc.c | 353 +++++++ libs/ffmpegindeo/vlc.h | 69 ++ 17 files changed, 5258 insertions(+), 36 deletions(-) delete mode 100644 dlls/ir50_32/ir50_compat.h create mode 100644 libs/ffmpegindeo/COPYING create mode 100644 libs/ffmpegindeo/Makefile.in create mode 100644 libs/ffmpegindeo/get_bits.h create mode 100644 libs/ffmpegindeo/indeo5.c create mode 100644 libs/ffmpegindeo/indeo5.h create mode 100644 libs/ffmpegindeo/indeo_compat.h create mode 100644 libs/ffmpegindeo/ivi.c create mode 100644 libs/ffmpegindeo/ivi.h create mode 100644 libs/ffmpegindeo/ivi_dsp.c create mode 100644 libs/ffmpegindeo/ivi_dsp.h create mode 100644 libs/ffmpegindeo/vlc.c create mode 100644 libs/ffmpegindeo/vlc.h
diff --git a/configure b/configure index b5d69827ce3..5db1191d611 100755 --- a/configure +++ b/configure @@ -731,6 +731,8 @@ JPEG_PE_LIBS JPEG_PE_CFLAGS GSM_PE_LIBS GSM_PE_CFLAGS +FFMPEGINDEO_PE_LIBS +FFMPEGINDEO_PE_CFLAGS FAUDIO_PE_LIBS FAUDIO_PE_CFLAGS MINGW_PKG_CONFIG @@ -1558,6 +1560,7 @@ enable_dxerr8 enable_dxerr9 enable_dxguid enable_faudio +enable_ffmpegindeo enable_gsm enable_jpeg enable_jxr @@ -1709,6 +1712,8 @@ OBJC OBJCFLAGS FAUDIO_PE_CFLAGS FAUDIO_PE_LIBS +FFMPEGINDEO_PE_CFLAGS +FFMPEGINDEO_PE_LIBS GSM_PE_CFLAGS GSM_PE_LIBS JPEG_PE_CFLAGS @@ -2485,6 +2490,12 @@ Some influential environment variables: version FAUDIO_PE_LIBS Linker flags for the PE faudio, overriding the bundled version + FFMPEGINDEO_PE_CFLAGS + C compiler flags for the PE ffmpegindeo, overriding the bundled + version + FFMPEGINDEO_PE_LIBS + Linker flags for the PE ffmpegindeo, overriding the bundled + version GSM_PE_CFLAGS C compiler flags for the PE gsm, overriding the bundled version GSM_PE_LIBS Linker flags for the PE gsm, overriding the bundled version @@ -13369,6 +13380,21 @@ fi printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio cflags: $FAUDIO_PE_CFLAGS" >&5 printf "%s\n" "$as_me:${as_lineno-$LINENO}: faudio libs: $FAUDIO_PE_LIBS" >&5
+if ${FFMPEGINDEO_PE_LIBS:+false} : +then : + FFMPEGINDEO_PE_LIBS=ffmpegindeo + if ${FFMPEGINDEO_PE_CFLAGS:+false} : +then : + FFMPEGINDEO_PE_CFLAGS="-I$(top_srcdir)/libs/ffmpegindeo" +else $as_nop + enable_ffmpegindeo=no +fi +else $as_nop + enable_ffmpegindeo=no +fi +printf "%s\n" "$as_me:${as_lineno-$LINENO}: ffmpegindeo cflags: $FFMPEGINDEO_PE_CFLAGS" >&5 +printf "%s\n" "$as_me:${as_lineno-$LINENO}: ffmpegindeo libs: $FFMPEGINDEO_PE_LIBS" >&5 + if ${GSM_PE_LIBS:+false} : then : GSM_PE_LIBS=gsm @@ -22252,6 +22278,7 @@ wine_fn_config_makefile libs/dxerr8 enable_dxerr8 wine_fn_config_makefile libs/dxerr9 enable_dxerr9 wine_fn_config_makefile libs/dxguid enable_dxguid wine_fn_config_makefile libs/faudio enable_faudio +wine_fn_config_makefile libs/ffmpegindeo enable_ffmpegindeo wine_fn_config_makefile libs/gsm enable_gsm wine_fn_config_makefile libs/jpeg enable_jpeg wine_fn_config_makefile libs/jxr enable_jxr @@ -23403,6 +23430,8 @@ PE_ARCHS = $PE_ARCHS MINGW_PKG_CONFIG = $MINGW_PKG_CONFIG FAUDIO_PE_CFLAGS = $FAUDIO_PE_CFLAGS FAUDIO_PE_LIBS = $FAUDIO_PE_LIBS +FFMPEGINDEO_PE_CFLAGS = $FFMPEGINDEO_PE_CFLAGS +FFMPEGINDEO_PE_LIBS = $FFMPEGINDEO_PE_LIBS GSM_PE_CFLAGS = $GSM_PE_CFLAGS GSM_PE_LIBS = $GSM_PE_LIBS JPEG_PE_CFLAGS = $JPEG_PE_CFLAGS diff --git a/configure.ac b/configure.ac index b240c273dec..384e9aeb16a 100644 --- a/configure.ac +++ b/configure.ac @@ -1187,6 +1187,7 @@ then fi
WINE_EXTLIB_FLAGS(FAUDIO, faudio, "faudio mfplat mfreadwrite mfuuid propsys", "-I$(top_srcdir)/libs/faudio/include") +WINE_EXTLIB_FLAGS(FFMPEGINDEO, ffmpegindeo, ffmpegindeo, "-I$(top_srcdir)/libs/ffmpegindeo") WINE_EXTLIB_FLAGS(GSM, gsm, gsm, "-I$(top_srcdir)/libs/gsm/inc") WINE_EXTLIB_FLAGS(JPEG, jpeg, jpeg, "-I$(top_srcdir)/libs/jpeg") WINE_EXTLIB_FLAGS(JXR, jxr, jxr, "-I$(top_srcdir)/libs/jxr/jxrgluelib -I$(top_srcdir)/libs/jxr/image/sys") @@ -3344,6 +3345,7 @@ WINE_CONFIG_MAKEFILE(libs/dxerr8) WINE_CONFIG_MAKEFILE(libs/dxerr9) WINE_CONFIG_MAKEFILE(libs/dxguid) WINE_CONFIG_MAKEFILE(libs/faudio) +WINE_CONFIG_MAKEFILE(libs/ffmpegindeo) WINE_CONFIG_MAKEFILE(libs/gsm) WINE_CONFIG_MAKEFILE(libs/jpeg) WINE_CONFIG_MAKEFILE(libs/jxr) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 2b04f338317..4e7fa0dcfeb 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -1,6 +1,7 @@ EXTRADEFS = -DWINE_NO_LONG_TYPES MODULE = ir50_32.dll -IMPORTS = user32 +IMPORTS = $(FFMPEGINDEO_PE_LIBS) user32 +EXTRAINCL = $(FFMPEGINDEO_PE_CFLAGS)
C_SRCS = \ ir50.c diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index bb589e66ff7..39d74abebe4 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -20,6 +20,9 @@
#include <stdarg.h> #include <stdlib.h> + +#include <indeo5.h> + #include "windef.h" #include "winbase.h" #include "wingdi.h" @@ -28,7 +31,6 @@ #include "vfw.h" #include "mmsystem.h" #include "ir50_private.h" -#include "ir50_compat.h"
#include "wine/debug.h"
@@ -37,6 +39,157 @@ WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); static HINSTANCE IR50_32_hModule;
#define IV50_MAGIC mmioFOURCC('I', 'V', '5', '0') +#define compare_fourcc(fcc1, fcc2) (((fcc1)^(fcc2))&~0x20202020) + + +static void decode_close( AVCodecContext *avctx ) +{ + ff_ivi_decode_close( avctx ); + free( avctx->out_buf ); + free( avctx->dither_buf ); + memset( avctx, 0, sizeof(*avctx) ); +} + +static LRESULT decode_init( AVCodecContext *avctx ) +{ + int result; + + if ( (result = indeo5_decode_init( avctx )) ) + return result; + + if ( avctx->out_bitcount == 16 ) + { + if ( !(avctx->out_buf = malloc( 3 * avctx->width * avctx->height )) || + !(avctx->dither_buf = malloc( 3 * (avctx->width + 1) * (avctx->height + 1) )) ) + { + decode_close( avctx ); + return ICERR_MEMORY; + } + } + + return ICERR_OK; +} + + +static av_always_inline unsigned bilerp( + unsigned y00, unsigned y10, unsigned y01, unsigned y11, unsigned ioff, unsigned joff ) +{ + unsigned rioff = 4 - ioff, rjoff = 4 - joff; + return (y00 * rioff * rjoff + y10 * ioff * rjoff + y01 * rioff * joff + y11 * ioff * joff) >> 4; +} + +static void yuv410p_to_bgr24( AVFrame *frame, uint8_t *out ) +{ + const uint8_t *y_data = frame->data[0]; + const uint8_t *cb_data = frame->data[1]; + const uint8_t *cr_data = frame->data[2]; + + unsigned w_cr = (frame->width + 3) / 4; + unsigned h_cr = (frame->height + 3) / 4; + + int i, j; + + out += 3 * (frame->height - 1) * frame->width; + + for ( j = 0; j < frame->height; j++ ) + { + for ( i = 0; i < frame->width; i++ ) + { + int c_x0 = (i-2) / 4, c_y0 = (j-2) / 4; + unsigned ioff = i - (4*c_x0 + 2), joff = j - (4*c_y0 + 2); + + unsigned ix00 = FFMAX(c_y0, 0) * w_cr + FFMAX(c_x0, 0); + unsigned ix10 = FFMAX(c_y0, 0) * w_cr + FFMIN(c_x0 + 1, w_cr - 1); + unsigned ix01 = FFMIN(c_y0 + 1, h_cr - 1) * w_cr + FFMAX(c_x0, 0); + unsigned ix11 = FFMIN(c_y0 + 1, h_cr - 1) * w_cr + FFMIN(c_x0 + 1, w_cr - 1); + + int cb = bilerp(cb_data[ix00], cb_data[ix10], cb_data[ix01], cb_data[ix11], ioff, joff) - 128; + int cr = bilerp(cr_data[ix00], cr_data[ix10], cr_data[ix01], cr_data[ix11], ioff, joff) - 128; + +/* The following snippet is based on libavutil/colorspace.h, + * from the ffmpeg project, released under LGPL 2.1 or later. + */ +#define SCALEBITS 10 +#define FIX(x) ((int) ((x) * (1<<SCALEBITS) + 0.5)) + int r_add = FIX(1.40200*255.0/224.0) * cr; + int g_add = -FIX(0.34414*255.0/224.0) * cb - FIX(0.71414*255.0/224.0) * cr; + int b_add = FIX(1.77200*255.0/224.0) * cb; + int lum = (y_data[i] - 16) * FIX(255.0/219.0) + FIX(0.5); + + out[3*i ] = av_clip_uint8((lum + b_add) >> SCALEBITS); + out[3*i + 1] = av_clip_uint8((lum + g_add) >> SCALEBITS); + out[3*i + 2] = av_clip_uint8((lum + r_add) >> SCALEBITS); + } + out -= 3 * frame->width; + y_data += frame->width; + } +} + +/* c5 = round(c8 * 31 / 255), clipped. The table starts at c8 = -8. */ +static const uint8_t rgb8_to_5[256 + 8*2] = { + 0, 0, 0, 0, 0, 0, 0, 0, + + 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 2, 2, 2, + 2, 2, 2, 2, 2, 3, 3, 3, 3, 3, 3, 3, 3, 4, 4, 4, + 4, 4, 4, 4, 4, 4, 5, 5, 5, 5, 5, 5, 5, 5, 6, 6, + 6, 6, 6, 6, 6, 6, 7, 7, 7, 7, 7, 7, 7, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 10, 10, 10, 10, 10, 10, 10, 11, 11, 11, 11, 11, 11, 11, 11, 12, + 12, 12, 12, 12, 12, 12, 12, 13, 13, 13, 13, 13, 13, 13, 13, 13, + 14, 14, 14, 14, 14, 14, 14, 14, 15, 15, 15, 15, 15, 15, 15, 15, + 16, 16, 16, 16, 16, 16, 16, 16, 17, 17, 17, 17, 17, 17, 17, 17, + 18, 18, 18, 18, 18, 18, 18, 18, 18, 19, 19, 19, 19, 19, 19, 19, + 19, 20, 20, 20, 20, 20, 20, 20, 20, 21, 21, 21, 21, 21, 21, 21, + 21, 22, 22, 22, 22, 22, 22, 22, 22, 22, 23, 23, 23, 23, 23, 23, + 23, 23, 24, 24, 24, 24, 24, 24, 24, 24, 25, 25, 25, 25, 25, 25, + 25, 25, 26, 26, 26, 26, 26, 26, 26, 26, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 28, 28, 28, 28, 28, 28, 28, 28, 29, 29, 29, 29, 29, + 29, 29, 29, 30, 30, 30, 30, 30, 30, 30, 30, 31, 31, 31, 31, 31, + + 31, 31, 31, 31, 31, 31, 31, 31 +}; +/* c8 = round(c5 * 255 / 31) */ +static const uint8_t rgb5_to_8[32] = { + 0, 8, 16, 25, 33, 41, 49, 58, 66, 74, 82, 90, 99, 107, 115, 123, + 132, 140, 148, 156, 165, 173, 181, 189, 197, 206, 214, 222, 230, 239, 247, 255 +}; + +static void bgr24_to_bgr555( int width, int height, uint8_t *out24, int8_t *dither_buf, uint16_t *out ) +{ + int i, j; + int dither_linesz = 3 * (width + 1); + + memset( dither_buf, 0, dither_linesz * height ); + for ( j = 0; j < height; j++ ) + { + for ( i = 0; i < width; i++ ) + { +#define DITHER_PIXEL(ix) ((out24[ix] << 4) + dither_buf[ix]) +#define TO5(c) rgb8_to_5[(((c)+8) >> 4) + 8] +#define PIXEL_ERROR(c, c5) ((c) - (rgb5_to_8[c5] << 4)) + int b = DITHER_PIXEL(3*i), g = DITHER_PIXEL(3*i + 1), r = DITHER_PIXEL(3*i + 2); + uint16_t b5 = TO5(b), g5 = TO5(g), r5 = TO5(r); + int berr = PIXEL_ERROR(b, b5), gerr = PIXEL_ERROR(g, g5), rerr = PIXEL_ERROR(r, r5); + +#define DIFFUSE_ERROR(ix, f) \ + do { \ + dither_buf[(ix) ] += ((f) * berr + 8) >> 4; \ + dither_buf[(ix) + 1] += ((f) * gerr + 8) >> 4; \ + dither_buf[(ix) + 2] += ((f) * rerr + 8) >> 4; \ + } while (0) + + DIFFUSE_ERROR(3*(i+1), 7); + DIFFUSE_ERROR(dither_linesz + 3*(i-1), 3); + DIFFUSE_ERROR(dither_linesz + 3*i , 5); + DIFFUSE_ERROR(dither_linesz + 3*(i+1), 1); + + out[i] = b5 | g5 << 5 | r5 << 10; + } + out24 += 3 * width; + dither_buf += dither_linesz; + out += width; + } +}
static LRESULT @@ -71,7 +224,7 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) return ICERR_BADFORMAT; }
- if ( out->bmiHeader.biBitCount != 24 ) + if ( out->bmiHeader.biBitCount != 24 && out->bmiHeader.biBitCount != 16 ) { TRACE("incompatible depth requested\n"); return ICERR_BADFORMAT; @@ -119,14 +272,70 @@ IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out )
static LRESULT IV50_DecompressBegin( AVCodecContext *avctx, LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", avctx, in, out); - return ICERR_UNSUPPORTED; + TRACE("ICM_DECOMPRESS_BEGIN %p %p %p\n", avctx, in, out); + + if( !avctx || !in ) + return ICERR_BADPARAM; + + TRACE("out->planes = %d\n", out->bmiHeader.biPlanes); + TRACE("out->bpp = %d\n", out->bmiHeader.biBitCount); + TRACE("out->height = %d\n", out->bmiHeader.biHeight); + TRACE("out->width = %d\n", out->bmiHeader.biWidth); + TRACE("out->compr = %#x\n", out->bmiHeader.biCompression); + + if ( out->bmiHeader.biBitCount != 24 && out->bmiHeader.biBitCount != 16 ) + return ICERR_BADFORMAT; + + decode_close( avctx ); + + avctx->width = in->bmiHeader.biWidth; + avctx->height = in->bmiHeader.biHeight; + avctx->out_bitcount = out->bmiHeader.biBitCount; + + return decode_init( avctx ); }
static LRESULT IV50_Decompress( AVCodecContext *avctx, ICDECOMPRESS *icd, DWORD size ) { - FIXME("ICM_DECOMPRESS %p %p %u\n", avctx, icd, size); - return ICERR_UNSUPPORTED; + + AVFrame frame = {0}; + int got_frame = 0; + int result; + + TRACE("ICM_DECOMPRESS %p %p %u\n", avctx, icd, size); + + if ( !avctx || !avctx->priv_data ) + return ICERR_BADPARAM; + + if ( icd->dwFlags ) + FIXME("ignoring flags %#x\n", icd->dwFlags); + + if ( (result = ff_ivi_decode_frame( avctx, &frame, &got_frame, icd->lpInput, icd->lpbiInput->biSizeImage )) < 0 ) + { + TRACE("ff_ivi_decode_frame failed with %d\n", result); + return result; + } + else if ( !got_frame ) + return ICERR_OK; + + if ( icd->lpbiOutput->biWidth != frame.width || icd->lpbiOutput->biHeight != frame.height ) + { + TRACE("output dimensions %d x %d does not match decoded dimensions %d x %d\n", + icd->lpbiOutput->biWidth, icd->lpbiOutput->biHeight, frame.width, frame.height); + return ICERR_BADFORMAT; + } + + if ( avctx->out_bitcount == 24 ) + { + yuv410p_to_bgr24( &frame, icd->lpOutput ); + } + else + { + yuv410p_to_bgr24( &frame, avctx->out_buf ); + bgr24_to_bgr555( frame.width, frame.height, avctx->out_buf, avctx->dither_buf, icd->lpOutput ); + } + + return ICERR_OK; }
static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) @@ -169,11 +378,25 @@ LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, break;
case DRV_OPEN: - FIXME("DRV_OPEN\n"); + { + ICINFO *icinfo = (ICINFO *)lParam2; + + TRACE("Opened\n"); + + if ( icinfo && compare_fourcc( icinfo->fccType, ICTYPE_VIDEO ) ) return 0; + + avctx = calloc( 1, sizeof(*avctx) ); + r = (LRESULT) avctx; break; + }
case DRV_CLOSE: - FIXME("DRV_CLOSE\n"); + if ( avctx ) + { + decode_close( avctx ); + free( avctx ); + } + r = 1; break;
case DRV_ENABLE: @@ -206,6 +429,8 @@ LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, break;
case ICM_DECOMPRESS_END: + if ( avctx ) + decode_close( avctx ); r = ICERR_OK; break;
diff --git a/dlls/ir50_32/ir50_compat.h b/dlls/ir50_32/ir50_compat.h deleted file mode 100644 index dcaf8d990a5..00000000000 --- a/dlls/ir50_32/ir50_compat.h +++ /dev/null @@ -1,27 +0,0 @@ -/* - * Copyright 2022 Shaun Ren for CodeWeavers - * - * This library 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. - * - * This library 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 this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#ifndef __IR50_COMPAT_H -#define __IR50_COMPAT_H - -typedef struct AVCodecContext { - int width, height; - void *priv_data; -} AVCodecContext; - -#endif /* __IR50_COMPAT_H */ diff --git a/libs/ffmpegindeo/COPYING b/libs/ffmpegindeo/COPYING new file mode 100644 index 00000000000..58af0d3787a --- /dev/null +++ b/libs/ffmpegindeo/COPYING @@ -0,0 +1,502 @@ + GNU LESSER GENERAL PUBLIC LICENSE + Version 2.1, February 1999 + + Copyright (C) 1991, 1999 Free Software Foundation, Inc. + 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + Everyone is permitted to copy and distribute verbatim copies + of this license document, but changing it is not allowed. + +[This is the first released version of the Lesser GPL. It also counts + as the successor of the GNU Library Public License, version 2, hence + the version number 2.1.] + + Preamble + + The licenses for most software are designed to take away your +freedom to share and change it. By contrast, the GNU General Public +Licenses are intended to guarantee your freedom to share and change +free software--to make sure the software is free for all its users. + + This license, the Lesser General Public License, applies to some +specially designated software packages--typically libraries--of the +Free Software Foundation and other authors who decide to use it. You +can use it too, but we suggest you first think carefully about whether +this license or the ordinary General Public License is the better +strategy to use in any particular case, based on the explanations below. + + When we speak of free software, we are referring to freedom of use, +not price. Our General Public Licenses are designed to make sure that +you have the freedom to distribute copies of free software (and charge +for this service if you wish); that you receive source code or can get +it if you want it; that you can change the software and use pieces of +it in new free programs; and that you are informed that you can do +these things. + + To protect your rights, we need to make restrictions that forbid +distributors to deny you these rights or to ask you to surrender these +rights. These restrictions translate to certain responsibilities for +you if you distribute copies of the library or if you modify it. + + For example, if you distribute copies of the library, whether gratis +or for a fee, you must give the recipients all the rights that we gave +you. You must make sure that they, too, receive or can get the source +code. If you link other code with the library, you must provide +complete object files to the recipients, so that they can relink them +with the library after making changes to the library and recompiling +it. And you must show them these terms so they know their rights. + + We protect your rights with a two-step method: (1) we copyright the +library, and (2) we offer you this license, which gives you legal +permission to copy, distribute and/or modify the library. + + To protect each distributor, we want to make it very clear that +there is no warranty for the free library. Also, if the library is +modified by someone else and passed on, the recipients should know +that what they have is not the original version, so that the original +author's reputation will not be affected by problems that might be +introduced by others. + + Finally, software patents pose a constant threat to the existence of +any free program. We wish to make sure that a company cannot +effectively restrict the users of a free program by obtaining a +restrictive license from a patent holder. Therefore, we insist that +any patent license obtained for a version of the library must be +consistent with the full freedom of use specified in this license. + + Most GNU software, including some libraries, is covered by the +ordinary GNU General Public License. This license, the GNU Lesser +General Public License, applies to certain designated libraries, and +is quite different from the ordinary General Public License. We use +this license for certain libraries in order to permit linking those +libraries into non-free programs. + + When a program is linked with a library, whether statically or using +a shared library, the combination of the two is legally speaking a +combined work, a derivative of the original library. The ordinary +General Public License therefore permits such linking only if the +entire combination fits its criteria of freedom. The Lesser General +Public License permits more lax criteria for linking other code with +the library. + + We call this license the "Lesser" General Public License because it +does Less to protect the user's freedom than the ordinary General +Public License. It also provides other free software developers Less +of an advantage over competing non-free programs. These disadvantages +are the reason we use the ordinary General Public License for many +libraries. However, the Lesser license provides advantages in certain +special circumstances. + + For example, on rare occasions, there may be a special need to +encourage the widest possible use of a certain library, so that it becomes +a de-facto standard. To achieve this, non-free programs must be +allowed to use the library. A more frequent case is that a free +library does the same job as widely used non-free libraries. In this +case, there is little to gain by limiting the free library to free +software only, so we use the Lesser General Public License. + + In other cases, permission to use a particular library in non-free +programs enables a greater number of people to use a large body of +free software. For example, permission to use the GNU C Library in +non-free programs enables many more people to use the whole GNU +operating system, as well as its variant, the GNU/Linux operating +system. + + Although the Lesser General Public License is Less protective of the +users' freedom, it does ensure that the user of a program that is +linked with the Library has the freedom and the wherewithal to run +that program using a modified version of the Library. + + The precise terms and conditions for copying, distribution and +modification follow. Pay close attention to the difference between a +"work based on the library" and a "work that uses the library". The +former contains code derived from the library, whereas the latter must +be combined with the library in order to run. + + GNU LESSER GENERAL PUBLIC LICENSE + TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION + + 0. This License Agreement applies to any software library or other +program which contains a notice placed by the copyright holder or +other authorized party saying it may be distributed under the terms of +this Lesser General Public License (also called "this License"). +Each licensee is addressed as "you". + + A "library" means a collection of software functions and/or data +prepared so as to be conveniently linked with application programs +(which use some of those functions and data) to form executables. + + The "Library", below, refers to any such software library or work +which has been distributed under these terms. A "work based on the +Library" means either the Library or any derivative work under +copyright law: that is to say, a work containing the Library or a +portion of it, either verbatim or with modifications and/or translated +straightforwardly into another language. (Hereinafter, translation is +included without limitation in the term "modification".) + + "Source code" for a work means the preferred form of the work for +making modifications to it. For a library, complete source code means +all the source code for all modules it contains, plus any associated +interface definition files, plus the scripts used to control compilation +and installation of the library. + + Activities other than copying, distribution and modification are not +covered by this License; they are outside its scope. The act of +running a program using the Library is not restricted, and output from +such a program is covered only if its contents constitute a work based +on the Library (independent of the use of the Library in a tool for +writing it). Whether that is true depends on what the Library does +and what the program that uses the Library does. + + 1. You may copy and distribute verbatim copies of the Library's +complete source code as you receive it, in any medium, provided that +you conspicuously and appropriately publish on each copy an +appropriate copyright notice and disclaimer of warranty; keep intact +all the notices that refer to this License and to the absence of any +warranty; and distribute a copy of this License along with the +Library. + + You may charge a fee for the physical act of transferring a copy, +and you may at your option offer warranty protection in exchange for a +fee. + + 2. You may modify your copy or copies of the Library or any portion +of it, thus forming a work based on the Library, and copy and +distribute such modifications or work under the terms of Section 1 +above, provided that you also meet all of these conditions: + + a) The modified work must itself be a software library. + + b) You must cause the files modified to carry prominent notices + stating that you changed the files and the date of any change. + + c) You must cause the whole of the work to be licensed at no + charge to all third parties under the terms of this License. + + d) If a facility in the modified Library refers to a function or a + table of data to be supplied by an application program that uses + the facility, other than as an argument passed when the facility + is invoked, then you must make a good faith effort to ensure that, + in the event an application does not supply such function or + table, the facility still operates, and performs whatever part of + its purpose remains meaningful. + + (For example, a function in a library to compute square roots has + a purpose that is entirely well-defined independent of the + application. Therefore, Subsection 2d requires that any + application-supplied function or table used by this function must + be optional: if the application does not supply it, the square + root function must still compute square roots.) + +These requirements apply to the modified work as a whole. If +identifiable sections of that work are not derived from the Library, +and can be reasonably considered independent and separate works in +themselves, then this License, and its terms, do not apply to those +sections when you distribute them as separate works. But when you +distribute the same sections as part of a whole which is a work based +on the Library, the distribution of the whole must be on the terms of +this License, whose permissions for other licensees extend to the +entire whole, and thus to each and every part regardless of who wrote +it. + +Thus, it is not the intent of this section to claim rights or contest +your rights to work written entirely by you; rather, the intent is to +exercise the right to control the distribution of derivative or +collective works based on the Library. + +In addition, mere aggregation of another work not based on the Library +with the Library (or with a work based on the Library) on a volume of +a storage or distribution medium does not bring the other work under +the scope of this License. + + 3. You may opt to apply the terms of the ordinary GNU General Public +License instead of this License to a given copy of the Library. To do +this, you must alter all the notices that refer to this License, so +that they refer to the ordinary GNU General Public License, version 2, +instead of to this License. (If a newer version than version 2 of the +ordinary GNU General Public License has appeared, then you can specify +that version instead if you wish.) Do not make any other change in +these notices. + + Once this change is made in a given copy, it is irreversible for +that copy, so the ordinary GNU General Public License applies to all +subsequent copies and derivative works made from that copy. + + This option is useful when you wish to copy part of the code of +the Library into a program that is not a library. + + 4. You may copy and distribute the Library (or a portion or +derivative of it, under Section 2) in object code or executable form +under the terms of Sections 1 and 2 above provided that you accompany +it with the complete corresponding machine-readable source code, which +must be distributed under the terms of Sections 1 and 2 above on a +medium customarily used for software interchange. + + If distribution of object code is made by offering access to copy +from a designated place, then offering equivalent access to copy the +source code from the same place satisfies the requirement to +distribute the source code, even though third parties are not +compelled to copy the source along with the object code. + + 5. A program that contains no derivative of any portion of the +Library, but is designed to work with the Library by being compiled or +linked with it, is called a "work that uses the Library". Such a +work, in isolation, is not a derivative work of the Library, and +therefore falls outside the scope of this License. + + However, linking a "work that uses the Library" with the Library +creates an executable that is a derivative of the Library (because it +contains portions of the Library), rather than a "work that uses the +library". The executable is therefore covered by this License. +Section 6 states terms for distribution of such executables. + + When a "work that uses the Library" uses material from a header file +that is part of the Library, the object code for the work may be a +derivative work of the Library even though the source code is not. +Whether this is true is especially significant if the work can be +linked without the Library, or if the work is itself a library. The +threshold for this to be true is not precisely defined by law. + + If such an object file uses only numerical parameters, data +structure layouts and accessors, and small macros and small inline +functions (ten lines or less in length), then the use of the object +file is unrestricted, regardless of whether it is legally a derivative +work. (Executables containing this object code plus portions of the +Library will still fall under Section 6.) + + Otherwise, if the work is a derivative of the Library, you may +distribute the object code for the work under the terms of Section 6. +Any executables containing that work also fall under Section 6, +whether or not they are linked directly with the Library itself. + + 6. As an exception to the Sections above, you may also combine or +link a "work that uses the Library" with the Library to produce a +work containing portions of the Library, and distribute that work +under terms of your choice, provided that the terms permit +modification of the work for the customer's own use and reverse +engineering for debugging such modifications. + + You must give prominent notice with each copy of the work that the +Library is used in it and that the Library and its use are covered by +this License. You must supply a copy of this License. If the work +during execution displays copyright notices, you must include the +copyright notice for the Library among them, as well as a reference +directing the user to the copy of this License. Also, you must do one +of these things: + + a) Accompany the work with the complete corresponding + machine-readable source code for the Library including whatever + changes were used in the work (which must be distributed under + Sections 1 and 2 above); and, if the work is an executable linked + with the Library, with the complete machine-readable "work that + uses the Library", as object code and/or source code, so that the + user can modify the Library and then relink to produce a modified + executable containing the modified Library. (It is understood + that the user who changes the contents of definitions files in the + Library will not necessarily be able to recompile the application + to use the modified definitions.) + + b) Use a suitable shared library mechanism for linking with the + Library. A suitable mechanism is one that (1) uses at run time a + copy of the library already present on the user's computer system, + rather than copying library functions into the executable, and (2) + will operate properly with a modified version of the library, if + the user installs one, as long as the modified version is + interface-compatible with the version that the work was made with. + + c) Accompany the work with a written offer, valid for at + least three years, to give the same user the materials + specified in Subsection 6a, above, for a charge no more + than the cost of performing this distribution. + + d) If distribution of the work is made by offering access to copy + from a designated place, offer equivalent access to copy the above + specified materials from the same place. + + e) Verify that the user has already received a copy of these + materials or that you have already sent this user a copy. + + For an executable, the required form of the "work that uses the +Library" must include any data and utility programs needed for +reproducing the executable from it. However, as a special exception, +the materials to be distributed need not include anything that is +normally distributed (in either source or binary form) with the major +components (compiler, kernel, and so on) of the operating system on +which the executable runs, unless that component itself accompanies +the executable. + + It may happen that this requirement contradicts the license +restrictions of other proprietary libraries that do not normally +accompany the operating system. Such a contradiction means you cannot +use both them and the Library together in an executable that you +distribute. + + 7. You may place library facilities that are a work based on the +Library side-by-side in a single library together with other library +facilities not covered by this License, and distribute such a combined +library, provided that the separate distribution of the work based on +the Library and of the other library facilities is otherwise +permitted, and provided that you do these two things: + + a) Accompany the combined library with a copy of the same work + based on the Library, uncombined with any other library + facilities. This must be distributed under the terms of the + Sections above. + + b) Give prominent notice with the combined library of the fact + that part of it is a work based on the Library, and explaining + where to find the accompanying uncombined form of the same work. + + 8. You may not copy, modify, sublicense, link with, or distribute +the Library except as expressly provided under this License. Any +attempt otherwise to copy, modify, sublicense, link with, or +distribute the Library is void, and will automatically terminate your +rights under this License. However, parties who have received copies, +or rights, from you under this License will not have their licenses +terminated so long as such parties remain in full compliance. + + 9. You are not required to accept this License, since you have not +signed it. However, nothing else grants you permission to modify or +distribute the Library or its derivative works. These actions are +prohibited by law if you do not accept this License. Therefore, by +modifying or distributing the Library (or any work based on the +Library), you indicate your acceptance of this License to do so, and +all its terms and conditions for copying, distributing or modifying +the Library or works based on it. + + 10. Each time you redistribute the Library (or any work based on the +Library), the recipient automatically receives a license from the +original licensor to copy, distribute, link with or modify the Library +subject to these terms and conditions. You may not impose any further +restrictions on the recipients' exercise of the rights granted herein. +You are not responsible for enforcing compliance by third parties with +this License. + + 11. If, as a consequence of a court judgment or allegation of patent +infringement or for any other reason (not limited to patent issues), +conditions are imposed on you (whether by court order, agreement or +otherwise) that contradict the conditions of this License, they do not +excuse you from the conditions of this License. If you cannot +distribute so as to satisfy simultaneously your obligations under this +License and any other pertinent obligations, then as a consequence you +may not distribute the Library at all. For example, if a patent +license would not permit royalty-free redistribution of the Library by +all those who receive copies directly or indirectly through you, then +the only way you could satisfy both it and this License would be to +refrain entirely from distribution of the Library. + +If any portion of this section is held invalid or unenforceable under any +particular circumstance, the balance of the section is intended to apply, +and the section as a whole is intended to apply in other circumstances. + +It is not the purpose of this section to induce you to infringe any +patents or other property right claims or to contest validity of any +such claims; this section has the sole purpose of protecting the +integrity of the free software distribution system which is +implemented by public license practices. Many people have made +generous contributions to the wide range of software distributed +through that system in reliance on consistent application of that +system; it is up to the author/donor to decide if he or she is willing +to distribute software through any other system and a licensee cannot +impose that choice. + +This section is intended to make thoroughly clear what is believed to +be a consequence of the rest of this License. + + 12. If the distribution and/or use of the Library is restricted in +certain countries either by patents or by copyrighted interfaces, the +original copyright holder who places the Library under this License may add +an explicit geographical distribution limitation excluding those countries, +so that distribution is permitted only in or among countries not thus +excluded. In such case, this License incorporates the limitation as if +written in the body of this License. + + 13. The Free Software Foundation may publish revised and/or new +versions of the Lesser General Public License from time to time. +Such new versions will be similar in spirit to the present version, +but may differ in detail to address new problems or concerns. + +Each version is given a distinguishing version number. If the Library +specifies a version number of this License which applies to it and +"any later version", you have the option of following the terms and +conditions either of that version or of any later version published by +the Free Software Foundation. If the Library does not specify a +license version number, you may choose any version ever published by +the Free Software Foundation. + + 14. If you wish to incorporate parts of the Library into other free +programs whose distribution conditions are incompatible with these, +write to the author to ask for permission. For software which is +copyrighted by the Free Software Foundation, write to the Free +Software Foundation; we sometimes make exceptions for this. Our +decision will be guided by the two goals of preserving the free status +of all derivatives of our free software and of promoting the sharing +and reuse of software generally. + + NO WARRANTY + + 15. BECAUSE THE LIBRARY IS LICENSED FREE OF CHARGE, THERE IS NO +WARRANTY FOR THE LIBRARY, TO THE EXTENT PERMITTED BY APPLICABLE LAW. +EXCEPT WHEN OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR +OTHER PARTIES PROVIDE THE LIBRARY "AS IS" WITHOUT WARRANTY OF ANY +KIND, EITHER EXPRESSED OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE +IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR +PURPOSE. THE ENTIRE RISK AS TO THE QUALITY AND PERFORMANCE OF THE +LIBRARY IS WITH YOU. SHOULD THE LIBRARY PROVE DEFECTIVE, YOU ASSUME +THE COST OF ALL NECESSARY SERVICING, REPAIR OR CORRECTION. + + 16. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN +WRITING WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY +AND/OR REDISTRIBUTE THE LIBRARY AS PERMITTED ABOVE, BE LIABLE TO YOU +FOR DAMAGES, INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR +CONSEQUENTIAL DAMAGES ARISING OUT OF THE USE OR INABILITY TO USE THE +LIBRARY (INCLUDING BUT NOT LIMITED TO LOSS OF DATA OR DATA BEING +RENDERED INACCURATE OR LOSSES SUSTAINED BY YOU OR THIRD PARTIES OR A +FAILURE OF THE LIBRARY TO OPERATE WITH ANY OTHER SOFTWARE), EVEN IF +SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE POSSIBILITY OF SUCH +DAMAGES. + + END OF TERMS AND CONDITIONS + + How to Apply These Terms to Your New Libraries + + If you develop a new library, and you want it to be of the greatest +possible use to the public, we recommend making it free software that +everyone can redistribute and change. You can do so by permitting +redistribution under these terms (or, alternatively, under the terms of the +ordinary General Public License). + + To apply these terms, attach the following notices to the library. It is +safest to attach them to the start of each source file to most effectively +convey the exclusion of warranty; and each file should have at least the +"copyright" line and a pointer to where the full notice is found. + + <one line to give the library's name and a brief idea of what it does.> + Copyright (C) <year> <name of author> + + This library 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. + + This library 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 this library; if not, write to the Free Software + Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + +Also add information on how to contact you by electronic and paper mail. + +You should also get your employer (if you work as a programmer) or your +school, if any, to sign a "copyright disclaimer" for the library, if +necessary. Here is a sample; alter the names: + + Yoyodyne, Inc., hereby disclaims all copyright interest in the + library `Frob' (a library for tweaking knobs) written by James Random Hacker. + + <signature of Ty Coon>, 1 April 1990 + Ty Coon, President of Vice + +That's all there is to it! diff --git a/libs/ffmpegindeo/Makefile.in b/libs/ffmpegindeo/Makefile.in new file mode 100644 index 00000000000..2b87ebc47e0 --- /dev/null +++ b/libs/ffmpegindeo/Makefile.in @@ -0,0 +1,7 @@ +STATICLIB = libffmpegindeo.a + +C_SRCS = \ + indeo5.c \ + ivi.c \ + ivi_dsp.c \ + vlc.c diff --git a/libs/ffmpegindeo/get_bits.h b/libs/ffmpegindeo/get_bits.h new file mode 100644 index 00000000000..ec4e94bdfed --- /dev/null +++ b/libs/ffmpegindeo/get_bits.h @@ -0,0 +1,443 @@ +/* + * Copyright (c) 2004 Michael Niedermayer michaelni@gmx.at + * Copyright (c) 2016 Alexandra Hájková + * + * 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 + * bitstream reader API header. + */ + +#ifndef AVCODEC_GET_BITS_H +#define AVCODEC_GET_BITS_H + +#include <stdint.h> +#include <limits.h> +#include "indeo_compat.h" +#include "vlc.h" + +#define BITSTREAM_READER_LE + +/* + * Safe bitstream reading: + * optionally, the get_bits API can check to ensure that we + * don't read past input buffer boundaries. This is protected + * with CONFIG_SAFE_BITSTREAM_READER at the global level, and + * then below that with UNCHECKED_BITSTREAM_READER at the per- + * decoder level. This means that decoders that check internally + * can "#define UNCHECKED_BITSTREAM_READER 1" to disable + * overread checks. + * Boundary checking causes a minor performance penalty so for + * applications that won't want/need this, it can be disabled + * globally using "#define CONFIG_SAFE_BITSTREAM_READER 0". + */ +#ifndef UNCHECKED_BITSTREAM_READER +#define UNCHECKED_BITSTREAM_READER 1 +#endif + +#ifndef CACHED_BITSTREAM_READER +#define CACHED_BITSTREAM_READER 0 +#endif + +typedef struct GetBitContext { + const uint8_t *buffer, *buffer_end; + int index; + int size_in_bits; + int size_in_bits_plus8; +} GetBitContext; + +static inline unsigned int get_bits(GetBitContext *s, int n); +static inline void skip_bits(GetBitContext *s, int n); + +/* Bitstream reader API docs: + * name + * arbitrary name which is used as prefix for the internal variables + * + * gb + * getbitcontext + * + * OPEN_READER(name, gb) + * load gb into local variables + * + * CLOSE_READER(name, gb) + * store local vars in gb + * + * UPDATE_CACHE(name, gb) + * Refill the internal cache from the bitstream. + * After this call at least MIN_CACHE_BITS will be available. + * + * GET_CACHE(name, gb) + * Will output the contents of the internal cache, + * next bit is MSB of 32 or 64 bits (FIXME 64 bits). + * + * SHOW_UBITS(name, gb, num) + * Will return the next num bits. + * + * SHOW_SBITS(name, gb, num) + * Will return the next num bits and do sign extension. + * + * SKIP_BITS(name, gb, num) + * Will skip over the next num bits. + * Note, this is equivalent to SKIP_CACHE; SKIP_COUNTER. + * + * SKIP_CACHE(name, gb, num) + * Will remove the next num bits from the cache (note SKIP_COUNTER + * MUST be called before UPDATE_CACHE / CLOSE_READER). + * + * SKIP_COUNTER(name, gb, num) + * Will increment the internal bit counter (see SKIP_CACHE & SKIP_BITS). + * + * LAST_SKIP_BITS(name, gb, num) + * Like SKIP_BITS, to be used if next call is UPDATE_CACHE or CLOSE_READER. + * + * BITS_LEFT(name, gb) + * Return the number of bits left + * + * For examples see get_bits, show_bits, skip_bits, get_vlc. + */ + +#if CACHED_BITSTREAM_READER +# define MIN_CACHE_BITS 64 +#elif defined LONG_BITSTREAM_READER +# define MIN_CACHE_BITS 32 +#else +# define MIN_CACHE_BITS 25 +#endif + +#if defined(__GNUC__) || defined(__clang__) +# define av_unused __attribute__((unused)) +#else +# define av_unused +#endif + +#define OPEN_READER_NOSIZE(name, gb) \ + unsigned int name ## _index = (gb)->index; \ + unsigned int av_unused name ## _cache + +#define OPEN_READER(name, gb) OPEN_READER_NOSIZE(name, gb) + +#define BITS_AVAILABLE(name, gb) 1 + + +#define CLOSE_READER(name, gb) (gb)->index = name ## _index + +# ifdef LONG_BITSTREAM_READER + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL64((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB64((gb)->buffer + (name ## _index >> 3)) >> (32 - (name ## _index & 7)) + +#else + +#define AV_RL32(x) \ + (((uint32_t)((const uint8_t*)(x))[3] << 24) | \ + (((const uint8_t*)(x))[2] << 16) | \ + (((const uint8_t*)(x))[1] << 8) | \ + ((const uint8_t*)(x))[0]) + +# define UPDATE_CACHE_LE(name, gb) name ## _cache = \ + AV_RL32((gb)->buffer + (name ## _index >> 3)) >> (name ## _index & 7) + +# define UPDATE_CACHE_BE(name, gb) name ## _cache = \ + AV_RB32((gb)->buffer + (name ## _index >> 3)) << (name ## _index & 7) + +#endif + + +#ifdef BITSTREAM_READER_LE + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_LE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache >>= (num) + +#else + +# define UPDATE_CACHE(name, gb) UPDATE_CACHE_BE(name, gb) + +# define SKIP_CACHE(name, gb, num) name ## _cache <<= (num) + +#endif + +#define SKIP_COUNTER(name, gb, num) name ## _index += (num) + + +#define BITS_LEFT(name, gb) ((int)((gb)->size_in_bits - name ## _index)) + +#define SKIP_BITS(name, gb, num) \ + do { \ + SKIP_CACHE(name, gb, num); \ + SKIP_COUNTER(name, gb, num); \ + } while (0) + +#define LAST_SKIP_BITS(name, gb, num) SKIP_COUNTER(name, gb, num) + +/* + * The following code snippet is taken from FFmpeg (libavcodec/mathops.h). + * + * Copyright (c) 2001, 2002 Fabrice Bellard + * Copyright (c) 2006 Michael Niedermayer michaelni@gmx.at et al + * + */ +static av_always_inline unsigned zero_extend(unsigned val, unsigned bits) +{ + return (val << ((8 * sizeof(int)) - bits)) >> ((8 * sizeof(int)) - bits); +} + +static av_always_inline int sign_extend(int val, unsigned bits) +{ + unsigned shift = 8 * sizeof(int) - bits; + union { unsigned u; int s; } v = { (unsigned) val << shift }; + return v.s >> shift; +} + +#define SHOW_UBITS_LE(name, gb, num) zero_extend(name ## _cache, num) +#define SHOW_SBITS_LE(name, gb, num) sign_extend(name ## _cache, num) + +#define SHOW_UBITS_BE(name, gb, num) NEG_USR32(name ## _cache, num) +#define SHOW_SBITS_BE(name, gb, num) NEG_SSR32(name ## _cache, num) + +#ifdef BITSTREAM_READER_LE +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_LE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_LE(name, gb, num) +#else +# define SHOW_UBITS(name, gb, num) SHOW_UBITS_BE(name, gb, num) +# define SHOW_SBITS(name, gb, num) SHOW_SBITS_BE(name, gb, num) +#endif + +#define GET_CACHE(name, gb) ((uint32_t) name ## _cache) + + +static inline int get_bits_count(const GetBitContext *s) +{ + return s->index; +} + + +/** + * Skips the specified number of bits. + * @param n the number of bits to skip, + * For the UNCHECKED_BITSTREAM_READER this must not cause the distance + * from the start to overflow int32_t. Staying within the bitstream + padding + * is sufficient, too. + */ +static inline void skip_bits_long(GetBitContext *s, int n) +{ + s->index += n; +} + + +/** + * Read 1-25 bits. + */ +static inline unsigned int get_bits(GetBitContext *s, int n) +{ + register unsigned int tmp; + OPEN_READER(re, s); + av_assert2(n>0 && n<=25); + UPDATE_CACHE(re, s); + tmp = SHOW_UBITS(re, s, n); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); + av_assert2(tmp < UINT64_C(1) << n); + return tmp; +} + +/** + * Read 0-32 bits. + */ +static inline unsigned int get_bits_long(GetBitContext *s, int n) +{ + av_assert2(n>=0 && n<=32); + if (!n) { + return 0; + } else if (n <= MIN_CACHE_BITS) { + return get_bits(s, n); + } else { +#ifdef BITSTREAM_READER_LE + unsigned ret = get_bits(s, 16); + return ret | (get_bits(s, n - 16) << 16); +#else + unsigned ret = get_bits(s, 16) << (n - 16); + return ret | get_bits(s, n - 16); +#endif + } +} + +static inline void skip_bits(GetBitContext *s, int n) +{ + OPEN_READER(re, s); + LAST_SKIP_BITS(re, s, n); + CLOSE_READER(re, s); +} + +static inline unsigned int get_bits1(GetBitContext *s) +{ + unsigned int index = s->index; + uint8_t result = s->buffer[index >> 3]; +#ifdef BITSTREAM_READER_LE + result >>= index & 7; + result &= 1; +#else + result <<= index & 7; + result >>= 8 - 1; +#endif + index++; + s->index = index; + + return result; +} + + +#define AV_INPUT_BUFFER_PADDING_SIZE 64 +static inline int init_get_bits_xe(GetBitContext *s, const uint8_t *buffer, + int bit_size, int is_le) +{ + int buffer_size; + int ret = 0; + + if (bit_size >= INT_MAX - FFMAX(7, AV_INPUT_BUFFER_PADDING_SIZE*8) || bit_size < 0 || !buffer) { + bit_size = 0; + buffer = NULL; + ret = AVERROR_INVALIDDATA; + } + + buffer_size = (bit_size + 7) >> 3; + + s->buffer = buffer; + s->size_in_bits = bit_size; + s->size_in_bits_plus8 = bit_size + 8; + s->buffer_end = buffer + buffer_size; + s->index = 0; + + return ret; +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param bit_size the size of the buffer in bits + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits(GetBitContext *s, const uint8_t *buffer, + int bit_size) +{ +#ifdef BITSTREAM_READER_LE + return init_get_bits_xe(s, buffer, bit_size, 1); +#else + return init_get_bits_xe(s, buffer, bit_size, 0); +#endif +} + +/** + * Initialize GetBitContext. + * @param buffer bitstream buffer, must be AV_INPUT_BUFFER_PADDING_SIZE bytes + * larger than the actual read bits because some optimized bitstream + * readers read 32 or 64 bit at once and could read over the end + * @param byte_size the size of the buffer in bytes + * @return 0 on success, AVERROR_INVALIDDATA if the buffer_size would overflow. + */ +static inline int init_get_bits8(GetBitContext *s, const uint8_t *buffer, + int byte_size) +{ + if (byte_size > INT_MAX / 8 || byte_size < 0) + byte_size = -1; + return init_get_bits(s, buffer, byte_size * 8); +} + +static inline const uint8_t *align_get_bits(GetBitContext *s) +{ + int n = -get_bits_count(s) & 7; + if (n) + skip_bits(s, n); + return s->buffer + (s->index >> 3); +} + +/** + * If the vlc code is invalid and max_depth=1, then no bits will be removed. + * If the vlc code is invalid and max_depth>1, then the number of bits removed + * is undefined. + */ +#define GET_VLC(code, name, gb, table, bits, max_depth) \ + do { \ + int n, nb_bits; \ + unsigned int index; \ + \ + index = SHOW_UBITS(name, gb, bits); \ + code = table[index].sym; \ + n = table[index].len; \ + \ + if (max_depth > 1 && n < 0) { \ + LAST_SKIP_BITS(name, gb, bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index].sym; \ + n = table[index].len; \ + if (max_depth > 2 && n < 0) { \ + LAST_SKIP_BITS(name, gb, nb_bits); \ + UPDATE_CACHE(name, gb); \ + \ + nb_bits = -n; \ + \ + index = SHOW_UBITS(name, gb, nb_bits) + code; \ + code = table[index].sym; \ + n = table[index].len; \ + } \ + } \ + SKIP_BITS(name, gb, n); \ + } while (0) + + +/** + * Parse a vlc code. + * @param bits is the number of bits which will be read at once, must be + * identical to nb_bits in init_vlc() + * @param max_depth is the number of times bits bits must be read to completely + * read the longest vlc code + * = (max_vlc_length + bits - 1) / bits + * @returns the code parsed or -1 if no vlc matches + */ +static av_always_inline int get_vlc2(GetBitContext *s, const VLCElem *table, + int bits, int max_depth) +{ + int code; + + OPEN_READER(re, s); + UPDATE_CACHE(re, s); + + GET_VLC(code, re, s, table, bits, max_depth); + + CLOSE_READER(re, s); + + return code; +} + + +static inline int get_bits_left(GetBitContext *gb) +{ + return gb->size_in_bits - get_bits_count(gb); +} + +#endif /* AVCODEC_GET_BITS_H */ diff --git a/libs/ffmpegindeo/indeo5.c b/libs/ffmpegindeo/indeo5.c new file mode 100644 index 00000000000..dfc24e1099b --- /dev/null +++ b/libs/ffmpegindeo/indeo5.c @@ -0,0 +1,825 @@ +/* + * Indeo Video Interactive v5 compatible decoder + * Copyright (c) 2009 Maxim Poliakovski + * + * 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 + * Indeo Video Interactive version 5 decoder + * + * Indeo5 data is usually transported within .avi or .mov files. + * Known FOURCCs: 'IV50' + */ + +#include <stdint.h> +#include "indeo_compat.h" + +#define BITSTREAM_READER_LE +#include "get_bits.h" +#include "indeo5.h" +#include "ivi_dsp.h" + + +/** + * standard picture dimensions (width, height divided by 4) + */ +static const uint8_t ivi5_common_pic_sizes[30] = { + 160, 120, 80, 60, 40, 30, 176, 120, 88, 60, 88, 72, 44, 36, 60, 45, 160, 60, + 176, 60, 20, 15, 22, 18, 0, 0, 0, 0, 0, 0 +}; + + +/** + * Indeo5 dequantization matrixes consist of two tables: base table + * and scale table. The base table defines the dequantization matrix + * itself and the scale table tells how this matrix should be scaled + * for a particular quant level (0...24). + * + * ivi5_base_quant_bbb_ttt - base tables for block size 'bbb' of type 'ttt' + * ivi5_scale_quant_bbb_ttt - scale tables for block size 'bbb' of type 'ttt' + */ +static const uint16_t ivi5_base_quant_8x8_inter[5][64] = { + {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e, + 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66, + 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e, + 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76, + }, + {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e, + 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66, + 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e, + 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76, + }, + {0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + }, + {0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + }, + {0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + } +}; + +static const uint16_t ivi5_base_quant_8x8_intra[5][64] = { + {0x1a, 0x2e, 0x36, 0x42, 0x46, 0x4a, 0x4e, 0x5a, 0x2e, 0x32, 0x3e, 0x42, 0x46, 0x4e, 0x56, 0x6a, + 0x36, 0x3e, 0x3e, 0x44, 0x4a, 0x54, 0x66, 0x72, 0x42, 0x42, 0x44, 0x4a, 0x52, 0x62, 0x6c, 0x7a, + 0x46, 0x46, 0x4a, 0x52, 0x5e, 0x66, 0x72, 0x8e, 0x4a, 0x4e, 0x54, 0x62, 0x66, 0x6e, 0x86, 0xa6, + 0x4e, 0x56, 0x66, 0x6c, 0x72, 0x86, 0x9a, 0xca, 0x5a, 0x6a, 0x72, 0x7a, 0x8e, 0xa6, 0xca, 0xfe, + }, + {0x26, 0x3a, 0x3e, 0x46, 0x4a, 0x4e, 0x52, 0x5a, 0x3a, 0x3e, 0x42, 0x46, 0x4a, 0x4e, 0x56, 0x5e, + 0x3e, 0x42, 0x46, 0x48, 0x4c, 0x52, 0x5a, 0x62, 0x46, 0x46, 0x48, 0x4a, 0x4e, 0x56, 0x5e, 0x66, + 0x4a, 0x4a, 0x4c, 0x4e, 0x52, 0x5a, 0x62, 0x6a, 0x4e, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x66, 0x6e, + 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x72, 0x5a, 0x5e, 0x62, 0x66, 0x6a, 0x6e, 0x72, 0x76, + }, + {0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, 0x4e, 0xaa, 0xf2, 0xd4, 0xde, 0xc2, 0xd6, 0xc2, + }, + {0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0x4e, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, 0xaa, + 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xf2, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, 0xd4, + 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xde, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xd6, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, 0xc2, + }, + {0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, 0x5e, + } +}; + +static const uint16_t ivi5_base_quant_4x4_inter[16] = { + 0x1e, 0x3e, 0x4a, 0x52, 0x3e, 0x4a, 0x52, 0x56, 0x4a, 0x52, 0x56, 0x5e, 0x52, 0x56, 0x5e, 0x66 +}; + +static const uint16_t ivi5_base_quant_4x4_intra[16] = { + 0x1e, 0x3e, 0x4a, 0x52, 0x3e, 0x4a, 0x52, 0x5e, 0x4a, 0x52, 0x5e, 0x7a, 0x52, 0x5e, 0x7a, 0x92 +}; + + +static const uint8_t ivi5_scale_quant_8x8_inter[5][24] = { + {0x0b, 0x11, 0x13, 0x14, 0x15, 0x16, 0x18, 0x1a, 0x1b, 0x1d, 0x20, 0x22, + 0x23, 0x25, 0x28, 0x2a, 0x2e, 0x32, 0x35, 0x39, 0x3d, 0x41, 0x44, 0x4a, + }, + {0x07, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x29, 0x2d, 0x31, 0x35, + 0x3a, 0x3f, 0x44, 0x4a, 0x50, 0x56, 0x5c, 0x63, 0x6a, 0x71, 0x78, 0x7e, + }, + {0x15, 0x25, 0x28, 0x2d, 0x30, 0x34, 0x3a, 0x3d, 0x42, 0x48, 0x4c, 0x51, + 0x56, 0x5b, 0x60, 0x65, 0x6b, 0x70, 0x76, 0x7c, 0x82, 0x88, 0x8f, 0x97, + }, + {0x13, 0x1f, 0x20, 0x22, 0x25, 0x28, 0x2b, 0x2d, 0x30, 0x33, 0x36, 0x39, + 0x3c, 0x3f, 0x42, 0x45, 0x48, 0x4b, 0x4e, 0x52, 0x56, 0x5a, 0x5e, 0x62, + }, + {0x3c, 0x52, 0x58, 0x5d, 0x63, 0x68, 0x68, 0x6d, 0x73, 0x78, 0x7c, 0x80, + 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa3, 0xa9, 0xad, 0xb1, 0xb5, 0xba, + }, +}; + +static const uint8_t ivi5_scale_quant_8x8_intra[5][24] = { + {0x0b, 0x0e, 0x10, 0x12, 0x14, 0x16, 0x17, 0x18, 0x1a, 0x1c, 0x1e, 0x20, + 0x22, 0x24, 0x27, 0x28, 0x2a, 0x2d, 0x2f, 0x31, 0x34, 0x37, 0x39, 0x3c, + }, + {0x01, 0x10, 0x12, 0x14, 0x16, 0x18, 0x1b, 0x1e, 0x22, 0x25, 0x28, 0x2c, + 0x30, 0x34, 0x38, 0x3d, 0x42, 0x47, 0x4c, 0x52, 0x58, 0x5e, 0x65, 0x6c, + }, + {0x13, 0x22, 0x27, 0x2a, 0x2d, 0x33, 0x36, 0x3c, 0x41, 0x45, 0x49, 0x4e, + 0x53, 0x58, 0x5d, 0x63, 0x69, 0x6f, 0x75, 0x7c, 0x82, 0x88, 0x8e, 0x95, + }, + {0x13, 0x1f, 0x21, 0x24, 0x27, 0x29, 0x2d, 0x2f, 0x34, 0x37, 0x3a, 0x3d, + 0x40, 0x44, 0x48, 0x4c, 0x4f, 0x52, 0x56, 0x5a, 0x5e, 0x62, 0x66, 0x6b, + }, + {0x31, 0x42, 0x47, 0x47, 0x4d, 0x52, 0x58, 0x58, 0x5d, 0x63, 0x67, 0x6b, + 0x6f, 0x73, 0x78, 0x7c, 0x80, 0x84, 0x89, 0x8e, 0x93, 0x98, 0x9d, 0xa4, + } +}; + +static const uint8_t ivi5_scale_quant_4x4_inter[24] = { + 0x0b, 0x0d, 0x0d, 0x0e, 0x11, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, + 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, +}; + +static const uint8_t ivi5_scale_quant_4x4_intra[24] = { + 0x01, 0x0b, 0x0b, 0x0d, 0x0d, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x13, 0x14, + 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20 +}; + + +/** + * Indeo5 frame types. + */ +enum { + FRAMETYPE_INTRA = 0, + FRAMETYPE_INTER = 1, ///< non-droppable P-frame + FRAMETYPE_INTER_SCAL = 2, ///< droppable P-frame used in the scalability mode + FRAMETYPE_INTER_NOREF = 3, ///< droppable P-frame + FRAMETYPE_NULL = 4 ///< empty frame with no data +}; + +#define IVI5_PIC_SIZE_ESC 15 + +const uint8_t ff_zigzag_direct[64] = { + 0, 1, 8, 16, 9, 2, 3, 10, + 17, 24, 32, 25, 18, 11, 4, 5, + 12, 19, 26, 33, 40, 48, 41, 34, + 27, 20, 13, 6, 7, 14, 21, 28, + 35, 42, 49, 56, 57, 50, 43, 36, + 29, 22, 15, 23, 30, 37, 44, 51, + 58, 59, 52, 45, 38, 31, 39, 46, + 53, 60, 61, 54, 47, 55, 62, 63 +}; + +/** + * Decode Indeo5 GOP (Group of pictures) header. + * This header is present in key frames only. + * It defines parameters for all frames in a GOP. + * + * @param[in,out] ctx ptr to the decoder context + * @param[in] avctx ptr to the AVCodecContext + * @return result code: 0 = OK, -1 = error + */ +static int decode_gop_header(IVI45DecContext *ctx, AVCodecContext *avctx) +{ + int result, i, p, tile_size, pic_size_indx, mb_size, blk_size, is_scalable; + int quant_mat, blk_size_changed = 0; + IVIBandDesc *band, *band1, *band2; + IVIPicConfig pic_conf; + + ctx->gop_flags = get_bits(&ctx->gb, 8); + + ctx->gop_hdr_size = (ctx->gop_flags & 1) ? get_bits(&ctx->gb, 16) : 0; + + if (ctx->gop_flags & IVI5_IS_PROTECTED) + ctx->lock_word = get_bits_long(&ctx->gb, 32); + + tile_size = (ctx->gop_flags & 0x40) ? 64 << get_bits(&ctx->gb, 2) : 0; + if (tile_size > 256) { + return AVERROR_INVALIDDATA; + } + + /* decode number of wavelet bands */ + /* num_levels * 3 + 1 */ + pic_conf.luma_bands = get_bits(&ctx->gb, 2) * 3 + 1; + pic_conf.chroma_bands = get_bits1(&ctx->gb) * 3 + 1; + is_scalable = pic_conf.luma_bands != 1 || pic_conf.chroma_bands != 1; + if (is_scalable && (pic_conf.luma_bands != 4 || pic_conf.chroma_bands != 1)) { + return AVERROR_INVALIDDATA; + } + + pic_size_indx = get_bits(&ctx->gb, 4); + if (pic_size_indx == IVI5_PIC_SIZE_ESC) { + pic_conf.pic_height = get_bits(&ctx->gb, 13); + pic_conf.pic_width = get_bits(&ctx->gb, 13); + } else { + pic_conf.pic_height = ivi5_common_pic_sizes[pic_size_indx * 2 + 1] << 2; + pic_conf.pic_width = ivi5_common_pic_sizes[pic_size_indx * 2 ] << 2; + } + + if (ctx->gop_flags & 2) { + avpriv_report_missing_feature(avctx, "YV12 picture format"); + return AVERROR_PATCHWELCOME; + } + + pic_conf.chroma_height = (pic_conf.pic_height + 3) >> 2; + pic_conf.chroma_width = (pic_conf.pic_width + 3) >> 2; + + if (!tile_size) { + pic_conf.tile_height = pic_conf.pic_height; + pic_conf.tile_width = pic_conf.pic_width; + } else { + pic_conf.tile_height = pic_conf.tile_width = tile_size; + } + + /* check if picture layout was changed and reallocate buffers */ + if (ivi_pic_config_cmp(&pic_conf, &ctx->pic_conf) || ctx->gop_invalid) { + result = ff_ivi_init_planes(avctx, ctx->planes, &pic_conf, 0); + if (result < 0) { + av_log(avctx, AV_LOG_ERROR, "Couldn't reallocate color planes!\n"); + return result; + } + ctx->pic_conf = pic_conf; + ctx->is_scalable = is_scalable; + blk_size_changed = 1; /* force reallocation of the internal structures */ + } + + for (p = 0; p <= 1; p++) { + for (i = 0; i < (!p ? pic_conf.luma_bands : pic_conf.chroma_bands); i++) { + band = &ctx->planes[p].bands[i]; + + band->is_halfpel = get_bits1(&ctx->gb); + + mb_size = get_bits1(&ctx->gb); + blk_size = 8 >> get_bits1(&ctx->gb); + mb_size = blk_size << !mb_size; + + if (p==0 && blk_size==4) { + av_log(avctx, AV_LOG_ERROR, "4x4 luma blocks are unsupported!\n"); + return AVERROR_PATCHWELCOME; + } + + blk_size_changed = mb_size != band->mb_size || blk_size != band->blk_size; + if (blk_size_changed) { + band->mb_size = mb_size; + band->blk_size = blk_size; + } + + if (get_bits1(&ctx->gb)) { + avpriv_report_missing_feature(avctx, "Extended transform info"); + return AVERROR_PATCHWELCOME; + } + + /* select transform function and scan pattern according to plane and band number */ + switch ((p << 2) + i) { + case 0: + band->inv_transform = ff_ivi_inverse_slant_8x8; + band->dc_transform = ff_ivi_dc_slant_2d; + band->scan = ff_zigzag_direct; + band->transform_size = 8; + break; + + case 1: + band->inv_transform = ff_ivi_row_slant8; + band->dc_transform = ff_ivi_dc_row_slant; + band->scan = ff_ivi_vertical_scan_8x8; + band->transform_size = 8; + break; + + case 2: + band->inv_transform = ff_ivi_col_slant8; + band->dc_transform = ff_ivi_dc_col_slant; + band->scan = ff_ivi_horizontal_scan_8x8; + band->transform_size = 8; + break; + + case 3: + band->inv_transform = ff_ivi_put_pixels_8x8; + band->dc_transform = ff_ivi_put_dc_pixel_8x8; + band->scan = ff_ivi_horizontal_scan_8x8; + band->transform_size = 8; + break; + + case 4: + band->inv_transform = ff_ivi_inverse_slant_4x4; + band->dc_transform = ff_ivi_dc_slant_2d; + band->scan = ff_ivi_direct_scan_4x4; + band->transform_size = 4; + break; + } + + band->is_2d_trans = band->inv_transform == ff_ivi_inverse_slant_8x8 || + band->inv_transform == ff_ivi_inverse_slant_4x4; + + if (band->transform_size != band->blk_size) { + av_log(avctx, AV_LOG_ERROR, "transform and block size mismatch (%d != %d)\n", band->transform_size, band->blk_size); + return AVERROR_INVALIDDATA; + } + + /* select dequant matrix according to plane and band number */ + if (!p) { + quant_mat = (pic_conf.luma_bands > 1) ? i+1 : 0; + } else { + quant_mat = 5; + } + + if (band->blk_size == 8) { + if(quant_mat >= 5){ + av_log(avctx, AV_LOG_ERROR, "quant_mat %d too large!\n", quant_mat); + return -1; + } + band->intra_base = &ivi5_base_quant_8x8_intra[quant_mat][0]; + band->inter_base = &ivi5_base_quant_8x8_inter[quant_mat][0]; + band->intra_scale = &ivi5_scale_quant_8x8_intra[quant_mat][0]; + band->inter_scale = &ivi5_scale_quant_8x8_inter[quant_mat][0]; + } else { + band->intra_base = ivi5_base_quant_4x4_intra; + band->inter_base = ivi5_base_quant_4x4_inter; + band->intra_scale = ivi5_scale_quant_4x4_intra; + band->inter_scale = ivi5_scale_quant_4x4_inter; + } + + if (get_bits(&ctx->gb, 2)) { + av_log(avctx, AV_LOG_ERROR, "End marker missing!\n"); + return AVERROR_INVALIDDATA; + } + } + } + + /* copy chroma parameters into the 2nd chroma plane */ + for (i = 0; i < pic_conf.chroma_bands; i++) { + band1 = &ctx->planes[1].bands[i]; + band2 = &ctx->planes[2].bands[i]; + + band2->width = band1->width; + band2->height = band1->height; + band2->mb_size = band1->mb_size; + band2->blk_size = band1->blk_size; + band2->is_halfpel = band1->is_halfpel; + band2->intra_base = band1->intra_base; + band2->inter_base = band1->inter_base; + band2->intra_scale = band1->intra_scale; + band2->inter_scale = band1->inter_scale; + band2->scan = band1->scan; + band2->inv_transform = band1->inv_transform; + band2->dc_transform = band1->dc_transform; + band2->is_2d_trans = band1->is_2d_trans; + band2->transform_size= band1->transform_size; + } + + /* reallocate internal structures if needed */ + if (blk_size_changed) { + result = ff_ivi_init_tiles(ctx->planes, pic_conf.tile_width, + pic_conf.tile_height); + if (result < 0) { + av_log(avctx, AV_LOG_ERROR, + "Couldn't reallocate internal structures!\n"); + return result; + } + } + + if (ctx->gop_flags & 8) { + if (get_bits(&ctx->gb, 3)) { + av_log(avctx, AV_LOG_ERROR, "Alignment bits are not zero!\n"); + return AVERROR_INVALIDDATA; + } + + if (get_bits1(&ctx->gb)) + skip_bits(&ctx->gb, 24); /* skip transparency fill color */ + } + + align_get_bits(&ctx->gb); + + skip_bits(&ctx->gb, 23); /* FIXME: unknown meaning */ + + /* skip GOP extension if any */ + if (get_bits1(&ctx->gb)) { + do { + i = get_bits(&ctx->gb, 16); + } while (i & 0x8000); + } + + align_get_bits(&ctx->gb); + + return 0; +} + + +/** + * Skip a header extension. + * + * @param[in,out] gb the GetBit context + */ +static inline int skip_hdr_extension(GetBitContext *gb) +{ + int i, len; + + do { + len = get_bits(gb, 8); + if (8*len > get_bits_left(gb)) + return AVERROR_INVALIDDATA; + for (i = 0; i < len; i++) skip_bits(gb, 8); + } while(len); + + return 0; +} + + +/** + * Decode Indeo5 picture header. + * + * @param[in,out] ctx ptr to the decoder context + * @param[in] avctx ptr to the AVCodecContext + * @return result code: 0 = OK, -1 = error + */ +static int decode_pic_hdr(IVI45DecContext *ctx, AVCodecContext *avctx) +{ + int ret; + + if (get_bits(&ctx->gb, 5) != 0x1F) { + av_log(avctx, AV_LOG_ERROR, "Invalid picture start code!\n"); + return AVERROR_INVALIDDATA; + } + + ctx->prev_frame_type = ctx->frame_type; + ctx->frame_type = get_bits(&ctx->gb, 3); + if (ctx->frame_type >= 5) { + av_log(avctx, AV_LOG_ERROR, "Invalid frame type: %d \n", ctx->frame_type); + ctx->frame_type = FRAMETYPE_INTRA; + return AVERROR_INVALIDDATA; + } + + ctx->frame_num = get_bits(&ctx->gb, 8); + + if (ctx->frame_type == FRAMETYPE_INTRA) { + if ((ret = decode_gop_header(ctx, avctx)) < 0) { + av_log(avctx, AV_LOG_ERROR, "Invalid GOP header, skipping frames.\n"); + ctx->gop_invalid = 1; + return ret; + } + ctx->gop_invalid = 0; + } + + if (ctx->frame_type == FRAMETYPE_INTER_SCAL && !ctx->is_scalable) { + av_log(avctx, AV_LOG_ERROR, "Scalable inter frame in non scalable stream\n"); + ctx->frame_type = FRAMETYPE_INTER; + return AVERROR_INVALIDDATA; + } + + if (ctx->frame_type != FRAMETYPE_NULL) { + ctx->frame_flags = get_bits(&ctx->gb, 8); + + ctx->pic_hdr_size = (ctx->frame_flags & 1) ? get_bits(&ctx->gb, 24) : 0; + + ctx->checksum = (ctx->frame_flags & 0x10) ? get_bits(&ctx->gb, 16) : 0; + + /* skip unknown extension if any */ + if (ctx->frame_flags & 0x20) + skip_hdr_extension(&ctx->gb); /* XXX: untested */ + + /* decode macroblock huffman codebook */ + ret = ff_ivi_dec_huff_desc(&ctx->gb, ctx->frame_flags & 0x40, + IVI_MB_HUFF, &ctx->mb_vlc, avctx); + if (ret < 0) + return ret; + + skip_bits(&ctx->gb, 3); /* FIXME: unknown meaning! */ + } + + align_get_bits(&ctx->gb); + + return 0; +} + + +/** + * Decode Indeo5 band header. + * + * @param[in,out] ctx ptr to the decoder context + * @param[in,out] band ptr to the band descriptor + * @param[in] avctx ptr to the AVCodecContext + * @return result code: 0 = OK, -1 = error + */ +static int decode_band_hdr(IVI45DecContext *ctx, IVIBandDesc *band, + AVCodecContext *avctx) +{ + int i, ret; + uint8_t band_flags; + + band_flags = get_bits(&ctx->gb, 8); + + if (band_flags & 1) { + band->is_empty = 1; + return 0; + } + + band->data_size = (ctx->frame_flags & 0x80) ? get_bits(&ctx->gb, 24) : 0; + + band->inherit_mv = band_flags & 2; + band->inherit_qdelta = band_flags & 8; + band->qdelta_present = band_flags & 4; + if (!band->qdelta_present) band->inherit_qdelta = 1; + + /* decode rvmap probability corrections if any */ + band->num_corr = 0; /* there are no corrections */ + if (band_flags & 0x10) { + band->num_corr = get_bits(&ctx->gb, 8); /* get number of correction pairs */ + if (band->num_corr > 61) { + av_log(avctx, AV_LOG_ERROR, "Too many corrections: %d\n", + band->num_corr); + return AVERROR_INVALIDDATA; + } + + /* read correction pairs */ + for (i = 0; i < band->num_corr * 2; i++) + band->corr[i] = get_bits(&ctx->gb, 8); + } + + /* select appropriate rvmap table for this band */ + band->rvmap_sel = (band_flags & 0x40) ? get_bits(&ctx->gb, 3) : 8; + + /* decode block huffman codebook */ + ret = ff_ivi_dec_huff_desc(&ctx->gb, band_flags & 0x80, IVI_BLK_HUFF, + &band->blk_vlc, avctx); + if (ret < 0) + return ret; + + band->checksum_present = get_bits1(&ctx->gb); + if (band->checksum_present) + band->checksum = get_bits(&ctx->gb, 16); + + band->glob_quant = get_bits(&ctx->gb, 5); + + /* skip unknown extension if any */ + if (band_flags & 0x20) { /* XXX: untested */ + align_get_bits(&ctx->gb); + skip_hdr_extension(&ctx->gb); + } + + align_get_bits(&ctx->gb); + + return 0; +} + + +/** + * Decode info (block type, cbp, quant delta, motion vector) + * for all macroblocks in the current tile. + * + * @param[in,out] ctx ptr to the decoder context + * @param[in,out] band ptr to the band descriptor + * @param[in,out] tile ptr to the tile descriptor + * @param[in] avctx ptr to the AVCodecContext + * @return result code: 0 = OK, -1 = error + */ +static int decode_mb_info(IVI45DecContext *ctx, IVIBandDesc *band, + IVITile *tile, AVCodecContext *avctx) +{ + int x, y, mv_x, mv_y, mv_delta, offs, mb_offset, + mv_scale, blks_per_mb, s; + IVIMbInfo *mb, *ref_mb; + int row_offset = band->mb_size * band->pitch; + + mb = tile->mbs; + ref_mb = tile->ref_mbs; + offs = tile->ypos * band->pitch + tile->xpos; + + if (!ref_mb && + ((band->qdelta_present && band->inherit_qdelta) || band->inherit_mv)) + return AVERROR_INVALIDDATA; + + if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)) { + av_log(avctx, AV_LOG_ERROR, "Allocated tile size %d mismatches parameters %d\n", + tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, band->mb_size)); + return AVERROR_INVALIDDATA; + } + + /* scale factor for motion vectors */ + mv_scale = (ctx->planes[0].bands[0].mb_size >> 3) - (band->mb_size >> 3); + mv_x = mv_y = 0; + + for (y = tile->ypos; y < (tile->ypos + tile->height); y += band->mb_size) { + mb_offset = offs; + + for (x = tile->xpos; x < (tile->xpos + tile->width); x += band->mb_size) { + mb->xpos = x; + mb->ypos = y; + mb->buf_offs = mb_offset; + + if (get_bits1(&ctx->gb)) { + if (ctx->frame_type == FRAMETYPE_INTRA) { + av_log(avctx, AV_LOG_ERROR, "Empty macroblock in an INTRA picture!\n"); + return AVERROR_INVALIDDATA; + } + mb->type = 1; /* empty macroblocks are always INTER */ + mb->cbp = 0; /* all blocks are empty */ + + mb->q_delta = 0; + if (!band->plane && !band->band_num && (ctx->frame_flags & 8)) { + mb->q_delta = get_vlc2(&ctx->gb, ctx->mb_vlc.tab->table, + IVI_VLC_BITS, 1); + mb->q_delta = IVI_TOSIGNED(mb->q_delta); + } + + mb->mv_x = mb->mv_y = 0; /* no motion vector coded */ + if (band->inherit_mv && ref_mb){ + /* motion vector inheritance */ + if (mv_scale) { + mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale); + mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale); + } else { + mb->mv_x = ref_mb->mv_x; + mb->mv_y = ref_mb->mv_y; + } + } + } else { + if (band->inherit_mv && ref_mb) { + mb->type = ref_mb->type; /* copy mb_type from corresponding reference mb */ + } else if (ctx->frame_type == FRAMETYPE_INTRA) { + mb->type = 0; /* mb_type is always INTRA for intra-frames */ + } else { + mb->type = get_bits1(&ctx->gb); + } + + blks_per_mb = band->mb_size != band->blk_size ? 4 : 1; + mb->cbp = get_bits(&ctx->gb, blks_per_mb); + + mb->q_delta = 0; + if (band->qdelta_present) { + if (band->inherit_qdelta) { + if (ref_mb) mb->q_delta = ref_mb->q_delta; + } else if (mb->cbp || (!band->plane && !band->band_num && + (ctx->frame_flags & 8))) { + mb->q_delta = get_vlc2(&ctx->gb, ctx->mb_vlc.tab->table, + IVI_VLC_BITS, 1); + mb->q_delta = IVI_TOSIGNED(mb->q_delta); + } + } + + if (!mb->type) { + mb->mv_x = mb->mv_y = 0; /* there is no motion vector in intra-macroblocks */ + } else { + if (band->inherit_mv && ref_mb){ + /* motion vector inheritance */ + if (mv_scale) { + mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale); + mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale); + } else { + mb->mv_x = ref_mb->mv_x; + mb->mv_y = ref_mb->mv_y; + } + } else { + /* decode motion vector deltas */ + mv_delta = get_vlc2(&ctx->gb, ctx->mb_vlc.tab->table, + IVI_VLC_BITS, 1); + mv_y += IVI_TOSIGNED(mv_delta); + mv_delta = get_vlc2(&ctx->gb, ctx->mb_vlc.tab->table, + IVI_VLC_BITS, 1); + mv_x += IVI_TOSIGNED(mv_delta); + mb->mv_x = mv_x; + mb->mv_y = mv_y; + } + } + } + + s= band->is_halfpel; + if (mb->type) + if ( x + (mb->mv_x >>s) + (y+ (mb->mv_y >>s))*band->pitch < 0 || + x + ((mb->mv_x+s)>>s) + band->mb_size - 1 + + (y+band->mb_size - 1 +((mb->mv_y+s)>>s))*band->pitch > band->bufsize - 1) { + av_log(avctx, AV_LOG_ERROR, "motion vector %d %d outside reference\n", x*s + mb->mv_x, y*s + mb->mv_y); + return AVERROR_INVALIDDATA; + } + + mb++; + if (ref_mb) + ref_mb++; + mb_offset += band->mb_size; + } + + offs += row_offset; + } + + align_get_bits(&ctx->gb); + + return 0; +} + + +/** + * Switch buffers. + * + * @param[in,out] ctx ptr to the decoder context + */ +static void switch_buffers(IVI45DecContext *ctx) +{ + switch (ctx->prev_frame_type) { + case FRAMETYPE_INTRA: + case FRAMETYPE_INTER: + ctx->buf_switch ^= 1; + ctx->dst_buf = ctx->buf_switch; + ctx->ref_buf = ctx->buf_switch ^ 1; + break; + case FRAMETYPE_INTER_SCAL: + if (!ctx->inter_scal) { + ctx->ref2_buf = 2; + ctx->inter_scal = 1; + } + FFSWAP(int, ctx->dst_buf, ctx->ref2_buf); + ctx->ref_buf = ctx->ref2_buf; + break; + case FRAMETYPE_INTER_NOREF: + break; + } + + switch (ctx->frame_type) { + case FRAMETYPE_INTRA: + ctx->buf_switch = 0; + /* FALLTHROUGH */ + case FRAMETYPE_INTER: + ctx->inter_scal = 0; + ctx->dst_buf = ctx->buf_switch; + ctx->ref_buf = ctx->buf_switch ^ 1; + break; + case FRAMETYPE_INTER_SCAL: + case FRAMETYPE_INTER_NOREF: + case FRAMETYPE_NULL: + break; + } +} + + +static int is_nonnull_frame(IVI45DecContext *ctx) +{ + return ctx->frame_type != FRAMETYPE_NULL; +} + + +/** + * Initialize Indeo5 decoder. + */ +int indeo5_decode_init(AVCodecContext *avctx) +{ + IVI45DecContext *ctx; + int result; + + if (!(ctx = calloc(1, sizeof(IVI45DecContext)))) + return AVERROR(ENOMEM); + + ctx->gop_invalid = 1; + + ff_ivi_init_static_vlc(); + + /* copy rvmap tables in our context so we can apply changes to them */ + memcpy(ctx->rvmap_tabs, ff_ivi_rvmap_tabs, sizeof(ff_ivi_rvmap_tabs)); + + /* set the initial picture layout according to the basic profile: + there is only one band per plane (no scalability), only one tile (no local decoding) + and picture format = YVU9 */ + ctx->pic_conf.pic_width = avctx->width; + ctx->pic_conf.pic_height = avctx->height; + ctx->pic_conf.chroma_width = (avctx->width + 3) >> 2; + ctx->pic_conf.chroma_height = (avctx->height + 3) >> 2; + ctx->pic_conf.tile_width = avctx->width; + ctx->pic_conf.tile_height = avctx->height; + ctx->pic_conf.luma_bands = ctx->pic_conf.chroma_bands = 1; + + result = ff_ivi_init_planes(avctx, ctx->planes, &ctx->pic_conf, 0); + if (result) { + av_log(avctx, AV_LOG_ERROR, "Couldn't allocate color planes!\n"); + free(ctx); + return result; + } + + ctx->buf_switch = 0; + ctx->inter_scal = 0; + + ctx->decode_pic_hdr = decode_pic_hdr; + ctx->decode_band_hdr = decode_band_hdr; + ctx->decode_mb_info = decode_mb_info; + ctx->switch_buffers = switch_buffers; + ctx->is_nonnull_frame = is_nonnull_frame; + + avctx->priv_data = ctx; + + return 0; +} diff --git a/libs/ffmpegindeo/indeo5.h b/libs/ffmpegindeo/indeo5.h new file mode 100644 index 00000000000..2570683bae9 --- /dev/null +++ b/libs/ffmpegindeo/indeo5.h @@ -0,0 +1,9 @@ +#ifndef __INDEO5_H +#define __INDEO5_H + +#include "indeo_compat.h" +#include "ivi.h" + +int indeo5_decode_init(AVCodecContext *avctx); + +#endif /* __INDEO5_H */ diff --git a/libs/ffmpegindeo/indeo_compat.h b/libs/ffmpegindeo/indeo_compat.h new file mode 100644 index 00000000000..64fdbe5c960 --- /dev/null +++ b/libs/ffmpegindeo/indeo_compat.h @@ -0,0 +1,96 @@ +/* + * Copyright 2022 Shaun Ren for CodeWeavers + * + * This library 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. + * + * This library 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 this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#ifndef __IR50_COMPAT_H +#define __IR50_COMPAT_H + +#include <stdint.h> +#include <stdlib.h> +#include <assert.h> +#include <errno.h> + +#include "windef.h" +#include "wingdi.h" +#include "vfw.h" + +#define av_assert0 assert +#define av_assert1 assert +#define av_assert2 assert + +#if defined(__GNUC__) || defined(__clang__) +# define av_always_inline inline __attribute__((always_inline)) +#else +# define av_always_inline inline +#endif + +#define av_mallocz(sz) calloc(1, sz) +#define av_calloc calloc +#define av_free free +#define av_freep(p) free(*((void **)(p))) + +#define av_log(a, ...) ((void)0) +#define ff_dlog(a, ...) ((void)0) +#define avpriv_request_sample(a, ...) ((void)0) +#define avpriv_report_missing_feature(a, ...) ((void)0) + +static av_always_inline int _averror(int err) +{ + if (err == ENOMEM) return ICERR_MEMORY; + if (err == EINVAL) return ICERR_BADPARAM; + return ICERR_ERROR; +} +#define AVERROR _averror + +#define AVERROR_INVALIDDATA ICERR_BADPARAM +#define AVERROR_PATCHWELCOME ICERR_UNSUPPORTED +#define AVERROR_INTERNAL ICERR_INTERNAL + +#define FFMAX(a, b) ((a) > (b) ? (a) : (b)) +#define FFMIN(a, b) ((a) > (b) ? (b) : (a)) +#define FFSIGN(a) ((a) > 0 ? 1 : -1) +#define FFALIGN(x, a) (((x)+(a)-1)&~((a)-1)) + +#define FFSWAP(type, a, b) do{ type tmp = b; b = a; a = tmp; } while(0) + +#define AV_QSORT(p, num, type, cmp) qsort(p, num, sizeof(type), cmp) + +static av_always_inline int av_clip(int a, int amin, int amax) +{ + if (a < amin) return amin; + if (a > amax) return amax; + return a; +} + +#define av_clip_uint8(a) ((uint8_t)av_clip(a, 0, 255)) + +typedef struct AVFrame { + uint8_t *data[3]; + int linesize[3]; + int width, height; +} AVFrame; + +typedef struct AVCodecContext { + int width, height; + void *priv_data; + + int out_bitcount; + uint8_t *out_buf; + int8_t *dither_buf; +} AVCodecContext; + +#endif /* __IR50_COMPAT_H */ diff --git a/libs/ffmpegindeo/ivi.c b/libs/ffmpegindeo/ivi.c new file mode 100644 index 00000000000..0ad8c4b9389 --- /dev/null +++ b/libs/ffmpegindeo/ivi.c @@ -0,0 +1,1572 @@ +/* + * common functions for Indeo Video Interactive codecs (Indeo4 and Indeo5) + * + * Copyright (c) 2009 Maxim Poliakovski + * + * 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 + * This file contains functions and data shared by both Indeo4 and + * Indeo5 decoders. + */ + +#include <inttypes.h> +#include "indeo_compat.h" + +#include "get_bits.h" +#include "ivi.h" +#include "ivi_dsp.h" + +/** + * These are 2x8 predefined Huffman codebooks for coding macroblock/block + * signals. They are specified using "huffman descriptors" in order to + * avoid huge static tables. The decoding tables will be generated at + * startup from these descriptors. + */ +/** static macroblock huffman tables */ +static const IVIHuffDesc ivi_mb_huff_desc[8] = { + {8, {0, 4, 5, 4, 4, 4, 6, 6}}, + {12, {0, 2, 2, 3, 3, 3, 3, 5, 3, 2, 2, 2}}, + {12, {0, 2, 3, 4, 3, 3, 3, 3, 4, 3, 2, 2}}, + {12, {0, 3, 4, 4, 3, 3, 3, 3, 3, 2, 2, 2}}, + {13, {0, 4, 4, 3, 3, 3, 3, 2, 3, 3, 2, 1, 1}}, + {9, {0, 4, 4, 4, 4, 3, 3, 3, 2}}, + {10, {0, 4, 4, 4, 4, 3, 3, 2, 2, 2}}, + {12, {0, 4, 4, 4, 3, 3, 2, 3, 2, 2, 2, 2}} +}; + +/** static block huffman tables */ +static const IVIHuffDesc ivi_blk_huff_desc[8] = { + {10, {1, 2, 3, 4, 4, 7, 5, 5, 4, 1}}, + {11, {2, 3, 4, 4, 4, 7, 5, 4, 3, 3, 2}}, + {12, {2, 4, 5, 5, 5, 5, 6, 4, 4, 3, 1, 1}}, + {13, {3, 3, 4, 4, 5, 6, 6, 4, 4, 3, 2, 1, 1}}, + {11, {3, 4, 4, 5, 5, 5, 6, 5, 4, 2, 2}}, + {13, {3, 4, 5, 5, 5, 5, 6, 4, 3, 3, 2, 1, 1}}, + {13, {3, 4, 5, 5, 5, 6, 5, 4, 3, 3, 2, 1, 1}}, + {9, {3, 4, 4, 5, 5, 5, 6, 5, 5}} +}; + +static VLC ivi_mb_vlc_tabs [8]; ///< static macroblock Huffman tables +static VLC ivi_blk_vlc_tabs[8]; ///< static block Huffman tables + +typedef void (*ivi_mc_func) (int16_t *buf, const int16_t *ref_buf, + ptrdiff_t pitch, int mc_type); +typedef void (*ivi_mc_avg_func) (int16_t *buf, const int16_t *ref_buf1, + const int16_t *ref_buf2, + ptrdiff_t pitch, int mc_type, int mc_type2); + +static int ivi_mc(const IVIBandDesc *band, ivi_mc_func mc, ivi_mc_avg_func mc_avg, + int offs, int mv_x, int mv_y, int mv_x2, int mv_y2, + int mc_type, int mc_type2) +{ + int ref_offs = offs + mv_y * band->pitch + mv_x; + int buf_size = band->pitch * band->aheight; + int min_size = band->pitch * (band->blk_size - 1) + band->blk_size; + int ref_size = (mc_type > 1) * band->pitch + (mc_type & 1); + + if (mc_type != -1) { + av_assert0(offs >= 0 && ref_offs >= 0 && band->ref_buf); + av_assert0(buf_size - min_size >= offs); + av_assert0(buf_size - min_size - ref_size >= ref_offs); + } + + if (mc_type2 == -1) { + mc(band->buf + offs, band->ref_buf + ref_offs, band->pitch, mc_type); + } else { + int ref_offs2 = offs + mv_y2 * band->pitch + mv_x2; + int ref_size2 = (mc_type2 > 1) * band->pitch + (mc_type2 & 1); + if (offs < 0 || ref_offs2 < 0 || !band->b_ref_buf) + return AVERROR_INVALIDDATA; + if (buf_size - min_size - ref_size2 < ref_offs2) + return AVERROR_INVALIDDATA; + + if (mc_type == -1) + mc(band->buf + offs, band->b_ref_buf + ref_offs2, + band->pitch, mc_type2); + else + mc_avg(band->buf + offs, band->ref_buf + ref_offs, + band->b_ref_buf + ref_offs2, band->pitch, + mc_type, mc_type2); + } + + return 0; +} + +/* + * Generate a huffman codebook from the given descriptor + * and convert it into the FFmpeg VLC table. + * + * @param[in] cb pointer to codebook descriptor + * @param[out] vlc where to place the generated VLC table + * @param[in] flag flag: 1 - for static or 0 for dynamic tables + * @return result code: 0 - OK, -1 = error (invalid codebook descriptor) + */ +static int ivi_create_huff_from_desc(const IVIHuffDesc *cb, VLC *vlc, int flag) +{ + int pos, i, j, codes_per_row, prefix, not_last_row; + uint16_t codewords[256]; /* FIXME: move this temporal storage out? */ + uint8_t bits[256]; + + pos = 0; /* current position = 0 */ + + for (i = 0; i < cb->num_rows; i++) { + codes_per_row = 1 << cb->xbits[i]; + not_last_row = (i != cb->num_rows - 1); + prefix = ((1 << i) - 1) << (cb->xbits[i] + not_last_row); + + for (j = 0; j < codes_per_row; j++) { + if (pos >= 256) /* Some Indeo5 codebooks can have more than 256 */ + break; /* elements, but only 256 codes are allowed! */ + + bits[pos] = i + cb->xbits[i] + not_last_row; + if (bits[pos] > IVI_VLC_BITS) + return AVERROR_INVALIDDATA; /* invalid descriptor */ + + codewords[pos] = prefix | j; + if (!bits[pos]) + bits[pos] = 1; + + pos++; + }//for j + }//for i + + /* number of codewords = pos */ + return init_vlc(vlc, IVI_VLC_BITS, pos, bits, 1, 1, codewords, 2, 2, + (flag ? INIT_VLC_USE_NEW_STATIC : 0) | INIT_VLC_OUTPUT_LE); +} + +static void ivi_init_static_vlc(void) +{ + int i; + static VLCElem table_data[8192 * 16]; + + for (i = 0; i < 8; i++) { + ivi_mb_vlc_tabs[i].table = table_data + i * 2 * 8192; + ivi_mb_vlc_tabs[i].table_allocated = 8192; + ivi_create_huff_from_desc(&ivi_mb_huff_desc[i], + &ivi_mb_vlc_tabs[i], 1); + ivi_blk_vlc_tabs[i].table = table_data + (i * 2 + 1) * 8192; + ivi_blk_vlc_tabs[i].table_allocated = 8192; + ivi_create_huff_from_desc(&ivi_blk_huff_desc[i], + &ivi_blk_vlc_tabs[i], 1); + } +} + +void ff_ivi_init_static_vlc(void) +{ + static INIT_ONCE init_static_once = INIT_ONCE_STATIC_INIT; + BOOL pending = FALSE; + + InitOnceBeginInitialize(&init_static_once, 0, &pending, NULL); + if (pending) + ivi_init_static_vlc(); + InitOnceComplete(&init_static_once, 0, NULL); +} + +/* + * Copy huffman codebook descriptors. + * + * @param[out] dst ptr to the destination descriptor + * @param[in] src ptr to the source descriptor + */ +static void ivi_huff_desc_copy(IVIHuffDesc *dst, const IVIHuffDesc *src) +{ + dst->num_rows = src->num_rows; + memcpy(dst->xbits, src->xbits, src->num_rows); +} + +/* + * Compare two huffman codebook descriptors. + * + * @param[in] desc1 ptr to the 1st descriptor to compare + * @param[in] desc2 ptr to the 2nd descriptor to compare + * @return comparison result: 0 - equal, 1 - not equal + */ +static int ivi_huff_desc_cmp(const IVIHuffDesc *desc1, + const IVIHuffDesc *desc2) +{ + return desc1->num_rows != desc2->num_rows || + memcmp(desc1->xbits, desc2->xbits, desc1->num_rows); +} + +int ff_ivi_dec_huff_desc(GetBitContext *gb, int desc_coded, int which_tab, + IVIHuffTab *huff_tab, AVCodecContext *avctx) +{ + int i, result; + IVIHuffDesc new_huff; + + if (!desc_coded) { + /* select default table */ + huff_tab->tab = (which_tab) ? &ivi_blk_vlc_tabs[7] + : &ivi_mb_vlc_tabs [7]; + return 0; + } + + huff_tab->tab_sel = get_bits(gb, 3); + if (huff_tab->tab_sel == 7) { + /* custom huffman table (explicitly encoded) */ + new_huff.num_rows = get_bits(gb, 4); + if (!new_huff.num_rows) { + av_log(avctx, AV_LOG_ERROR, "Empty custom Huffman table!\n"); + return AVERROR_INVALIDDATA; + } + + for (i = 0; i < new_huff.num_rows; i++) + new_huff.xbits[i] = get_bits(gb, 4); + + /* Have we got the same custom table? Rebuild if not. */ + if (ivi_huff_desc_cmp(&new_huff, &huff_tab->cust_desc) || !huff_tab->cust_tab.table) { + ivi_huff_desc_copy(&huff_tab->cust_desc, &new_huff); + + if (huff_tab->cust_tab.table) + ff_free_vlc(&huff_tab->cust_tab); + result = ivi_create_huff_from_desc(&huff_tab->cust_desc, + &huff_tab->cust_tab, 0); + if (result) { + // reset faulty description + huff_tab->cust_desc.num_rows = 0; + av_log(avctx, AV_LOG_ERROR, + "Error while initializing custom vlc table!\n"); + return result; + } + } + huff_tab->tab = &huff_tab->cust_tab; + } else { + /* select one of predefined tables */ + huff_tab->tab = (which_tab) ? &ivi_blk_vlc_tabs[huff_tab->tab_sel] + : &ivi_mb_vlc_tabs [huff_tab->tab_sel]; + } + + return 0; +} + +/* + * Free planes, bands and macroblocks buffers. + * + * @param[in] planes pointer to the array of the plane descriptors + */ +static void ivi_free_buffers(IVIPlaneDesc *planes) +{ + int p, b, t; + + for (p = 0; p < 3; p++) { + if (planes[p].bands) { + for (b = 0; b < planes[p].num_bands; b++) { + IVIBandDesc *band = &planes[p].bands[b]; + av_freep(&band->bufs[0]); + av_freep(&band->bufs[1]); + av_freep(&band->bufs[2]); + av_freep(&band->bufs[3]); + + if (band->blk_vlc.cust_tab.table) + ff_free_vlc(&band->blk_vlc.cust_tab); + for (t = 0; t < band->num_tiles; t++) + av_freep(&band->tiles[t].mbs); + av_freep(&band->tiles); + } + } + av_freep(&planes[p].bands); + planes[p].num_bands = 0; + } +} + +int ff_ivi_init_planes(AVCodecContext *avctx, IVIPlaneDesc *planes, const IVIPicConfig *cfg, + int is_indeo4) +{ + int p, b; + uint32_t b_width, b_height, align_fac, width_aligned, + height_aligned, buf_size; + IVIBandDesc *band; + + ivi_free_buffers(planes); + + if (/* av_image_check_size2(cfg->pic_width, cfg->pic_height, avctx->max_pixels, AV_PIX_FMT_YUV410P, 0, avctx) < 0 || */ + cfg->luma_bands < 1 || cfg->chroma_bands < 1) + return AVERROR_INVALIDDATA; + + /* fill in the descriptor of the luminance plane */ + planes[0].width = cfg->pic_width; + planes[0].height = cfg->pic_height; + planes[0].num_bands = cfg->luma_bands; + + /* fill in the descriptors of the chrominance planes */ + planes[1].width = planes[2].width = (cfg->pic_width + 3) >> 2; + planes[1].height = planes[2].height = (cfg->pic_height + 3) >> 2; + planes[1].num_bands = planes[2].num_bands = cfg->chroma_bands; + + for (p = 0; p < 3; p++) { + planes[p].bands = av_calloc(planes[p].num_bands, sizeof(*planes[p].bands)); + if (!planes[p].bands) + return AVERROR(ENOMEM); + + /* select band dimensions: if there is only one band then it + * has the full size, if there are several bands each of them + * has only half size */ + b_width = planes[p].num_bands == 1 ? planes[p].width + : (planes[p].width + 1) >> 1; + b_height = planes[p].num_bands == 1 ? planes[p].height + : (planes[p].height + 1) >> 1; + + /* luma band buffers will be aligned on 16x16 (max macroblock size) */ + /* chroma band buffers will be aligned on 8x8 (max macroblock size) */ + align_fac = p ? 8 : 16; + width_aligned = FFALIGN(b_width , align_fac); + height_aligned = FFALIGN(b_height, align_fac); + buf_size = width_aligned * height_aligned * sizeof(int16_t); + + for (b = 0; b < planes[p].num_bands; b++) { + band = &planes[p].bands[b]; /* select appropriate plane/band */ + band->plane = p; + band->band_num = b; + band->width = b_width; + band->height = b_height; + band->pitch = width_aligned; + band->aheight = height_aligned; + av_assert0(!band->bufs[0] && !band->bufs[1] && + !band->bufs[2] && !band->bufs[3]); + band->bufsize = buf_size/2; + av_assert0(buf_size % 2 == 0); + + /* reset custom vlc */ + planes[p].bands[0].blk_vlc.cust_desc.num_rows = 0; + } + } + + return 0; +} + +static int ivi_init_tiles(const IVIBandDesc *band, IVITile *ref_tile, + int p, int b, int t_height, int t_width) +{ + int x, y; + IVITile *tile = band->tiles; + + for (y = 0; y < band->height; y += t_height) { + for (x = 0; x < band->width; x += t_width) { + tile->xpos = x; + tile->ypos = y; + tile->mb_size = band->mb_size; + tile->width = FFMIN(band->width - x, t_width); + tile->height = FFMIN(band->height - y, t_height); + tile->is_empty = tile->data_size = 0; + /* calculate number of macroblocks */ + tile->num_MBs = IVI_MBs_PER_TILE(tile->width, tile->height, + band->mb_size); + + av_freep(&tile->mbs); + tile->mbs = av_calloc(tile->num_MBs, sizeof(*tile->mbs)); + if (!tile->mbs) + return AVERROR(ENOMEM); + + tile->ref_mbs = 0; + if (p || b) { + if (tile->num_MBs != ref_tile->num_MBs) { + av_log(NULL, AV_LOG_DEBUG, "ref_tile mismatch\n"); + return AVERROR_INVALIDDATA; + } + tile->ref_mbs = ref_tile->mbs; + ref_tile++; + } + tile++; + } + } + + return 0; +} + +int ff_ivi_init_tiles(IVIPlaneDesc *planes, + int tile_width, int tile_height) +{ + int p, b, x_tiles, y_tiles, t_width, t_height, ret; + IVIBandDesc *band; + + for (p = 0; p < 3; p++) { + t_width = !p ? tile_width : (tile_width + 3) >> 2; + t_height = !p ? tile_height : (tile_height + 3) >> 2; + + if (!p && planes[0].num_bands == 4) { + if (t_width % 2 || t_height % 2) { + avpriv_request_sample(NULL, "Odd tiles"); + return AVERROR_PATCHWELCOME; + } + t_width >>= 1; + t_height >>= 1; + } + if(t_width<=0 || t_height<=0) + return AVERROR(EINVAL); + + for (b = 0; b < planes[p].num_bands; b++) { + band = &planes[p].bands[b]; + + if (band->tiles) { + int t; + for (t = 0; t < band->num_tiles; t++) { + av_freep(&band->tiles[t].mbs); + } + } + + x_tiles = IVI_NUM_TILES(band->width, t_width); + y_tiles = IVI_NUM_TILES(band->height, t_height); + band->num_tiles = x_tiles * y_tiles; + + av_freep(&band->tiles); + band->tiles = av_calloc(band->num_tiles, sizeof(*band->tiles)); + if (!band->tiles) { + band->num_tiles = 0; + return AVERROR(ENOMEM); + } + + /* use the first luma band as reference for motion vectors + * and quant */ + ret = ivi_init_tiles(band, planes[0].bands[0].tiles, + p, b, t_height, t_width); + if (ret < 0) + return ret; + } + } + + return 0; +} + +/* + * Decode size of the tile data. + * The size is stored as a variable-length field having the following format: + * if (tile_data_size < 255) than this field is only one byte long + * if (tile_data_size >= 255) than this field four is byte long: 0xFF X1 X2 X3 + * where X1-X3 is size of the tile data + * + * @param[in,out] gb the GetBit context + * @return size of the tile data in bytes + */ +static int ivi_dec_tile_data_size(GetBitContext *gb) +{ + int len; + + len = 0; + if (get_bits1(gb)) { + len = get_bits(gb, 8); + if (len == 255) + len = get_bits(gb, 24); + } + + /* align the bitstream reader on the byte boundary */ + align_get_bits(gb); + + return len; +} + +static int ivi_dc_transform(const IVIBandDesc *band, int *prev_dc, int buf_offs, + int blk_size) +{ + band->dc_transform(prev_dc, band->buf + buf_offs, + band->pitch, blk_size); + + return 0; +} + +static int ivi_decode_coded_blocks(GetBitContext *gb, const IVIBandDesc *band, + ivi_mc_func mc, ivi_mc_avg_func mc_avg, + int mv_x, int mv_y, + int mv_x2, int mv_y2, + int *prev_dc, int is_intra, + int mc_type, int mc_type2, + uint32_t quant, int offs, + AVCodecContext *avctx) +{ + const uint16_t *base_tab = is_intra ? band->intra_base : band->inter_base; + RVMapDesc *rvmap = band->rv_map; + uint8_t col_flags[8]; + int32_t trvec[64]; + uint32_t sym = 0, lo, hi, q; + int pos, run, val; + int blk_size = band->blk_size; + int num_coeffs = blk_size * blk_size; + int col_mask = blk_size - 1; + int scan_pos = -1; + int min_size = band->pitch * (band->transform_size - 1) + + band->transform_size; + int buf_size = band->pitch * band->aheight - offs; + + if (min_size > buf_size) + return AVERROR_INVALIDDATA; + + if (!band->scan) { + av_log(avctx, AV_LOG_ERROR, "Scan pattern is not set.\n"); + return AVERROR_INVALIDDATA; + } + + /* zero transform vector */ + memset(trvec, 0, num_coeffs * sizeof(trvec[0])); + /* zero column flags */ + memset(col_flags, 0, sizeof(col_flags)); + while (scan_pos <= num_coeffs) { + sym = get_vlc2(gb, band->blk_vlc.tab->table, + IVI_VLC_BITS, 1); + if (sym == rvmap->eob_sym) + break; /* End of block */ + + /* Escape - run/val explicitly coded using 3 vlc codes */ + if (sym == rvmap->esc_sym) { + run = get_vlc2(gb, band->blk_vlc.tab->table, IVI_VLC_BITS, 1) + 1; + lo = get_vlc2(gb, band->blk_vlc.tab->table, IVI_VLC_BITS, 1); + hi = get_vlc2(gb, band->blk_vlc.tab->table, IVI_VLC_BITS, 1); + /* merge them and convert into signed val */ + val = IVI_TOSIGNED((hi << 6) | lo); + } else { + if (sym >= 256U) { + av_log(avctx, AV_LOG_ERROR, "Invalid sym encountered: %"PRIu32".\n", sym); + return AVERROR_INVALIDDATA; + } + run = rvmap->runtab[sym]; + val = rvmap->valtab[sym]; + } + + /* de-zigzag and dequantize */ + scan_pos += run; + if (scan_pos >= num_coeffs || scan_pos < 0) + break; + pos = band->scan[scan_pos]; + + if (!val) + ff_dlog(avctx, "Val = 0 encountered!\n"); + + q = (base_tab[pos] * quant) >> 9; + if (q > 1) + val = val * q + FFSIGN(val) * (((q ^ 1) - 1) >> 1); + trvec[pos] = val; + /* track columns containing non-zero coeffs */ + col_flags[pos & col_mask] |= !!val; + } + + if (scan_pos < 0 || (scan_pos >= num_coeffs && sym != rvmap->eob_sym)) + return AVERROR_INVALIDDATA; /* corrupt block data */ + + /* undoing DC coeff prediction for intra-blocks */ + if (is_intra && band->is_2d_trans) { + *prev_dc += trvec[0]; + trvec[0] = *prev_dc; + col_flags[0] |= !!*prev_dc; + } + + if(band->transform_size > band->blk_size){ + av_log(NULL, AV_LOG_ERROR, "Too large transform\n"); + return AVERROR_INVALIDDATA; + } + + /* apply inverse transform */ + band->inv_transform(trvec, band->buf + offs, + band->pitch, col_flags); + + /* apply motion compensation */ + if (!is_intra) + return ivi_mc(band, mc, mc_avg, offs, mv_x, mv_y, mv_x2, mv_y2, + mc_type, mc_type2); + + return 0; +} +/* + * Decode block data: + * extract huffman-coded transform coefficients from the bitstream, + * dequantize them, apply inverse transform and motion compensation + * in order to reconstruct the picture. + * + * @param[in,out] gb the GetBit context + * @param[in] band pointer to the band descriptor + * @param[in] tile pointer to the tile descriptor + * @return result code: 0 - OK, -1 = error (corrupted blocks data) + */ +static int ivi_decode_blocks(GetBitContext *gb, const IVIBandDesc *band, + IVITile *tile, AVCodecContext *avctx) +{ + int mbn, blk, num_blocks, blk_size, ret, is_intra; + int mc_type = 0, mc_type2 = -1; + int mv_x = 0, mv_y = 0, mv_x2 = 0, mv_y2 = 0; + int32_t prev_dc; + uint32_t cbp, quant, buf_offs; + IVIMbInfo *mb; + ivi_mc_func mc_with_delta_func, mc_no_delta_func; + ivi_mc_avg_func mc_avg_with_delta_func, mc_avg_no_delta_func; + const uint8_t *scale_tab; + + /* init intra prediction for the DC coefficient */ + prev_dc = 0; + blk_size = band->blk_size; + /* number of blocks per mb */ + num_blocks = (band->mb_size != blk_size) ? 4 : 1; + if (blk_size == 8) { + mc_with_delta_func = ff_ivi_mc_8x8_delta; + mc_no_delta_func = ff_ivi_mc_8x8_no_delta; + mc_avg_with_delta_func = ff_ivi_mc_avg_8x8_delta; + mc_avg_no_delta_func = ff_ivi_mc_avg_8x8_no_delta; + } else { + mc_with_delta_func = ff_ivi_mc_4x4_delta; + mc_no_delta_func = ff_ivi_mc_4x4_no_delta; + mc_avg_with_delta_func = ff_ivi_mc_avg_4x4_delta; + mc_avg_no_delta_func = ff_ivi_mc_avg_4x4_no_delta; + } + + for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) { + is_intra = !mb->type; + cbp = mb->cbp; + buf_offs = mb->buf_offs; + + quant = band->glob_quant + mb->q_delta; + quant = av_clip(quant, 0, 23); + + scale_tab = is_intra ? band->intra_scale : band->inter_scale; + if (scale_tab) + quant = scale_tab[quant]; + + if (!is_intra) { + mv_x = mb->mv_x; + mv_y = mb->mv_y; + mv_x2 = mb->b_mv_x; + mv_y2 = mb->b_mv_y; + if (band->is_halfpel) { + mc_type = ((mv_y & 1) << 1) | (mv_x & 1); + mc_type2 = ((mv_y2 & 1) << 1) | (mv_x2 & 1); + mv_x >>= 1; + mv_y >>= 1; + mv_x2 >>= 1; + mv_y2 >>= 1; /* convert halfpel vectors into fullpel ones */ + } + if (mb->type == 2) + mc_type = -1; + if (mb->type != 2 && mb->type != 3) + mc_type2 = -1; + if (mb->type) { + int dmv_x, dmv_y, cx, cy; + + dmv_x = mb->mv_x >> band->is_halfpel; + dmv_y = mb->mv_y >> band->is_halfpel; + cx = mb->mv_x & band->is_halfpel; + cy = mb->mv_y & band->is_halfpel; + + if (mb->xpos + dmv_x < 0 || + mb->xpos + dmv_x + band->mb_size + cx > band->pitch || + mb->ypos + dmv_y < 0 || + mb->ypos + dmv_y + band->mb_size + cy > band->aheight) { + return AVERROR_INVALIDDATA; + } + } + if (mb->type == 2 || mb->type == 3) { + int dmv_x, dmv_y, cx, cy; + + dmv_x = mb->b_mv_x >> band->is_halfpel; + dmv_y = mb->b_mv_y >> band->is_halfpel; + cx = mb->b_mv_x & band->is_halfpel; + cy = mb->b_mv_y & band->is_halfpel; + + if (mb->xpos + dmv_x < 0 || + mb->xpos + dmv_x + band->mb_size + cx > band->pitch || + mb->ypos + dmv_y < 0 || + mb->ypos + dmv_y + band->mb_size + cy > band->aheight) { + return AVERROR_INVALIDDATA; + } + } + } + + for (blk = 0; blk < num_blocks; blk++) { + /* adjust block position in the buffer according to its number */ + if (blk & 1) { + buf_offs += blk_size; + } else if (blk == 2) { + buf_offs -= blk_size; + buf_offs += blk_size * band->pitch; + } + + if (cbp & 1) { /* block coded ? */ + ret = ivi_decode_coded_blocks(gb, band, mc_with_delta_func, + mc_avg_with_delta_func, + mv_x, mv_y, mv_x2, mv_y2, + &prev_dc, is_intra, + mc_type, mc_type2, quant, + buf_offs, avctx); + if (ret < 0) + return ret; + } else { + int buf_size = band->pitch * band->aheight - buf_offs; + int min_size = (blk_size - 1) * band->pitch + blk_size; + + if (min_size > buf_size) + return AVERROR_INVALIDDATA; + /* block not coded */ + /* for intra blocks apply the dc slant transform */ + /* for inter - perform the motion compensation without delta */ + if (is_intra) { + ret = ivi_dc_transform(band, &prev_dc, buf_offs, blk_size); + if (ret < 0) + return ret; + } else { + ret = ivi_mc(band, mc_no_delta_func, mc_avg_no_delta_func, + buf_offs, mv_x, mv_y, mv_x2, mv_y2, + mc_type, mc_type2); + if (ret < 0) + return ret; + } + } + + cbp >>= 1; + }// for blk + }// for mbn + + align_get_bits(gb); + + return 0; +} + +/** + * Handle empty tiles by performing data copying and motion + * compensation respectively. + * + * @param[in] avctx ptr to the AVCodecContext + * @param[in] band pointer to the band descriptor + * @param[in] tile pointer to the tile descriptor + * @param[in] mv_scale scaling factor for motion vectors + */ +static int ivi_process_empty_tile(AVCodecContext *avctx, const IVIBandDesc *band, + IVITile *tile, int32_t mv_scale) +{ + int x, y, need_mc, mbn, blk, num_blocks, mv_x, mv_y, mc_type; + int offs, mb_offset, row_offset, ret; + IVIMbInfo *mb, *ref_mb; + const int16_t *src; + int16_t *dst; + ivi_mc_func mc_no_delta_func; + int clear_first = !band->qdelta_present && !band->plane && !band->band_num; + int mb_size = band->mb_size; + int xend = tile->xpos + tile->width; + int is_halfpel = band->is_halfpel; + int pitch = band->pitch; + + if (tile->num_MBs != IVI_MBs_PER_TILE(tile->width, tile->height, mb_size)) { + av_log(avctx, AV_LOG_ERROR, "Allocated tile size %d mismatches " + "parameters %d in ivi_process_empty_tile()\n", + tile->num_MBs, IVI_MBs_PER_TILE(tile->width, tile->height, mb_size)); + return AVERROR_INVALIDDATA; + } + + offs = tile->ypos * pitch + tile->xpos; + mb = tile->mbs; + ref_mb = tile->ref_mbs; + row_offset = mb_size * pitch; + need_mc = 0; /* reset the mc tracking flag */ + + for (y = tile->ypos; y < (tile->ypos + tile->height); y += mb_size) { + mb_offset = offs; + + for (x = tile->xpos; x < xend; x += mb_size) { + mb->xpos = x; + mb->ypos = y; + mb->buf_offs = mb_offset; + + mb->type = 1; /* set the macroblocks type = INTER */ + mb->cbp = 0; /* all blocks are empty */ + + if (clear_first) { + mb->q_delta = band->glob_quant; + mb->mv_x = 0; + mb->mv_y = 0; + } + + if (ref_mb) { + if (band->inherit_qdelta) + mb->q_delta = ref_mb->q_delta; + + if (band->inherit_mv) { + /* motion vector inheritance */ + if (mv_scale) { + mb->mv_x = ivi_scale_mv(ref_mb->mv_x, mv_scale); + mb->mv_y = ivi_scale_mv(ref_mb->mv_y, mv_scale); + } else { + mb->mv_x = ref_mb->mv_x; + mb->mv_y = ref_mb->mv_y; + } + need_mc |= mb->mv_x || mb->mv_y; /* tracking non-zero motion vectors */ + { + int dmv_x, dmv_y, cx, cy; + + dmv_x = mb->mv_x >> is_halfpel; + dmv_y = mb->mv_y >> is_halfpel; + cx = mb->mv_x & is_halfpel; + cy = mb->mv_y & is_halfpel; + + if ( mb->xpos + dmv_x < 0 + || mb->xpos + dmv_x + mb_size + cx > pitch + || mb->ypos + dmv_y < 0 + || mb->ypos + dmv_y + mb_size + cy > band->aheight) { + av_log(avctx, AV_LOG_ERROR, "MV out of bounds\n"); + return AVERROR_INVALIDDATA; + } + } + } + ref_mb++; + } + + mb++; + mb_offset += mb_size; + } // for x + offs += row_offset; + } // for y + + if (band->inherit_mv && need_mc) { /* apply motion compensation if there is at least one non-zero motion vector */ + num_blocks = (mb_size != band->blk_size) ? 4 : 1; /* number of blocks per mb */ + mc_no_delta_func = (band->blk_size == 8) ? ff_ivi_mc_8x8_no_delta + : ff_ivi_mc_4x4_no_delta; + + for (mbn = 0, mb = tile->mbs; mbn < tile->num_MBs; mb++, mbn++) { + mv_x = mb->mv_x; + mv_y = mb->mv_y; + if (!band->is_halfpel) { + mc_type = 0; /* we have only fullpel vectors */ + } else { + mc_type = ((mv_y & 1) << 1) | (mv_x & 1); + mv_x >>= 1; + mv_y >>= 1; /* convert halfpel vectors into fullpel ones */ + } + + for (blk = 0; blk < num_blocks; blk++) { + /* adjust block position in the buffer according with its number */ + offs = mb->buf_offs + band->blk_size * ((blk & 1) + !!(blk & 2) * pitch); + ret = ivi_mc(band, mc_no_delta_func, 0, offs, + mv_x, mv_y, 0, 0, mc_type, -1); + if (ret < 0) + return ret; + } + } + } else { + /* copy data from the reference tile into the current one */ + src = band->ref_buf + tile->ypos * pitch + tile->xpos; + dst = band->buf + tile->ypos * pitch + tile->xpos; + for (y = 0; y < tile->height; y++) { + memcpy(dst, src, tile->width*sizeof(band->buf[0])); + src += pitch; + dst += pitch; + } + } + + return 0; +} + + +#ifdef DEBUG +static uint16_t ivi_calc_band_checksum(const IVIBandDesc *band) +{ + int x, y; + int16_t *src, checksum; + + src = band->buf; + checksum = 0; + + for (y = 0; y < band->height; src += band->pitch, y++) + for (x = 0; x < band->width; x++) + checksum += src[x]; + + return checksum; +} +#endif + +/* + * Convert and output the current plane. + * This conversion is done by adding back the bias value of 128 + * (subtracted in the encoder) and clipping the result. + * + * @param[in] plane pointer to the descriptor of the plane being processed + * @param[out] dst pointer to the buffer receiving converted pixels + * @param[in] dst_pitch pitch for moving to the next y line + */ +static void ivi_output_plane(IVIPlaneDesc *plane, uint8_t *dst, ptrdiff_t dst_pitch) +{ + int x, y; + const int16_t *src = plane->bands[0].buf; + ptrdiff_t pitch = plane->bands[0].pitch; + + if (!src) + return; + + for (y = 0; y < plane->height; y++) { + int m = 0; + int w = plane->width; + for (x = 0; x < w; x++) { + int t = src[x] + 128; + dst[x] = t; + m |= t; + } + if (m & ~255) + for (x = 0; x < w; x++) + dst[x] = av_clip_uint8(src[x] + 128); + src += pitch; + dst += dst_pitch; + } +} + +static void *prepare_buf(IVI45DecContext *ctx, IVIBandDesc *band, int i) +{ + if (ctx->pic_conf.luma_bands <= 1 && i == 2) + return NULL; + if (!band->bufs[i]) + band->bufs[i] = av_mallocz(2 * band->bufsize); + return band->bufs[i]; +} + +/** + * Decode an Indeo 4 or 5 band. + * + * @param[in,out] ctx ptr to the decoder context + * @param[in,out] band ptr to the band descriptor + * @param[in] avctx ptr to the AVCodecContext + * @return result code: 0 = OK, -1 = error + */ +static int decode_band(IVI45DecContext *ctx, + IVIBandDesc *band, AVCodecContext *avctx) +{ + int result, i, t, idx1, idx2, pos; + IVITile *tile; + + band->buf = prepare_buf(ctx, band, ctx->dst_buf); + if (!band->buf) { + av_log(avctx, AV_LOG_ERROR, "Band buffer points to no data!\n"); + return AVERROR_INVALIDDATA; + } + + band->ref_buf = prepare_buf(ctx, band, ctx->ref_buf); + band->b_ref_buf = 0; + + if (!band->ref_buf) + return AVERROR(ENOMEM); + band->data_ptr = ctx->frame_data + (get_bits_count(&ctx->gb) >> 3); + + result = ctx->decode_band_hdr(ctx, band, avctx); + if (result) { + av_log(avctx, AV_LOG_ERROR, "Error while decoding band header: %d\n", + result); + return result; + } + + if (band->is_empty) { + av_log(avctx, AV_LOG_ERROR, "Empty band encountered!\n"); + return AVERROR_INVALIDDATA; + } + + band->rv_map = &ctx->rvmap_tabs[band->rvmap_sel]; + + /* apply corrections to the selected rvmap table if present */ + for (i = 0; i < band->num_corr; i++) { + idx1 = band->corr[i * 2]; + idx2 = band->corr[i * 2 + 1]; + FFSWAP(uint8_t, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]); + FFSWAP(int16_t, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]); + if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym) + band->rv_map->eob_sym ^= idx1 ^ idx2; + if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym) + band->rv_map->esc_sym ^= idx1 ^ idx2; + } + + pos = get_bits_count(&ctx->gb); + + for (t = 0; t < band->num_tiles; t++) { + tile = &band->tiles[t]; + + if (tile->mb_size != band->mb_size) { + av_log(avctx, AV_LOG_ERROR, "MB sizes mismatch: %d vs. %d\n", + band->mb_size, tile->mb_size); + return AVERROR_INVALIDDATA; + } + tile->is_empty = get_bits1(&ctx->gb); + if (tile->is_empty) { + result = ivi_process_empty_tile(avctx, band, tile, + (ctx->planes[0].bands[0].mb_size >> 3) - (band->mb_size >> 3)); + if (result < 0) + break; + ff_dlog(avctx, "Empty tile encountered!\n"); + } else { + tile->data_size = ivi_dec_tile_data_size(&ctx->gb); + if (!tile->data_size) { + av_log(avctx, AV_LOG_ERROR, "Tile data size is zero!\n"); + result = AVERROR_INVALIDDATA; + break; + } + + result = ctx->decode_mb_info(ctx, band, tile, avctx); + if (result < 0) + break; + + result = ivi_decode_blocks(&ctx->gb, band, tile, avctx); + if (result < 0) { + av_log(avctx, AV_LOG_ERROR, + "Corrupted tile data encountered!\n"); + break; + } + + if (((get_bits_count(&ctx->gb) - pos) >> 3) != tile->data_size) { + av_log(avctx, AV_LOG_ERROR, + "Tile data_size mismatch!\n"); + result = AVERROR_INVALIDDATA; + break; + } + + pos += tile->data_size << 3; // skip to next tile + } + } + + /* restore the selected rvmap table by applying its corrections in + * reverse order */ + for (i = band->num_corr-1; i >= 0; i--) { + idx1 = band->corr[i*2]; + idx2 = band->corr[i*2+1]; + FFSWAP(uint8_t, band->rv_map->runtab[idx1], band->rv_map->runtab[idx2]); + FFSWAP(int16_t, band->rv_map->valtab[idx1], band->rv_map->valtab[idx2]); + if (idx1 == band->rv_map->eob_sym || idx2 == band->rv_map->eob_sym) + band->rv_map->eob_sym ^= idx1 ^ idx2; + if (idx1 == band->rv_map->esc_sym || idx2 == band->rv_map->esc_sym) + band->rv_map->esc_sym ^= idx1 ^ idx2; + } + +#ifdef DEBUG + if (band->checksum_present) { + uint16_t chksum = ivi_calc_band_checksum(band); + if (chksum != band->checksum) { + av_log(avctx, AV_LOG_ERROR, + "Band checksum mismatch! Plane %d, band %d, " + "received: %"PRIx32", calculated: %"PRIx16"\n", + band->plane, band->band_num, band->checksum, chksum); + } + } +#endif + + align_get_bits(&ctx->gb); + + return result; +} + +int ff_ivi_decode_frame(AVCodecContext *avctx, AVFrame *frame, + int *got_frame, const uint8_t *buf, int buf_size) +{ + IVI45DecContext *ctx = avctx->priv_data; + int w, h; + int frame_buf_sz; + int result, p, b; + + result = init_get_bits8(&ctx->gb, buf, buf_size); + if (result < 0) + return result; + ctx->frame_data = buf; + ctx->frame_size = buf_size; + + result = ctx->decode_pic_hdr(ctx, avctx); + if (result) { + av_log(avctx, AV_LOG_ERROR, + "Error while decoding picture header: %d\n", result); + return result; + } + if (ctx->gop_invalid) + return AVERROR_INVALIDDATA; + + if (ctx->gop_flags & IVI5_IS_PROTECTED) { + avpriv_report_missing_feature(avctx, "Password-protected clip"); + return AVERROR_PATCHWELCOME; + } + + if (!ctx->planes[0].bands) { + av_log(avctx, AV_LOG_ERROR, "Color planes not initialized yet\n"); + return AVERROR_INVALIDDATA; + } + + ctx->switch_buffers(ctx); + + if (ctx->is_nonnull_frame(ctx)) { + ctx->buf_invalid[ctx->dst_buf] = 1; + for (p = 0; p < 3; p++) { + for (b = 0; b < ctx->planes[p].num_bands; b++) { + result = decode_band(ctx, &ctx->planes[p].bands[b], avctx); + if (result < 0) { + av_log(avctx, AV_LOG_ERROR, + "Error while decoding band: %d, plane: %d\n", b, p); + return result; + } + } + } + ctx->buf_invalid[ctx->dst_buf] = 0; + } else { + if (ctx->is_scalable) + return AVERROR_INVALIDDATA; + + for (p = 0; p < 3; p++) { + if (!ctx->planes[p].bands[0].buf) + return AVERROR_INVALIDDATA; + } + } + if (ctx->buf_invalid[ctx->dst_buf]) + return AVERROR_INTERNAL; + + if (!ctx->is_nonnull_frame(ctx)) + return buf_size; + + avctx->width = ctx->pic_conf.pic_width; + avctx->height = ctx->pic_conf.pic_height; + + w = FFALIGN(avctx->width, 4); + h = FFALIGN(avctx->height, 4); + + frame_buf_sz = w * h + 2 * (w / 4) * (h / 4); + if (ctx->frame_buf_size < frame_buf_sz) { + free(ctx->frame_buf); + if (!(ctx->frame_buf = malloc(frame_buf_sz))) { + ctx->frame_buf_size = 0; + return AVERROR(ENOMEM); + } + ctx->frame_buf_size = frame_buf_sz; + } + + frame->width = avctx->width; + frame->height = avctx->height; + frame->linesize[0] = w; + frame->linesize[1] = frame->linesize[2] = w / 4; + frame->data[0] = ctx->frame_buf; + frame->data[1] = frame->data[0] + w * h; + frame->data[2] = frame->data[1] + (w / 4) * (h / 4); + + if (ctx->is_scalable) { + ff_ivi_recompose53(&ctx->planes[0], frame->data[0], frame->linesize[0]); + } else { + ivi_output_plane(&ctx->planes[0], frame->data[0], frame->linesize[0]); + } + + ivi_output_plane(&ctx->planes[2], frame->data[1], frame->linesize[1]); + ivi_output_plane(&ctx->planes[1], frame->data[2], frame->linesize[2]); + + *got_frame = 1; + + return buf_size; +} + +/** + * Close Indeo5 decoder and clean up its context. + */ +int ff_ivi_decode_close(AVCodecContext *avctx) +{ + IVI45DecContext *ctx = avctx->priv_data; + + if (!ctx) + return 0; + + ivi_free_buffers(&ctx->planes[0]); + + if (ctx->mb_vlc.cust_tab.table) + ff_free_vlc(&ctx->mb_vlc.cust_tab); + + if (ctx->blk_vlc.cust_tab.table) + ff_free_vlc(&ctx->blk_vlc.cust_tab); + + free(ctx->frame_buf); + + free(ctx); + avctx->priv_data = NULL; + + return 0; +} + + +/** + * Scan patterns shared between indeo4 and indeo5 + */ +const uint8_t ff_ivi_vertical_scan_8x8[64] = { + 0, 8, 16, 24, 32, 40, 48, 56, + 1, 9, 17, 25, 33, 41, 49, 57, + 2, 10, 18, 26, 34, 42, 50, 58, + 3, 11, 19, 27, 35, 43, 51, 59, + 4, 12, 20, 28, 36, 44, 52, 60, + 5, 13, 21, 29, 37, 45, 53, 61, + 6, 14, 22, 30, 38, 46, 54, 62, + 7, 15, 23, 31, 39, 47, 55, 63 +}; + +const uint8_t ff_ivi_horizontal_scan_8x8[64] = { + 0, 1, 2, 3, 4, 5, 6, 7, + 8, 9, 10, 11, 12, 13, 14, 15, + 16, 17, 18, 19, 20, 21, 22, 23, + 24, 25, 26, 27, 28, 29, 30, 31, + 32, 33, 34, 35, 36, 37, 38, 39, + 40, 41, 42, 43, 44, 45, 46, 47, + 48, 49, 50, 51, 52, 53, 54, 55, + 56, 57, 58, 59, 60, 61, 62, 63 +}; + +const uint8_t ff_ivi_direct_scan_4x4[16] = { + 0, 1, 4, 8, 5, 2, 3, 6, 9, 12, 13, 10, 7, 11, 14, 15 +}; + + +/** + * Run-value (RLE) tables. + */ +const RVMapDesc ff_ivi_rvmap_tabs[9] = { +{ /* MapTab0 */ + 5, /* eob_sym */ + 2, /* esc_sym */ + /* run table */ + {1, 1, 0, 1, 1, 0, 1, 1, 2, 2, 1, 1, 1, 1, 3, 3, + 1, 1, 2, 2, 1, 1, 4, 4, 1, 1, 1, 1, 2, 2, 5, 5, + 1, 1, 3, 3, 1, 1, 6, 6, 1, 2, 1, 2, 7, 7, 1, 1, + 8, 8, 1, 1, 4, 2, 1, 4, 2, 1, 3, 3, 1, 1, 1, 9, + 9, 1, 2, 1, 2, 1, 5, 5, 1, 1, 10, 10, 1, 1, 3, 3, + 2, 2, 1, 1, 11, 11, 6, 4, 4, 1, 6, 1, 2, 1, 2, 12, + 8, 1, 12, 7, 8, 7, 1, 16, 1, 16, 1, 3, 3, 13, 1, 13, + 2, 2, 1, 15, 1, 5, 14, 15, 1, 5, 14, 1, 17, 8, 17, 8, + 1, 4, 4, 2, 2, 1, 25, 25, 24, 24, 1, 3, 1, 3, 1, 8, + 6, 7, 6, 1, 18, 8, 18, 1, 7, 23, 2, 2, 23, 1, 1, 21, + 22, 9, 9, 22, 19, 1, 21, 5, 19, 5, 1, 33, 20, 33, 20, 8, + 4, 4, 1, 32, 2, 2, 8, 3, 32, 26, 3, 1, 7, 7, 26, 6, + 1, 6, 1, 1, 16, 1, 10, 1, 10, 2, 16, 29, 28, 2, 29, 28, + 1, 27, 5, 8, 5, 27, 1, 8, 3, 7, 3, 31, 41, 31, 1, 41, + 6, 1, 6, 7, 4, 4, 1, 1, 2, 1, 2, 11, 34, 30, 11, 1, + 30, 15, 15, 34, 36, 40, 36, 40, 35, 35, 37, 37, 39, 39, 38, 38}, + + /* value table */ + { 1, -1, 0, 2, -2, 0, 3, -3, 1, -1, 4, -4, 5, -5, 1, -1, + 6, -6, 2, -2, 7, -7, 1, -1, 8, -8, 9, -9, 3, -3, 1, -1, + 10, -10, 2, -2, 11, -11, 1, -1, 12, 4, -12, -4, 1, -1, 13, -13, + 1, -1, 14, -14, 2, 5, 15, -2, -5, -15, -3, 3, 16, -16, 17, 1, + -1, -17, 6, 18, -6, -18, 2, -2, 19, -19, 1, -1, 20, -20, 4, -4, + 7, -7, 21, -21, 1, -1, 2, 3, -3, 22, -2, -22, 8, 23, -8, 1, + 2, -23, -1, 2, -2, -2, 24, 1, -24, -1, 25, 5, -5, 1, -25, -1, + 9, -9, 26, 1, -26, 3, 1, -1, 27, -3, -1, -27, 1, 3, -1, -3, + 28, -4, 4, 10, -10, -28, 1, -1, 1, -1, 29, 6, -29, -6, 30, -4, + 3, 3, -3, -30, 1, 4, -1, 31, -3, 1, 11, -11, -1, -31, 32, -1, + -1, 2, -2, 1, 1, -32, 1, 4, -1, -4, 33, -1, 1, 1, -1, 5, + 5, -5, -33, -1, -12, 12, -5, -7, 1, 1, 7, 34, 4, -4, -1, 4, + -34, -4, 35, 36, -2, -35, -2, -36, 2, 13, 2, -1, 1, -13, 1, -1, + 37, 1, -5, 6, 5, -1, 38, -6, -8, 5, 8, -1, 1, 1, -37, -1, + 5, 39, -5, -5, 6, -6, -38, -39, -14, 40, 14, 2, 1, 1, -2, -40, + -1, -2, 2, -1, -1, -1, 1, 1, 1, -1, 1, -1, 1, -1, 1, -1} +},{ + /* MapTab1 */ + 0, /* eob_sym */ + 38, /* esc_sym */ + /* run table */ + {0, 1, 1, 2, 2, 3, 3, 4, 4, 5, 5, 6, 8, 6, 8, 7, + 7, 9, 9, 10, 10, 11, 11, 1, 12, 1, 12, 13, 13, 16, 14, 16, + 14, 15, 15, 17, 17, 18, 0, 18, 19, 20, 21, 19, 22, 21, 20, 22, + 25, 24, 2, 25, 24, 23, 23, 2, 26, 28, 26, 28, 29, 27, 29, 27, + 33, 33, 1, 32, 1, 3, 32, 30, 36, 3, 36, 30, 31, 31, 35, 34, + 37, 41, 34, 35, 37, 4, 41, 4, 49, 8, 8, 49, 40, 38, 5, 38, + 40, 39, 5, 39, 42, 43, 42, 7, 57, 6, 43, 44, 6, 50, 7, 44, + 57, 48, 50, 48, 45, 45, 46, 47, 51, 46, 47, 58, 1, 51, 58, 1, + 52, 59, 53, 9, 52, 55, 55, 59, 53, 56, 54, 56, 54, 9, 64, 64, + 60, 63, 60, 63, 61, 62, 61, 62, 2, 10, 2, 10, 11, 1, 11, 13, + 12, 1, 12, 13, 16, 16, 8, 8, 14, 3, 3, 15, 14, 15, 4, 4, + 1, 17, 17, 5, 1, 7, 7, 5, 6, 1, 2, 2, 6, 22, 1, 25, + 21, 22, 8, 24, 1, 21, 25, 24, 8, 18, 18, 23, 9, 20, 23, 33, + 29, 33, 20, 1, 19, 1, 29, 36, 9, 36, 19, 41, 28, 57, 32, 3, + 28, 3, 1, 27, 49, 49, 1, 32, 26, 26, 2, 4, 4, 7, 57, 41, + 2, 7, 10, 5, 37, 16, 10, 27, 8, 8, 13, 16, 37, 13, 1, 5}, + + /* value table */ + {0, 1, -1, 1, -1, 1, -1, 1, -1, 1, -1, 1, 1, -1, -1, 1, + -1, 1, -1, 1, -1, 1, -1, 2, 1, -2, -1, 1, -1, 1, 1, -1, + -1, 1, -1, 1, -1, 1, 0, -1, 1, 1, 1, -1, 1, -1, -1, -1, + 1, 1, 2, -1, -1, 1, -1, -2, 1, 1, -1, -1, 1, 1, -1, -1, + 1, -1, 3, 1, -3, 2, -1, 1, 1, -2, -1, -1, -1, 1, 1, 1, + 1, 1, -1, -1, -1, 2, -1, -2, 1, 2, -2, -1, 1, 1, 2, -1, + -1, 1, -2, -1, 1, 1, -1, 2, 1, 2, -1, 1, -2, -1, -2, -1, + -1, 1, 1, -1, 1, -1, 1, 1, 1, -1, -1, 1, 4, -1, -1, -4, + 1, 1, 1, 2, -1, -1, 1, -1, -1, 1, -1, -1, 1, -2, 1, -1, + 1, 1, -1, -1, 1, 1, -1, -1, 3, 2, -3, -2, 2, 5, -2, 2, + 2, -5, -2, -2, -2, 2, -3, 3, 2, 3, -3, 2, -2, -2, 3, -3, + 6, 2, -2, 3, -6, 3, -3, -3, 3, 7, -4, 4, -3, 2, -7, 2, + 2, -2, -4, 2, 8, -2, -2, -2, 4, 2, -2, 2, 3, 2, -2, -2, + 2, 2, -2, -8, -2, 9, -2, 2, -3, -2, 2, -2, 2, 2, 2, 4, + -2, -4, 10, 2, 2, -2, -9, -2, 2, -2, 5, 4, -4, 4, -2, 2, + -5, -4, -3, 4, 2, -3, 3, -2, -5, 5, 3, 3, -2, -3, -10, -4} +},{ + /* MapTab2 */ + 2, /* eob_sym */ + 11, /* esc_sym */ + /* run table */ + {1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 0, 1, 1, 5, 5, + 2, 2, 6, 6, 7, 7, 1, 8, 1, 8, 3, 3, 9, 9, 1, 2, + 2, 1, 4, 10, 4, 10, 11, 11, 1, 5, 12, 12, 1, 5, 13, 13, + 3, 3, 6, 6, 2, 2, 14, 14, 16, 16, 15, 7, 15, 8, 8, 7, + 1, 1, 17, 17, 4, 4, 1, 1, 18, 18, 2, 2, 5, 5, 25, 3, + 9, 3, 25, 9, 19, 24, 19, 24, 1, 21, 20, 1, 21, 22, 20, 22, + 23, 23, 8, 6, 33, 6, 8, 33, 7, 7, 26, 26, 1, 32, 1, 32, + 28, 4, 28, 10, 29, 27, 27, 10, 41, 4, 29, 2, 2, 41, 36, 31, + 49, 31, 34, 30, 34, 36, 30, 35, 1, 49, 11, 5, 35, 11, 1, 3, + 3, 5, 37, 37, 8, 40, 8, 40, 12, 12, 42, 42, 1, 38, 16, 57, + 1, 6, 16, 39, 38, 6, 7, 7, 13, 13, 39, 43, 2, 43, 57, 2, + 50, 9, 44, 9, 50, 4, 15, 48, 44, 4, 1, 15, 48, 14, 14, 1, + 45, 45, 8, 3, 5, 8, 51, 47, 3, 46, 46, 47, 5, 51, 1, 17, + 17, 58, 1, 58, 2, 52, 52, 2, 53, 7, 59, 6, 6, 56, 53, 55, + 7, 55, 1, 54, 59, 56, 54, 10, 1, 10, 4, 60, 1, 60, 8, 4, + 8, 64, 64, 61, 1, 63, 3, 63, 62, 61, 5, 11, 5, 3, 11, 62}, + + /* value table */ + { 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 0, 3, -3, 1, -1, + 2, -2, 1, -1, 1, -1, 4, 1, -4, -1, 2, -2, 1, -1, 5, 3, + -3, -5, 2, 1, -2, -1, 1, -1, 6, 2, 1, -1, -6, -2, 1, -1, + 3, -3, 2, -2, 4, -4, 1, -1, 1, -1, 1, 2, -1, 2, -2, -2, + 7, -7, 1, -1, 3, -3, 8, -8, 1, -1, 5, -5, 3, -3, 1, 4, + 2, -4, -1, -2, 1, 1, -1, -1, 9, 1, 1, -9, -1, 1, -1, -1, + 1, -1, 3, -3, 1, 3, -3, -1, 3, -3, 1, -1, 10, 1, -10, -1, + 1, 4, -1, 2, 1, -1, 1, -2, 1, -4, -1, 6, -6, -1, 1, 1, + 1, -1, 1, 1, -1, -1, -1, 1, 11, -1, -2, 4, -1, 2, -11, 5, + -5, -4, -1, 1, 4, 1, -4, -1, -2, 2, 1, -1, 12, 1, -2, 1, + -12, 4, 2, 1, -1, -4, 4, -4, 2, -2, -1, 1, 7, -1, -1, -7, + -1, -3, 1, 3, 1, 5, 2, 1, -1, -5, 13, -2, -1, 2, -2, -13, + 1, -1, 5, 6, 5, -5, 1, 1, -6, 1, -1, -1, -5, -1, 14, 2, + -2, 1, -14, -1, 8, 1, -1, -8, 1, 5, 1, 5, -5, 1, -1, 1, + -5, -1, 15, 1, -1, -1, -1, 3, -15, -3, 6, 1, 16, -1, 6, -6, + -6, 1, -1, 1, -16, 1, 7, -1, 1, -1, -6, -3, 6, -7, 3, -1} +},{ + /* MapTab3 */ + 0, /* eob_sym */ + 35, /* esc_sym */ + /* run table */ + {0, 1, 1, 2, 2, 3, 3, 4, 4, 1, 1, 5, 5, 6, 6, 7, + 7, 8, 8, 9, 9, 2, 2, 10, 10, 1, 1, 11, 11, 12, 12, 3, + 3, 13, 13, 0, 14, 14, 16, 15, 16, 15, 4, 4, 17, 1, 17, 1, + 5, 5, 18, 18, 2, 2, 6, 6, 8, 19, 7, 8, 7, 19, 20, 20, + 21, 21, 22, 24, 22, 24, 23, 23, 1, 1, 25, 25, 3, 3, 26, 26, + 9, 9, 27, 27, 28, 28, 33, 29, 4, 33, 29, 1, 4, 1, 32, 32, + 2, 2, 31, 10, 30, 10, 30, 31, 34, 34, 5, 5, 36, 36, 35, 41, + 35, 11, 41, 11, 37, 1, 8, 8, 37, 6, 1, 6, 40, 7, 7, 40, + 12, 38, 12, 39, 39, 38, 49, 13, 49, 13, 3, 42, 3, 42, 16, 16, + 43, 43, 14, 14, 1, 1, 44, 15, 44, 15, 2, 2, 57, 48, 50, 48, + 57, 50, 4, 45, 45, 4, 46, 47, 47, 46, 1, 51, 1, 17, 17, 51, + 8, 9, 9, 5, 58, 8, 58, 5, 52, 52, 55, 56, 53, 56, 55, 59, + 59, 53, 54, 1, 6, 54, 7, 7, 6, 1, 2, 3, 2, 3, 64, 60, + 60, 10, 10, 64, 61, 62, 61, 63, 1, 63, 62, 1, 18, 24, 18, 4, + 25, 4, 8, 21, 21, 1, 24, 22, 25, 22, 8, 11, 19, 11, 23, 1, + 20, 23, 19, 20, 5, 12, 5, 1, 16, 2, 12, 13, 2, 13, 1, 16}, + + /* value table */ + { 0, 1, -1, 1, -1, 1, -1, 1, -1, 2, -2, 1, -1, 1, -1, 1, + -1, 1, -1, 1, -1, 2, -2, 1, -1, 3, -3, 1, -1, 1, -1, 2, + -2, 1, -1, 0, 1, -1, 1, 1, -1, -1, 2, -2, 1, 4, -1, -4, + 2, -2, 1, -1, -3, 3, 2, -2, 2, 1, 2, -2, -2, -1, 1, -1, + 1, -1, 1, 1, -1, -1, 1, -1, 5, -5, 1, -1, 3, -3, 1, -1, + 2, -2, 1, -1, 1, -1, 1, 1, 3, -1, -1, 6, -3, -6, -1, 1, + 4, -4, 1, 2, 1, -2, -1, -1, 1, -1, 3, -3, 1, -1, 1, 1, + -1, 2, -1, -2, 1, 7, -3, 3, -1, 3, -7, -3, 1, -3, 3, -1, + 2, 1, -2, 1, -1, -1, 1, 2, -1, -2, -4, -1, 4, 1, 2, -2, + 1, -1, -2, 2, 8, -8, -1, 2, 1, -2, -5, 5, 1, -1, -1, 1, + -1, 1, 4, -1, 1, -4, -1, -1, 1, 1, 9, 1, -9, 2, -2, -1, + -4, 3, -3, -4, -1, 4, 1, 4, 1, -1, 1, -1, 1, 1, -1, 1, + -1, -1, -1, 10, 4, 1, 4, -4, -4, -10, 6, 5, -6, -5, 1, -1, + 1, 3, -3, -1, 1, -1, -1, -1, 11, 1, 1, -11, -2, -2, 2, 5, + -2, -5, -5, 2, -2, 12, 2, -2, 2, 2, 5, -3, -2, 3, -2, -12, + -2, 2, 2, 2, -5, 3, 5, 13, -3, 7, -3, -3, -7, 3, -13, 3} +},{ + /* MapTab4 */ + 0, /* eob_sym */ + 34, /* esc_sym */ + /* run table */ + {0, 1, 1, 1, 2, 2, 1, 3, 3, 1, 1, 1, 4, 4, 1, 5, + 2, 1, 5, 2, 1, 1, 6, 6, 1, 1, 1, 1, 1, 7, 3, 1, + 2, 3, 0, 1, 2, 7, 1, 1, 1, 8, 1, 1, 8, 1, 1, 1, + 9, 1, 9, 1, 2, 1, 1, 2, 1, 1, 10, 4, 1, 10, 1, 4, + 1, 1, 1, 1, 1, 3, 1, 1, 1, 3, 2, 1, 5, 1, 1, 1, + 2, 5, 1, 11, 1, 11, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 2, 1, 6, 1, 6, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, 12, + 3, 1, 12, 1, 1, 1, 2, 1, 1, 3, 1, 1, 1, 1, 1, 1, + 4, 1, 1, 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, 1, 2, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 3, 1, 2, 1, 1, 5, + 1, 1, 1, 1, 1, 7, 1, 7, 1, 1, 2, 3, 1, 1, 1, 1, + 5, 1, 1, 1, 1, 1, 1, 2, 13, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 13, 2, 1, 1, 4, 1, 1, 1, + 3, 1, 6, 1, 1, 1, 14, 1, 1, 1, 1, 1, 14, 6, 1, 1, + 1, 1, 15, 2, 4, 1, 2, 3, 15, 1, 1, 1, 8, 1, 1, 8, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 1, 1, 1, 1, 1, 1, 1}, + + /* value table */ + { 0, 1, -1, 2, 1, -1, -2, 1, -1, 3, -3, 4, 1, -1, -4, 1, + 2, 5, -1, -2, -5, 6, 1, -1, -6, 7, -7, 8, -8, 1, 2, 9, + 3, -2, 0, -9, -3, -1, 10, -10, 11, 1, -11, 12, -1, -12, 13, -13, + 1, 14, -1, -14, 4, 15, -15, -4, 16, -16, 1, 2, 17, -1, -17, -2, + 18, -18, 19, -19, 20, 3, -20, 21, -21, -3, 5, 22, 2, -22, -23, 23, + -5, -2, 24, 1, -24, -1, 25, -25, 26, -26, -27, 27, 28, 29, -28, -29, + 6, 30, 2, -31, -2, -30, 31, -6, -32, 32, 33, -33, 34, -35, -34, 1, + 4, -36, -1, 35, 37, 36, 7, -37, 38, -4, -38, 39, 41, 40, -40, -39, + 3, 42, -43, -41, -7, -42, 43, -3, 44, -44, 45, -45, 46, 47, 8, -47, + -48, -46, 50, -50, 48, 49, 51, -49, 52, -52, 5, -51, -8, -53, 53, 3, + -56, 56, 55, 54, -54, 2, 60, -2, -55, 58, 9, -5, 59, 57, -57, -63, + -3, -58, -60, -61, 61, -59, -62, -9, 1, 64, 62, 69, -64, 63, 65, -67, + -68, 66, -65, 68, -66, -69, 67, -70, -1, 10, 71, -71, 4, 73, 72, 70, + 6, -76, -3, 74, -78, -74, 1, 78, 80, -72, -75, 76, -1, 3, -73, 79, + 75, 77, 1, 11, -4, -79, -10, -6, -1, -77, -83, -80, 2, 81, -84, -2, + 83, -81, 82, -82, 84, -87, -86, 85, -11, -85, 86, -89, 87, -88, 88, 89} +},{ + /* MapTab5 */ + 2, /* eob_sym */ + 33, /* esc_sym */ + /* run table */ + {1, 1, 0, 2, 1, 2, 1, 3, 3, 1, 1, 4, 4, 2, 2, 1, + 1, 5, 5, 6, 1, 6, 1, 7, 7, 3, 3, 2, 8, 2, 8, 1, + 1, 0, 9, 9, 1, 1, 10, 4, 10, 4, 11, 11, 2, 1, 2, 1, + 12, 12, 3, 3, 1, 1, 13, 5, 5, 13, 14, 1, 1, 14, 2, 2, + 6, 6, 15, 1, 1, 15, 16, 4, 7, 16, 4, 7, 1, 1, 3, 3, + 8, 8, 2, 2, 1, 1, 17, 17, 1, 1, 18, 18, 5, 5, 2, 2, + 1, 1, 9, 19, 9, 19, 20, 3, 3, 20, 1, 10, 21, 1, 10, 4, + 4, 21, 22, 6, 6, 22, 1, 1, 23, 24, 2, 2, 23, 24, 11, 1, + 1, 11, 7, 25, 7, 1, 1, 25, 8, 8, 3, 26, 3, 1, 12, 2, + 2, 26, 1, 12, 5, 5, 27, 4, 1, 4, 1, 27, 28, 1, 28, 13, + 1, 13, 2, 29, 2, 1, 32, 6, 1, 30, 14, 29, 14, 6, 3, 31, + 3, 1, 30, 1, 32, 31, 33, 9, 33, 1, 1, 7, 9, 7, 2, 2, + 1, 1, 4, 36, 34, 4, 5, 10, 10, 5, 34, 1, 1, 35, 8, 8, + 36, 3, 35, 1, 15, 3, 2, 1, 16, 15, 16, 2, 37, 1, 37, 1, + 1, 1, 6, 6, 38, 1, 38, 11, 1, 39, 39, 40, 11, 2, 41, 4, + 40, 1, 2, 4, 1, 1, 1, 41, 3, 1, 3, 1, 5, 7, 5, 7}, + + /* value table */ + { 1, -1, 0, 1, 2, -1, -2, 1, -1, 3, -3, 1, -1, 2, -2, 4, + -4, 1, -1, 1, 5, -1, -5, 1, -1, 2, -2, 3, 1, -3, -1, 6, + -6, 0, 1, -1, 7, -7, 1, 2, -1, -2, 1, -1, 4, 8, -4, -8, + 1, -1, 3, -3, 9, -9, 1, 2, -2, -1, 1, 10, -10, -1, 5, -5, + 2, -2, 1, 11, -11, -1, 1, 3, 2, -1, -3, -2, 12, -12, 4, -4, + 2, -2, -6, 6, 13, -13, 1, -1, 14, -14, 1, -1, 3, -3, 7, -7, + 15, -15, 2, 1, -2, -1, 1, 5, -5, -1, -16, 2, 1, 16, -2, 4, + -4, -1, 1, 3, -3, -1, 17, -17, 1, 1, -8, 8, -1, -1, 2, 18, + -18, -2, 3, 1, -3, 19, -19, -1, 3, -3, 6, 1, -6, 20, 2, 9, + -9, -1, -20, -2, 4, -4, 1, -5, 21, 5, -21, -1, 1, -22, -1, 2, + 22, -2, 10, 1, -10, 23, 1, 4, -23, 1, 2, -1, -2, -4, -7, 1, + 7, -24, -1, 24, -1, -1, 1, 3, -1, -25, 25, 4, -3, -4, 11, -11, + 26, -26, 6, 1, 1, -6, -5, -3, 3, 5, -1, -27, 27, 1, 4, -4, + -1, -8, -1, 28, 2, 8, -12, -28, -2, -2, 2, 12, -1, 29, 1, -29, + 30, -30, 5, -5, 1, -31, -1, 3, 31, -1, 1, 1, -3, -13, 1, -7, + -1, -32, 13, 7, 32, 33, -33, -1, -9, -34, 9, 34, -6, 5, 6, -5} +},{ + /* MapTab6 */ + 2, /* eob_sym */ + 13, /* esc_sym */ + /* run table */ + {1, 1, 0, 1, 1, 2, 2, 1, 1, 3, 3, 1, 1, 0, 2, 2, + 4, 1, 4, 1, 1, 1, 5, 5, 1, 1, 6, 6, 2, 2, 1, 1, + 3, 3, 7, 7, 1, 1, 8, 8, 1, 1, 2, 2, 1, 9, 1, 9, + 4, 4, 10, 1, 1, 10, 1, 1, 11, 11, 3, 3, 1, 2, 1, 2, + 1, 1, 12, 12, 5, 5, 1, 1, 13, 1, 1, 13, 2, 2, 1, 1, + 6, 6, 1, 1, 4, 14, 4, 14, 3, 1, 3, 1, 1, 1, 15, 7, + 15, 2, 2, 7, 1, 1, 1, 8, 1, 8, 16, 16, 1, 1, 1, 1, + 2, 1, 1, 2, 1, 1, 3, 5, 5, 3, 4, 1, 1, 4, 1, 1, + 17, 17, 9, 1, 1, 9, 2, 2, 1, 1, 10, 10, 1, 6, 1, 1, + 6, 18, 1, 1, 18, 1, 1, 1, 2, 2, 3, 1, 3, 1, 1, 1, + 4, 1, 19, 1, 19, 7, 1, 1, 20, 1, 4, 20, 1, 7, 11, 2, + 1, 11, 21, 2, 8, 5, 1, 8, 1, 5, 21, 1, 1, 1, 22, 1, + 1, 22, 1, 1, 3, 3, 1, 23, 2, 12, 24, 1, 1, 2, 1, 1, + 12, 23, 1, 1, 24, 1, 1, 1, 4, 1, 1, 1, 2, 1, 6, 6, + 4, 2, 1, 1, 1, 1, 1, 1, 1, 14, 13, 3, 1, 25, 9, 25, + 14, 1, 9, 3, 13, 1, 1, 1, 1, 1, 10, 1, 1, 2, 10, 2}, + + /* value table */ + {-20, -1, 0, 2, -2, 1, -1, 3, -3, 1, -1, 4, -4, 0, 2, -2, + 1, 5, -1, -5, 6, -6, 1, -1, 7, -7, 1, -1, 3, -3, 8, -8, + 2, -2, 1, -1, 9, -9, 1, -1, 10, -10, 4, -4, 11, 1, -11, -1, + 2, -2, 1, 12, -12, -1, 13, -13, 1, -1, 3, -3, 14, 5, -14, -5, + -15, 15, -1, 1, 2, -2, 16, -16, 1, 17, -17, -1, 6, -6, 18, -18, + 2, -2, -19, 19, -3, 1, 3, -1, 4, 20, -4, 1, -21, 21, 1, 2, + -1, -7, 7, -2, 22, -22, 23, 2, -23, -2, 1, -1, -24, 24, -25, 25, + -8, -26, 26, 8, -27, 27, 5, 3, -3, -5, -4, 28, -28, 4, 29, -29, + 1, -1, -2, -30, 30, 2, 9, -9, -31, 31, 2, -2, -32, 3, 32, -33, + -3, 1, 33, -34, -1, 34, -35, 35, -10, 10, -6, 36, 6, -36, 37, -37, + -5, 38, 1, -38, -1, 3, 39, -39, -1, 40, 5, 1, -40, -3, 2, -11, + -41, -2, 1, 11, -3, -4, 41, 3, 42, 4, -1, -43, -42, 43, 1, -44, + 45, -1, 44, -45, -7, 7, -46, 1, -12, 2, 1, -47, 46, 12, 47, 48, + -2, -1, -48, 49, -1, -50, -49, 50, -6, -51, 51, 52, -13, 53, -4, 4, + 6, 13, -53, -52, -54, 55, 54, -55, -56, -2, 2, -8, 56, 1, -3, -1, + 2, 58, 3, 8, -2, 57, -58, -60, -59, -57, -3, 60, 59, -14, 3, 14} +},{ + /* MapTab7 */ + 2, /* eob_sym */ + 38, /* esc_sym */ + /* run table */ + {1, 1, 0, 2, 2, 1, 1, 3, 3, 4, 4, 5, 5, 1, 1, 6, + 6, 2, 2, 7, 7, 8, 8, 1, 1, 3, 3, 9, 9, 10, 10, 1, + 1, 2, 2, 4, 4, 11, 0, 11, 12, 12, 13, 13, 1, 1, 5, 5, + 14, 14, 15, 16, 15, 16, 3, 3, 1, 6, 1, 6, 2, 2, 7, 7, + 8, 8, 17, 17, 1, 1, 4, 4, 18, 18, 2, 2, 1, 19, 1, 20, + 19, 20, 21, 21, 3, 3, 22, 22, 5, 5, 24, 1, 1, 23, 9, 23, + 24, 9, 2, 2, 10, 1, 1, 10, 6, 6, 25, 4, 4, 25, 7, 7, + 26, 8, 1, 8, 3, 1, 26, 3, 11, 11, 27, 27, 2, 28, 1, 2, + 28, 1, 12, 12, 5, 5, 29, 13, 13, 29, 32, 1, 1, 33, 31, 30, + 32, 4, 30, 33, 4, 31, 3, 14, 1, 1, 3, 34, 34, 2, 2, 14, + 6, 6, 35, 36, 35, 36, 1, 15, 1, 16, 16, 15, 7, 9, 7, 9, + 37, 8, 8, 37, 1, 1, 39, 2, 38, 39, 2, 40, 5, 38, 40, 5, + 3, 3, 4, 4, 10, 10, 1, 1, 1, 1, 41, 2, 41, 2, 6, 6, + 1, 1, 11, 42, 11, 43, 3, 42, 3, 17, 4, 43, 1, 17, 7, 1, + 8, 44, 4, 7, 44, 5, 8, 2, 5, 1, 2, 48, 45, 1, 12, 45, + 12, 48, 13, 13, 1, 9, 9, 46, 1, 46, 47, 47, 49, 18, 18, 49}, + + /* value table */ + { 1, -1, 0, 1, -1, 2, -2, 1, -1, 1, -1, 1, -1, 3, -3, 1, + -1, -2, 2, 1, -1, 1, -1, 4, -4, -2, 2, 1, -1, 1, -1, 5, + -5, -3, 3, 2, -2, 1, 0, -1, 1, -1, 1, -1, 6, -6, 2, -2, + 1, -1, 1, 1, -1, -1, -3, 3, 7, 2, -7, -2, -4, 4, 2, -2, + 2, -2, 1, -1, 8, -8, 3, -3, 1, -1, -5, 5, 9, 1, -9, 1, + -1, -1, 1, -1, -4, 4, 1, -1, 3, -3, 1, -10, 10, 1, 2, -1, + -1, -2, 6, -6, 2, 11, -11, -2, 3, -3, 1, -4, 4, -1, 3, -3, + 1, 3, 12, -3, -5, -12, -1, 5, 2, -2, 1, -1, -7, 1, 13, 7, + -1, -13, 2, -2, 4, -4, 1, 2, -2, -1, 1, 14, -14, 1, 1, 1, + -1, -5, -1, -1, 5, -1, -6, 2, -15, 15, 6, 1, -1, -8, 8, -2, + -4, 4, 1, 1, -1, -1, 16, 2, -16, -2, 2, -2, 4, 3, -4, -3, + -1, -4, 4, 1, -17, 17, -1, -9, 1, 1, 9, 1, -5, -1, -1, 5, + -7, 7, 6, -6, 3, -3, 18, -18, 19, -19, 1, -10, -1, 10, -5, 5, + 20, -20, -3, 1, 3, 1, 8, -1, -8, 2, 7, -1, -21, -2, 5, 21, + 5, -1, -7, -5, 1, -6, -5, -11, 6, 22, 11, 1, 1, -22, -3, -1, + 3, -1, 3, -3, -23, 4, -4, 1, 23, -1, 1, -1, 1, -2, 2, -1} +},{ + /* MapTab8 */ + 4, /* eob_sym */ + 11, /* esc_sym */ + /* run table */ + {1, 1, 1, 1, 0, 2, 2, 1, 1, 3, 3, 0, 1, 1, 2, 2, + 4, 4, 1, 1, 5, 5, 1, 1, 2, 2, 3, 3, 6, 6, 1, 1, + 7, 7, 8, 1, 8, 2, 2, 1, 4, 4, 1, 3, 1, 3, 9, 9, + 2, 2, 1, 5, 1, 5, 10, 10, 1, 1, 11, 11, 3, 6, 3, 4, + 4, 6, 2, 2, 1, 12, 1, 12, 7, 13, 7, 13, 1, 1, 8, 8, + 2, 2, 14, 14, 16, 15, 16, 5, 5, 1, 3, 15, 1, 3, 4, 4, + 1, 1, 17, 17, 2, 2, 6, 6, 1, 18, 1, 18, 22, 21, 22, 21, + 25, 24, 25, 19, 9, 20, 9, 23, 19, 24, 20, 3, 23, 7, 3, 1, + 1, 7, 28, 26, 29, 5, 28, 26, 5, 8, 29, 4, 8, 27, 2, 2, + 4, 27, 1, 1, 10, 36, 10, 33, 33, 36, 30, 1, 32, 32, 1, 30, + 6, 31, 31, 35, 3, 6, 11, 11, 3, 2, 35, 2, 34, 1, 34, 1, + 37, 37, 12, 7, 12, 5, 41, 5, 4, 7, 1, 8, 13, 4, 1, 41, + 13, 38, 8, 38, 9, 1, 40, 40, 9, 1, 39, 2, 2, 49, 39, 42, + 3, 3, 14, 16, 49, 14, 16, 42, 43, 43, 6, 6, 15, 1, 1, 15, + 44, 44, 1, 1, 50, 48, 4, 5, 4, 7, 5, 2, 10, 10, 48, 7, + 50, 45, 2, 1, 45, 8, 8, 1, 46, 46, 3, 47, 47, 3, 1, 1}, + + /* value table */ + { 1, -1, 2, -2, 0, 1, -1, 3, -3, 1, -1, 0, 4, -4, 2, -2, + 1, -1, 5, -5, 1, -1, 6, -6, 3, -3, 2, -2, 1, -1, 7, -7, + 1, -1, 1, 8, -1, 4, -4, -8, 2, -2, 9, 3, -9, -3, 1, -1, + 5, -5, 10, 2, -10, -2, 1, -1, 11, -11, 1, -1, -4, 2, 4, 3, + -3, -2, 6, -6, 12, 1, -12, -1, 2, 1, -2, -1, 13, -13, 2, -2, + 7, -7, 1, -1, 1, 1, -1, 3, -3, 14, 5, -1, -14, -5, 4, -4, + 15, -15, 1, -1, 8, -8, -3, 3, 16, 1, -16, -1, 1, 1, -1, -1, + 1, 1, -1, 1, 2, 1, -2, 1, -1, -1, -1, 6, -1, 3, -6, 17, + -17, -3, 1, 1, 1, 4, -1, -1, -4, 3, -1, 5, -3, -1, -9, 9, + -5, 1, 18, -18, 2, 1, -2, 1, -1, -1, 1, 19, -1, 1, -19, -1, + 4, 1, -1, 1, 7, -4, -2, 2, -7, 10, -1, -10, 1, 20, -1, -20, + 1, -1, 2, 4, -2, 5, 1, -5, 6, -4, 21, 4, 2, -6, -21, -1, + -2, 1, -4, -1, -3, 22, -1, 1, 3, -22, -1, 11, -11, 1, 1, 1, + 8, -8, 2, 2, -1, -2, -2, -1, 1, -1, -5, 5, 2, 23, -23, -2, + 1, -1, 24, -24, -1, -1, 7, 6, -7, 5, -6, 12, -3, 3, 1, -5, + 1, 1, -12, 25, -1, -5, 5, -25, -1, 1, 9, 1, -1, -9, 26, -26} +} +}; diff --git a/libs/ffmpegindeo/ivi.h b/libs/ffmpegindeo/ivi.h new file mode 100644 index 00000000000..98ffee599e7 --- /dev/null +++ b/libs/ffmpegindeo/ivi.h @@ -0,0 +1,321 @@ +/* + * common functions for Indeo Video Interactive codecs (Indeo4 and Indeo5) + * + * Copyright (c) 2009 Maxim Poliakovski + * + * 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 + * This file contains structures and macros shared by both Indeo4 and + * Indeo5 decoders. + */ + +#ifndef AVCODEC_IVI_H +#define AVCODEC_IVI_H + +#include "get_bits.h" +#include <stdint.h> +#include "indeo_compat.h" + + +#define IVI_VLC_BITS 13 ///< max number of bits of the ivi's huffman codes +#define IVI5_IS_PROTECTED 0x20 + +/** + * huffman codebook descriptor + */ +typedef struct IVIHuffDesc { + int32_t num_rows; + uint8_t xbits[16]; +} IVIHuffDesc; + +/** + * macroblock/block huffman table descriptor + */ +typedef struct IVIHuffTab { + int32_t tab_sel; /// index of one of the predefined tables + /// or "7" for custom one + VLC *tab; /// pointer to the table associated with tab_sel + + /// the following are used only when tab_sel == 7 + IVIHuffDesc cust_desc; /// custom Huffman codebook descriptor + VLC cust_tab; /// vlc table for custom codebook +} IVIHuffTab; + +enum { + IVI_MB_HUFF = 0, /// Huffman table is used for coding macroblocks + IVI_BLK_HUFF = 1 /// Huffman table is used for coding blocks +}; + + +/** + * Common scan patterns (defined in ivi_common.c) + */ +extern const uint8_t ff_ivi_vertical_scan_8x8[64]; +extern const uint8_t ff_ivi_horizontal_scan_8x8[64]; +extern const uint8_t ff_ivi_direct_scan_4x4[16]; + + +/** + * Declare inverse transform function types + */ +typedef void (InvTransformPtr)(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags); +typedef void (DCTransformPtr) (const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size); + + +/** + * run-value (RLE) table descriptor + */ +typedef struct RVMapDesc { + uint8_t eob_sym; ///< end of block symbol + uint8_t esc_sym; ///< escape symbol + uint8_t runtab[256]; + int8_t valtab[256]; +} RVMapDesc; + +extern const RVMapDesc ff_ivi_rvmap_tabs[9]; + + +/** + * information for Indeo macroblock (16x16, 8x8 or 4x4) + */ +typedef struct IVIMbInfo { + int16_t xpos; + int16_t ypos; + uint32_t buf_offs; ///< address in the output buffer for this mb + uint8_t type; ///< macroblock type: 0 - INTRA, 1 - INTER + uint8_t cbp; ///< coded block pattern + int8_t q_delta; ///< quant delta + int8_t mv_x; ///< motion vector (x component) + int8_t mv_y; ///< motion vector (y component) + int8_t b_mv_x; ///< second motion vector (x component) + int8_t b_mv_y; ///< second motion vector (y component) +} IVIMbInfo; + + +/** + * information for Indeo tile + */ +typedef struct IVITile { + int xpos; + int ypos; + int width; + int height; + int mb_size; + int is_empty; ///< = 1 if this tile doesn't contain any data + int data_size; ///< size of the data in bytes + int num_MBs; ///< number of macroblocks in this tile + IVIMbInfo *mbs; ///< array of macroblock descriptors + IVIMbInfo *ref_mbs; ///< ptr to the macroblock descriptors of the reference tile +} IVITile; + + +/** + * information for Indeo wavelet band + */ +typedef struct IVIBandDesc { + int plane; ///< plane number this band belongs to + int band_num; ///< band number + int width; + int height; + int aheight; ///< aligned band height + const uint8_t *data_ptr; ///< ptr to the first byte of the band data + int data_size; ///< size of the band data + int16_t *buf; ///< pointer to the output buffer for this band + int16_t *ref_buf; ///< pointer to the reference frame buffer (for motion compensation) + int16_t *b_ref_buf; ///< pointer to the second reference frame buffer (for motion compensation) + int16_t *bufs[4]; ///< array of pointers to the band buffers + ptrdiff_t pitch; ///< pitch associated with the buffers above + int is_empty; ///< = 1 if this band doesn't contain any data + int mb_size; ///< macroblock size + int blk_size; ///< block size + int is_halfpel; ///< precision of the motion compensation: 0 - fullpel, 1 - halfpel + int inherit_mv; ///< tells if motion vector is inherited from reference macroblock + int inherit_qdelta; ///< tells if quantiser delta is inherited from reference macroblock + int qdelta_present; ///< tells if Qdelta signal is present in the bitstream (Indeo5 only) + int quant_mat; ///< dequant matrix index + int glob_quant; ///< quant base for this band + const uint8_t *scan; ///< ptr to the scan pattern + int scan_size; ///< size of the scantable + + IVIHuffTab blk_vlc; ///< vlc table for decoding block data + + int num_corr; ///< number of correction entries + uint8_t corr[61*2]; ///< rvmap correction pairs + int rvmap_sel; ///< rvmap table selector + RVMapDesc *rv_map; ///< ptr to the RLE table for this band + int num_tiles; ///< number of tiles in this band + IVITile *tiles; ///< array of tile descriptors + InvTransformPtr *inv_transform; + int transform_size; + DCTransformPtr *dc_transform; + int is_2d_trans; ///< 1 indicates that the two-dimensional inverse transform is used + int32_t checksum; ///< for debug purposes + int checksum_present; + int bufsize; ///< band buffer size in bytes + const uint16_t *intra_base; ///< quantization matrix for intra blocks + const uint16_t *inter_base; ///< quantization matrix for inter blocks + const uint8_t *intra_scale; ///< quantization coefficient for intra blocks + const uint8_t *inter_scale; ///< quantization coefficient for inter blocks +} IVIBandDesc; + + +/** + * color plane (luma or chroma) information + */ +typedef struct IVIPlaneDesc { + uint16_t width; + uint16_t height; + uint8_t num_bands; ///< number of bands this plane subdivided into + IVIBandDesc *bands; ///< array of band descriptors +} IVIPlaneDesc; + + +typedef struct IVIPicConfig { + uint16_t pic_width; + uint16_t pic_height; + uint16_t chroma_width; + uint16_t chroma_height; + uint16_t tile_width; + uint16_t tile_height; + uint8_t luma_bands; + uint8_t chroma_bands; +} IVIPicConfig; + +typedef struct IVI45DecContext { + GetBitContext gb; + RVMapDesc rvmap_tabs[9]; ///< local corrected copy of the static rvmap tables + + uint32_t frame_num; + int frame_type; + int prev_frame_type; ///< frame type of the previous frame + uint32_t data_size; ///< size of the frame data in bytes from picture header + int is_scalable; + const uint8_t *frame_data; ///< input frame data pointer + int inter_scal; ///< signals a sequence of scalable inter frames + uint32_t frame_size; ///< frame size in bytes + uint32_t pic_hdr_size; ///< picture header size in bytes + uint8_t frame_flags; + uint16_t checksum; ///< frame checksum + + IVIPicConfig pic_conf; + IVIPlaneDesc planes[3]; ///< color planes + + int buf_switch; ///< used to switch between three buffers + int dst_buf; ///< buffer index for the currently decoded frame + int ref_buf; ///< inter frame reference buffer index + int ref2_buf; ///< temporal storage for switching buffers + int b_ref_buf; ///< second reference frame buffer index + + IVIHuffTab mb_vlc; ///< current macroblock table descriptor + IVIHuffTab blk_vlc; ///< current block table descriptor + + uint8_t rvmap_sel; + uint8_t in_imf; + uint8_t in_q; ///< flag for explicitly stored quantiser delta + uint8_t pic_glob_quant; + uint8_t unknown1; + + uint16_t gop_hdr_size; + uint8_t gop_flags; + uint32_t lock_word; + + int (*decode_pic_hdr) (struct IVI45DecContext *ctx, AVCodecContext *avctx); + int (*decode_band_hdr) (struct IVI45DecContext *ctx, IVIBandDesc *band, AVCodecContext *avctx); + int (*decode_mb_info) (struct IVI45DecContext *ctx, IVIBandDesc *band, IVITile *tile, AVCodecContext *avctx); + void (*switch_buffers) (struct IVI45DecContext *ctx); + int (*is_nonnull_frame)(struct IVI45DecContext *ctx); + + int gop_invalid; + int buf_invalid[4]; + + int frame_buf_size; + uint8_t *frame_buf; +} IVI45DecContext; + +/** compare some properties of two pictures */ +static inline int ivi_pic_config_cmp(IVIPicConfig *str1, IVIPicConfig *str2) +{ + return str1->pic_width != str2->pic_width || str1->pic_height != str2->pic_height || + str1->chroma_width != str2->chroma_width || str1->chroma_height != str2->chroma_height || + str1->tile_width != str2->tile_width || str1->tile_height != str2->tile_height || + str1->luma_bands != str2->luma_bands || str1->chroma_bands != str2->chroma_bands; +} + +/** calculate number of tiles in a stride */ +#define IVI_NUM_TILES(stride, tile_size) (((stride) + (tile_size) - 1) / (tile_size)) + +/** calculate number of macroblocks in a tile */ +#define IVI_MBs_PER_TILE(tile_width, tile_height, mb_size) \ + ((((tile_width) + (mb_size) - 1) / (mb_size)) * (((tile_height) + (mb_size) - 1) / (mb_size))) + +/** convert unsigned values into signed ones (the sign is in the LSB) */ +#define IVI_TOSIGNED(val) (-(((val) >> 1) ^ -((val) & 1))) + +/** scale motion vector */ +static inline int ivi_scale_mv(int mv, int mv_scale) +{ + return (mv + (mv > 0) + (mv_scale - 1)) >> mv_scale; +} + +/** + * Initialize static codes used for macroblock and block decoding. + */ +void ff_ivi_init_static_vlc(void); + +/** + * Decode a huffman codebook descriptor from the bitstream + * and select specified huffman table. + * + * @param[in,out] gb the GetBit context + * @param[in] desc_coded flag signalling if table descriptor was coded + * @param[in] which_tab codebook purpose (IVI_MB_HUFF or IVI_BLK_HUFF) + * @param[out] huff_tab pointer to the descriptor of the selected table + * @param[in] avctx AVCodecContext pointer + * @return zero on success, negative value otherwise + */ +int ff_ivi_dec_huff_desc(GetBitContext *gb, int desc_coded, int which_tab, + IVIHuffTab *huff_tab, AVCodecContext *avctx); + +/** + * Initialize planes (prepares descriptors, allocates buffers etc). + * + * @param[in,out] planes pointer to the array of the plane descriptors + * @param[in] cfg pointer to the ivi_pic_config structure describing picture layout + * @param[in] is_indeo4 flag signalling if it is Indeo 4 or not + * @return result code: 0 - OK + */ +int ff_ivi_init_planes(AVCodecContext *avctx, IVIPlaneDesc *planes, + const IVIPicConfig *cfg, int is_indeo4); + +/** + * Initialize tile and macroblock descriptors. + * + * @param[in,out] planes pointer to the array of the plane descriptors + * @param[in] tile_width tile width + * @param[in] tile_height tile height + * @return result code: 0 - OK + */ +int ff_ivi_init_tiles(IVIPlaneDesc *planes, int tile_width, int tile_height); + +int ff_ivi_decode_frame(AVCodecContext *avctx, AVFrame *data, + int *got_frame, const uint8_t *buf, int buf_size); +int ff_ivi_decode_close(AVCodecContext *avctx); + +#endif /* AVCODEC_IVI_H */ diff --git a/libs/ffmpegindeo/ivi_dsp.c b/libs/ffmpegindeo/ivi_dsp.c new file mode 100644 index 00000000000..c2a383ae204 --- /dev/null +++ b/libs/ffmpegindeo/ivi_dsp.c @@ -0,0 +1,551 @@ +/* + * DSP functions for Indeo Video Interactive codecs (Indeo4 and Indeo5) + * + * Copyright (c) 2009-2011 Maxim Poliakovski + * + * 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 + * DSP functions (inverse transforms, motion compensation, wavelet recompositions) + * for Indeo Video Interactive codecs. + */ + +#include <string.h> +#include "ivi.h" +#include "ivi_dsp.h" + +void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst, + const ptrdiff_t dst_pitch) +{ + int x, y, indx; + int32_t p0, p1, p2, p3, tmp0, tmp1, tmp2; + int32_t b0_1, b0_2, b1_1, b1_2, b1_3, b2_1, b2_2, b2_3, b2_4, b2_5, b2_6; + int32_t b3_1, b3_2, b3_3, b3_4, b3_5, b3_6, b3_7, b3_8, b3_9; + ptrdiff_t pitch, back_pitch; + const short *b0_ptr, *b1_ptr, *b2_ptr, *b3_ptr; + const int num_bands = 4; + + /* all bands should have the same pitch */ + pitch = plane->bands[0].pitch; + + /* pixels at the position "y-1" will be set to pixels at the "y" for the 1st iteration */ + back_pitch = 0; + + /* get pointers to the wavelet bands */ + b0_ptr = plane->bands[0].buf; + b1_ptr = plane->bands[1].buf; + b2_ptr = plane->bands[2].buf; + b3_ptr = plane->bands[3].buf; + + for (y = 0; y < plane->height; y += 2) { + + if (y+2 >= plane->height) + pitch= 0; + /* load storage variables with values */ + if (num_bands > 0) { + b0_1 = b0_ptr[0]; + b0_2 = b0_ptr[pitch]; + } + + if (num_bands > 1) { + b1_1 = b1_ptr[back_pitch]; + b1_2 = b1_ptr[0]; + b1_3 = b1_1 - b1_2*6 + b1_ptr[pitch]; + } + + if (num_bands > 2) { + b2_2 = b2_ptr[0]; // b2[x, y ] + b2_3 = b2_2; // b2[x+1,y ] = b2[x,y] + b2_5 = b2_ptr[pitch]; // b2[x ,y+1] + b2_6 = b2_5; // b2[x+1,y+1] = b2[x,y+1] + } + + if (num_bands > 3) { + b3_2 = b3_ptr[back_pitch]; // b3[x ,y-1] + b3_3 = b3_2; // b3[x+1,y-1] = b3[x ,y-1] + b3_5 = b3_ptr[0]; // b3[x ,y ] + b3_6 = b3_5; // b3[x+1,y ] = b3[x ,y ] + b3_8 = b3_2 - b3_5*6 + b3_ptr[pitch]; + b3_9 = b3_8; + } + + for (x = 0, indx = 0; x < plane->width; x+=2, indx++) { + if (x+2 >= plane->width) { + b0_ptr --; + b1_ptr --; + b2_ptr --; + b3_ptr --; + } + + /* some values calculated in the previous iterations can */ + /* be reused in the next ones, so do appropriate copying */ + b2_1 = b2_2; // b2[x-1,y ] = b2[x, y ] + b2_2 = b2_3; // b2[x ,y ] = b2[x+1,y ] + b2_4 = b2_5; // b2[x-1,y+1] = b2[x ,y+1] + b2_5 = b2_6; // b2[x ,y+1] = b2[x+1,y+1] + b3_1 = b3_2; // b3[x-1,y-1] = b3[x ,y-1] + b3_2 = b3_3; // b3[x ,y-1] = b3[x+1,y-1] + b3_4 = b3_5; // b3[x-1,y ] = b3[x ,y ] + b3_5 = b3_6; // b3[x ,y ] = b3[x+1,y ] + b3_7 = b3_8; // vert_HPF(x-1) + b3_8 = b3_9; // vert_HPF(x ) + + p0 = p1 = p2 = p3 = 0; + + /* process the LL-band by applying LPF both vertically and horizontally */ + if (num_bands > 0) { + tmp0 = b0_1; + tmp2 = b0_2; + b0_1 = b0_ptr[indx+1]; + b0_2 = b0_ptr[pitch+indx+1]; + tmp1 = tmp0 + b0_1; + + p0 = tmp0 * 16; + p1 = tmp1 * 8; + p2 = (tmp0 + tmp2) * 8; + p3 = (tmp1 + tmp2 + b0_2) * 4; + } + + /* process the HL-band by applying HPF vertically and LPF horizontally */ + if (num_bands > 1) { + tmp0 = b1_2; + tmp1 = b1_1; + b1_2 = b1_ptr[indx+1]; + b1_1 = b1_ptr[back_pitch+indx+1]; + + tmp2 = tmp1 - tmp0*6 + b1_3; + b1_3 = b1_1 - b1_2*6 + b1_ptr[pitch+indx+1]; + + p0 += (tmp0 + tmp1) * 8; + p1 += (tmp0 + tmp1 + b1_1 + b1_2) * 4; + p2 += tmp2 * 4; + p3 += (tmp2 + b1_3) * 2; + } + + /* process the LH-band by applying LPF vertically and HPF horizontally */ + if (num_bands > 2) { + b2_3 = b2_ptr[indx+1]; + b2_6 = b2_ptr[pitch+indx+1]; + + tmp0 = b2_1 + b2_2; + tmp1 = b2_1 - b2_2*6 + b2_3; + + p0 += tmp0 * 8; + p1 += tmp1 * 4; + p2 += (tmp0 + b2_4 + b2_5) * 4; + p3 += (tmp1 + b2_4 - b2_5*6 + b2_6) * 2; + } + + /* process the HH-band by applying HPF both vertically and horizontally */ + if (num_bands > 3) { + b3_6 = b3_ptr[indx+1]; // b3[x+1,y ] + b3_3 = b3_ptr[back_pitch+indx+1]; // b3[x+1,y-1] + + tmp0 = b3_1 + b3_4; + tmp1 = b3_2 + b3_5; + tmp2 = b3_3 + b3_6; + + b3_9 = b3_3 - b3_6*6 + b3_ptr[pitch+indx+1]; + + p0 += (tmp0 + tmp1) * 4; + p1 += (tmp0 - tmp1*6 + tmp2) * 2; + p2 += (b3_7 + b3_8) * 2; + p3 += b3_7 - b3_8*6 + b3_9; + } + + /* output four pixels */ + dst[x] = av_clip_uint8((p0 >> 6) + 128); + dst[x+1] = av_clip_uint8((p1 >> 6) + 128); + dst[dst_pitch+x] = av_clip_uint8((p2 >> 6) + 128); + dst[dst_pitch+x+1] = av_clip_uint8((p3 >> 6) + 128); + }// for x + + dst += dst_pitch << 1; + + back_pitch = -pitch; + + b0_ptr += pitch + 1; + b1_ptr += pitch + 1; + b2_ptr += pitch + 1; + b3_ptr += pitch + 1; + } +} + + +/** butterfly operation for the inverse slant transform */ +#define IVI_SLANT_BFLY(s1, s2, o1, o2, t) \ + t = (s1) - (s2);\ + o1 = (s1) + (s2);\ + o2 = (t);\ + +/** This is a reflection a,b = 1/2, 5/4 for the inverse slant transform */ +#define IVI_IREFLECT(s1, s2, o1, o2, t) \ + t = (((s1) + (s2)*2 + 2) >> 2) + (s1);\ + o2 = (((s1)*2 - (s2) + 2) >> 2) - (s2);\ + o1 = (t);\ + +/** This is a reflection a,b = 1/2, 7/8 for the inverse slant transform */ +#define IVI_SLANT_PART4(s1, s2, o1, o2, t) \ + t = (s2) + (((s1)*4 - (s2) + 4) >> 3);\ + o2 = (s1) + ((-(s1) - (s2)*4 + 4) >> 3);\ + o1 = (t);\ + +/** inverse slant8 transform */ +#define IVI_INV_SLANT8(s1, s4, s8, s5, s2, s6, s3, s7,\ + d1, d2, d3, d4, d5, d6, d7, d8,\ + t0, t1, t2, t3, t4, t5, t6, t7, t8) {\ + IVI_SLANT_PART4(s4, s5, t4, t5, t0);\ +\ + IVI_SLANT_BFLY(s1, t5, t1, t5, t0); IVI_SLANT_BFLY(s2, s6, t2, t6, t0);\ + IVI_SLANT_BFLY(s7, s3, t7, t3, t0); IVI_SLANT_BFLY(t4, s8, t4, t8, t0);\ +\ + IVI_SLANT_BFLY(t1, t2, t1, t2, t0); IVI_IREFLECT (t4, t3, t4, t3, t0);\ + IVI_SLANT_BFLY(t5, t6, t5, t6, t0); IVI_IREFLECT (t8, t7, t8, t7, t0);\ + IVI_SLANT_BFLY(t1, t4, t1, t4, t0); IVI_SLANT_BFLY(t2, t3, t2, t3, t0);\ + IVI_SLANT_BFLY(t5, t8, t5, t8, t0); IVI_SLANT_BFLY(t6, t7, t6, t7, t0);\ + d1 = COMPENSATE(t1);\ + d2 = COMPENSATE(t2);\ + d3 = COMPENSATE(t3);\ + d4 = COMPENSATE(t4);\ + d5 = COMPENSATE(t5);\ + d6 = COMPENSATE(t6);\ + d7 = COMPENSATE(t7);\ + d8 = COMPENSATE(t8);} + +/** inverse slant4 transform */ +#define IVI_INV_SLANT4(s1, s4, s2, s3, d1, d2, d3, d4, t0, t1, t2, t3, t4) {\ + IVI_SLANT_BFLY(s1, s2, t1, t2, t0); IVI_IREFLECT (s4, s3, t4, t3, t0);\ +\ + IVI_SLANT_BFLY(t1, t4, t1, t4, t0); IVI_SLANT_BFLY(t2, t3, t2, t3, t0);\ + d1 = COMPENSATE(t1);\ + d2 = COMPENSATE(t2);\ + d3 = COMPENSATE(t3);\ + d4 = COMPENSATE(t4);} + +void ff_ivi_inverse_slant_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i; + const int32_t *src; + int32_t *dst; + int tmp[64]; + int t0, t1, t2, t3, t4, t5, t6, t7, t8; + +#define COMPENSATE(x) (x) + src = in; + dst = tmp; + for (i = 0; i < 8; i++) { + if (flags[i]) { + IVI_INV_SLANT8(src[0], src[8], src[16], src[24], src[32], src[40], src[48], src[56], + dst[0], dst[8], dst[16], dst[24], dst[32], dst[40], dst[48], dst[56], + t0, t1, t2, t3, t4, t5, t6, t7, t8); + } else + dst[0] = dst[8] = dst[16] = dst[24] = dst[32] = dst[40] = dst[48] = dst[56] = 0; + + src++; + dst++; + } +#undef COMPENSATE + +#define COMPENSATE(x) (((x) + 1)>>1) + src = tmp; + for (i = 0; i < 8; i++) { + if (!src[0] && !src[1] && !src[2] && !src[3] && !src[4] && !src[5] && !src[6] && !src[7]) { + memset(out, 0, 8*sizeof(out[0])); + } else { + IVI_INV_SLANT8(src[0], src[1], src[2], src[3], src[4], src[5], src[6], src[7], + out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], + t0, t1, t2, t3, t4, t5, t6, t7, t8); + } + src += 8; + out += pitch; + } +#undef COMPENSATE +} + +void ff_ivi_inverse_slant_4x4(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i; + const int32_t *src; + int32_t *dst; + int tmp[16]; + int t0, t1, t2, t3, t4; + +#define COMPENSATE(x) (x) + src = in; + dst = tmp; + for (i = 0; i < 4; i++) { + if (flags[i]) { + IVI_INV_SLANT4(src[0], src[4], src[8], src[12], + dst[0], dst[4], dst[8], dst[12], + t0, t1, t2, t3, t4); + } else + dst[0] = dst[4] = dst[8] = dst[12] = 0; + + src++; + dst++; + } +#undef COMPENSATE + +#define COMPENSATE(x) (((x) + 1)>>1) + src = tmp; + for (i = 0; i < 4; i++) { + if (!src[0] && !src[1] && !src[2] && !src[3]) { + out[0] = out[1] = out[2] = out[3] = 0; + } else { + IVI_INV_SLANT4(src[0], src[1], src[2], src[3], + out[0], out[1], out[2], out[3], + t0, t1, t2, t3, t4); + } + src += 4; + out += pitch; + } +#undef COMPENSATE +} + +void ff_ivi_dc_slant_2d(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size) +{ + int x, y; + int16_t dc_coeff; + + dc_coeff = (*in + 1) >> 1; + + for (y = 0; y < blk_size; out += pitch, y++) { + for (x = 0; x < blk_size; x++) + out[x] = dc_coeff; + } +} + +void ff_ivi_row_slant8(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i; + int t0, t1, t2, t3, t4, t5, t6, t7, t8; + +#define COMPENSATE(x) (((x) + 1)>>1) + for (i = 0; i < 8; i++) { + if (!in[0] && !in[1] && !in[2] && !in[3] && !in[4] && !in[5] && !in[6] && !in[7]) { + memset(out, 0, 8*sizeof(out[0])); + } else { + IVI_INV_SLANT8( in[0], in[1], in[2], in[3], in[4], in[5], in[6], in[7], + out[0], out[1], out[2], out[3], out[4], out[5], out[6], out[7], + t0, t1, t2, t3, t4, t5, t6, t7, t8); + } + in += 8; + out += pitch; + } +#undef COMPENSATE +} + +void ff_ivi_dc_row_slant(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size) +{ + int x, y; + int16_t dc_coeff; + + dc_coeff = (*in + 1) >> 1; + + for (x = 0; x < blk_size; x++) + out[x] = dc_coeff; + + out += pitch; + + for (y = 1; y < blk_size; out += pitch, y++) { + for (x = 0; x < blk_size; x++) + out[x] = 0; + } +} + +void ff_ivi_col_slant8(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i, row2, row4, row8; + int t0, t1, t2, t3, t4, t5, t6, t7, t8; + + row2 = pitch << 1; + row4 = pitch << 2; + row8 = pitch << 3; + +#define COMPENSATE(x) (((x) + 1)>>1) + for (i = 0; i < 8; i++) { + if (flags[i]) { + IVI_INV_SLANT8(in[0], in[8], in[16], in[24], in[32], in[40], in[48], in[56], + out[0], out[pitch], out[row2], out[row2 + pitch], out[row4], + out[row4 + pitch], out[row4 + row2], out[row8 - pitch], + t0, t1, t2, t3, t4, t5, t6, t7, t8); + } else { + out[0] = out[pitch] = out[row2] = out[row2 + pitch] = out[row4] = + out[row4 + pitch] = out[row4 + row2] = out[row8 - pitch] = 0; + } + + in++; + out++; + } +#undef COMPENSATE +} + +void ff_ivi_dc_col_slant(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size) +{ + int x, y; + int16_t dc_coeff; + + dc_coeff = (*in + 1) >> 1; + + for (y = 0; y < blk_size; out += pitch, y++) { + out[0] = dc_coeff; + for (x = 1; x < blk_size; x++) + out[x] = 0; + } +} + +void ff_ivi_row_slant4(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i; + int t0, t1, t2, t3, t4; + +#define COMPENSATE(x) (((x) + 1)>>1) + for (i = 0; i < 4; i++) { + if (!in[0] && !in[1] && !in[2] && !in[3]) { + memset(out, 0, 4*sizeof(out[0])); + } else { + IVI_INV_SLANT4( in[0], in[1], in[2], in[3], + out[0], out[1], out[2], out[3], + t0, t1, t2, t3, t4); + } + in += 4; + out += pitch; + } +#undef COMPENSATE +} + +void ff_ivi_col_slant4(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags) +{ + int i, row2; + int t0, t1, t2, t3, t4; + + row2 = pitch << 1; + +#define COMPENSATE(x) (((x) + 1)>>1) + for (i = 0; i < 4; i++) { + if (flags[i]) { + IVI_INV_SLANT4(in[0], in[4], in[8], in[12], + out[0], out[pitch], out[row2], out[row2 + pitch], + t0, t1, t2, t3, t4); + } else { + out[0] = out[pitch] = out[row2] = out[row2 + pitch] = 0; + } + + in++; + out++; + } +#undef COMPENSATE +} + +void ff_ivi_put_pixels_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags) +{ + int x, y; + + for (y = 0; y < 8; out += pitch, in += 8, y++) + for (x = 0; x < 8; x++) + out[x] = in[x]; +} + +void ff_ivi_put_dc_pixel_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, + int blk_size) +{ + int y; + + out[0] = in[0]; + memset(out + 1, 0, 7*sizeof(out[0])); + out += pitch; + + for (y = 1; y < 8; out += pitch, y++) + memset(out, 0, 8*sizeof(out[0])); +} + +#define IVI_MC_TEMPLATE(size, suffix, OP) \ +static void ivi_mc_ ## size ##x## size ## suffix(int16_t *buf, \ + ptrdiff_t dpitch, \ + const int16_t *ref_buf, \ + ptrdiff_t pitch, int mc_type) \ +{ \ + int i, j; \ + const int16_t *wptr; \ +\ + switch (mc_type) { \ + case 0: /* fullpel (no interpolation) */ \ + for (i = 0; i < size; i++, buf += dpitch, ref_buf += pitch) { \ + for (j = 0; j < size; j++) {\ + OP(buf[j], ref_buf[j]); \ + } \ + } \ + break; \ + case 1: /* horizontal halfpel interpolation */ \ + for (i = 0; i < size; i++, buf += dpitch, ref_buf += pitch) \ + for (j = 0; j < size; j++) \ + OP(buf[j], (ref_buf[j] + ref_buf[j+1]) >> 1); \ + break; \ + case 2: /* vertical halfpel interpolation */ \ + wptr = ref_buf + pitch; \ + for (i = 0; i < size; i++, buf += dpitch, wptr += pitch, ref_buf += pitch) \ + for (j = 0; j < size; j++) \ + OP(buf[j], (ref_buf[j] + wptr[j]) >> 1); \ + break; \ + case 3: /* vertical and horizontal halfpel interpolation */ \ + wptr = ref_buf + pitch; \ + for (i = 0; i < size; i++, buf += dpitch, wptr += pitch, ref_buf += pitch) \ + for (j = 0; j < size; j++) \ + OP(buf[j], (ref_buf[j] + ref_buf[j+1] + wptr[j] + wptr[j+1]) >> 2); \ + break; \ + } \ +} \ +\ +void ff_ivi_mc_ ## size ##x## size ## suffix(int16_t *buf, const int16_t *ref_buf, \ + ptrdiff_t pitch, int mc_type) \ +{ \ + ivi_mc_ ## size ##x## size ## suffix(buf, pitch, ref_buf, pitch, mc_type); \ +} \ + +#define IVI_MC_AVG_TEMPLATE(size, suffix, OP) \ +void ff_ivi_mc_avg_ ## size ##x## size ## suffix(int16_t *buf, \ + const int16_t *ref_buf, \ + const int16_t *ref_buf2, \ + ptrdiff_t pitch, \ + int mc_type, int mc_type2) \ +{ \ + int16_t tmp[size * size]; \ + int i, j; \ +\ + ivi_mc_ ## size ##x## size ## _no_delta(tmp, size, ref_buf, pitch, mc_type); \ + ivi_mc_ ## size ##x## size ## _delta(tmp, size, ref_buf2, pitch, mc_type2); \ + for (i = 0; i < size; i++, buf += pitch) { \ + for (j = 0; j < size; j++) {\ + OP(buf[j], tmp[i * size + j] >> 1); \ + } \ + } \ +} \ + +#define OP_PUT(a, b) (a) = (b) +#define OP_ADD(a, b) (a) += (b) + +IVI_MC_TEMPLATE(8, _no_delta, OP_PUT) +IVI_MC_TEMPLATE(8, _delta, OP_ADD) +IVI_MC_TEMPLATE(4, _no_delta, OP_PUT) +IVI_MC_TEMPLATE(4, _delta, OP_ADD) +IVI_MC_AVG_TEMPLATE(8, _no_delta, OP_PUT) +IVI_MC_AVG_TEMPLATE(8, _delta, OP_ADD) +IVI_MC_AVG_TEMPLATE(4, _no_delta, OP_PUT) +IVI_MC_AVG_TEMPLATE(4, _delta, OP_ADD) diff --git a/libs/ffmpegindeo/ivi_dsp.h b/libs/ffmpegindeo/ivi_dsp.h new file mode 100644 index 00000000000..3a14148624f --- /dev/null +++ b/libs/ffmpegindeo/ivi_dsp.h @@ -0,0 +1,244 @@ +/* + * DSP functions for Indeo Video Interactive codecs (Indeo4 and Indeo5) + * + * Copyright (c) 2009-2011 Maxim Poliakovski + * + * 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 + * DSP functions (inverse transforms, motion compensations, wavelet recomposition) + * for Indeo Video Interactive codecs. + */ + +#ifndef AVCODEC_IVI_DSP_H +#define AVCODEC_IVI_DSP_H + +#include <stddef.h> +#include <stdint.h> + +#include "ivi.h" + +/** + * 5/3 wavelet recomposition filter for Indeo5 + * + * @param[in] plane pointer to the descriptor of the plane being processed + * @param[out] dst pointer to the destination buffer + * @param[in] dst_pitch pitch of the destination buffer + */ +void ff_ivi_recompose53(const IVIPlaneDesc *plane, uint8_t *dst, + const ptrdiff_t dst_pitch); + + +/** + * two-dimensional inverse slant 8x8 transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags: + * != 0 - non_empty column, 0 - empty one + * (this array must be filled by caller) + */ +void ff_ivi_inverse_slant_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * two-dimensional inverse slant 4x4 transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags: + * != 0 - non_empty column, 0 - empty one + * (this array must be filled by caller) + */ +void ff_ivi_inverse_slant_4x4(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * DC-only two-dimensional inverse slant transform. + * Performing the inverse slant transform in this case is equivalent to + * spreading (DC_coeff + 1)/2 over the whole block. + * It works much faster than performing the slant transform on a vector of zeroes. + * + * @param[in] in pointer to the dc coefficient + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] blk_size transform block size + */ +void ff_ivi_dc_slant_2d(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size); + +/** + * inverse 1D row slant transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags (unused here) + */ +void ff_ivi_row_slant8(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * inverse 1D column slant transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags: + * != 0 - non_empty column, 0 - empty one + * (this array must be filled by caller) + */ +void ff_ivi_col_slant8(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * inverse 1D row slant transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags (unused here) + */ +void ff_ivi_row_slant4(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * inverse 1D column slant transform + * + * @param[in] in pointer to the vector of transform coefficients + * @param[out] out pointer to the output buffer (frame) + * @param[in] pitch pitch to move to the next y line + * @param[in] flags pointer to the array of column flags: + * != 0 - non_empty column, 0 - empty one + * (this array must be filled by caller) + */ +void ff_ivi_col_slant4(const int32_t *in, int16_t *out, ptrdiff_t pitch, + const uint8_t *flags); + +/** + * DC-only inverse row slant transform + */ +void ff_ivi_dc_row_slant(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size); + +/** + * DC-only inverse column slant transform + */ +void ff_ivi_dc_col_slant(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size); + +/** + * Copy the pixels into the frame buffer. + */ +void ff_ivi_put_pixels_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, const uint8_t *flags); + +/** + * Copy the DC coefficient into the first pixel of the block and + * zero all others. + */ +void ff_ivi_put_dc_pixel_8x8(const int32_t *in, int16_t *out, ptrdiff_t pitch, int blk_size); + +/** + * 8x8 block motion compensation with adding delta + * + * @param[in,out] buf pointer to the block in the current frame buffer containing delta + * @param[in] ref_buf pointer to the corresponding block in the reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type + */ +void ff_ivi_mc_8x8_delta(int16_t *buf, const int16_t *ref_buf, ptrdiff_t pitch, int mc_type); + +/** + * 4x4 block motion compensation with adding delta + * + * @param[in,out] buf pointer to the block in the current frame buffer containing delta + * @param[in] ref_buf pointer to the corresponding block in the reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type + */ +void ff_ivi_mc_4x4_delta(int16_t *buf, const int16_t *ref_buf, ptrdiff_t pitch, int mc_type); + +/** + * motion compensation without adding delta + * + * @param[in,out] buf pointer to the block in the current frame receiving the result + * @param[in] ref_buf pointer to the corresponding block in the reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type + */ +void ff_ivi_mc_8x8_no_delta(int16_t *buf, const int16_t *ref_buf, ptrdiff_t pitch, int mc_type); + +/** + * 4x4 block motion compensation without adding delta + * + * @param[in,out] buf pointer to the block in the current frame receiving the result + * @param[in] ref_buf pointer to the corresponding block in the reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type + */ +void ff_ivi_mc_4x4_no_delta(int16_t *buf, const int16_t *ref_buf, ptrdiff_t pitch, int mc_type); + +/** + * 8x8 block motion compensation with adding delta + * + * @param[in,out] buf pointer to the block in the current frame buffer containing delta + * @param[in] ref_buf pointer to the corresponding block in the backward reference frame + * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type for backward reference + * @param[in] mc_type2 interpolation type for forward reference + */ +void ff_ivi_mc_avg_8x8_delta(int16_t *buf, const int16_t *ref_buf, const int16_t *ref_buf2, ptrdiff_t pitch, int mc_type, int mc_type2); + +/** + * 4x4 block motion compensation with adding delta + * + * @param[in,out] buf pointer to the block in the current frame buffer containing delta + * @param[in] ref_buf pointer to the corresponding block in the backward reference frame + * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type for backward reference + * @param[in] mc_type2 interpolation type for forward reference + */ +void ff_ivi_mc_avg_4x4_delta(int16_t *buf, const int16_t *ref_buf, const int16_t *ref_buf2, ptrdiff_t pitch, int mc_type, int mc_type2); + +/** + * motion compensation without adding delta for B-frames + * + * @param[in,out] buf pointer to the block in the current frame receiving the result + * @param[in] ref_buf pointer to the corresponding block in the backward reference frame + * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type for backward reference + * @param[in] mc_type2 interpolation type for forward reference + */ +void ff_ivi_mc_avg_8x8_no_delta(int16_t *buf, const int16_t *ref_buf, const int16_t *ref_buf2, ptrdiff_t pitch, int mc_type, int mc_type2); + +/** + * 4x4 block motion compensation without adding delta for B-frames + * + * @param[in,out] buf pointer to the block in the current frame receiving the result + * @param[in] ref_buf pointer to the corresponding block in the backward reference frame + * @param[in] ref_buf2 pointer to the corresponding block in the forward reference frame + * @param[in] pitch pitch for moving to the next y line + * @param[in] mc_type interpolation type for backward reference + * @param[in] mc_type2 interpolation type for forward reference + */ +void ff_ivi_mc_avg_4x4_no_delta(int16_t *buf, const int16_t *ref_buf, const int16_t *ref_buf2, ptrdiff_t pitch, int mc_type, int mc_type2); + +#endif /* AVCODEC_IVI_DSP_H */ diff --git a/libs/ffmpegindeo/vlc.c b/libs/ffmpegindeo/vlc.c new file mode 100644 index 00000000000..d97e6b565fd --- /dev/null +++ b/libs/ffmpegindeo/vlc.c @@ -0,0 +1,353 @@ +/* + * API for creating VLC trees + * Copyright (c) 2000, 2001 Fabrice Bellard + * Copyright (c) 2002-2004 Michael Niedermayer michaelni@gmx.at + * Copyright (c) 2010 Loren Merritt + * + * 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 <inttypes.h> +#include <stdint.h> +#include <stdlib.h> +#include <string.h> + +#include "indeo_compat.h" +#include "vlc.h" + +#define GET_DATA(v, table, i, wrap, size) \ +{ \ + const uint8_t *ptr = (const uint8_t *)table + i * wrap; \ + switch(size) { \ + case 1: \ + v = *(const uint8_t *)ptr; \ + break; \ + case 2: \ + v = *(const uint16_t *)ptr; \ + break; \ + case 4: \ + default: \ + av_assert1(size == 4); \ + v = *(const uint32_t *)ptr; \ + break; \ + } \ +} + +static const uint8_t ff_reverse[256] = { +0x00,0x80,0x40,0xC0,0x20,0xA0,0x60,0xE0,0x10,0x90,0x50,0xD0,0x30,0xB0,0x70,0xF0, +0x08,0x88,0x48,0xC8,0x28,0xA8,0x68,0xE8,0x18,0x98,0x58,0xD8,0x38,0xB8,0x78,0xF8, +0x04,0x84,0x44,0xC4,0x24,0xA4,0x64,0xE4,0x14,0x94,0x54,0xD4,0x34,0xB4,0x74,0xF4, +0x0C,0x8C,0x4C,0xCC,0x2C,0xAC,0x6C,0xEC,0x1C,0x9C,0x5C,0xDC,0x3C,0xBC,0x7C,0xFC, +0x02,0x82,0x42,0xC2,0x22,0xA2,0x62,0xE2,0x12,0x92,0x52,0xD2,0x32,0xB2,0x72,0xF2, +0x0A,0x8A,0x4A,0xCA,0x2A,0xAA,0x6A,0xEA,0x1A,0x9A,0x5A,0xDA,0x3A,0xBA,0x7A,0xFA, +0x06,0x86,0x46,0xC6,0x26,0xA6,0x66,0xE6,0x16,0x96,0x56,0xD6,0x36,0xB6,0x76,0xF6, +0x0E,0x8E,0x4E,0xCE,0x2E,0xAE,0x6E,0xEE,0x1E,0x9E,0x5E,0xDE,0x3E,0xBE,0x7E,0xFE, +0x01,0x81,0x41,0xC1,0x21,0xA1,0x61,0xE1,0x11,0x91,0x51,0xD1,0x31,0xB1,0x71,0xF1, +0x09,0x89,0x49,0xC9,0x29,0xA9,0x69,0xE9,0x19,0x99,0x59,0xD9,0x39,0xB9,0x79,0xF9, +0x05,0x85,0x45,0xC5,0x25,0xA5,0x65,0xE5,0x15,0x95,0x55,0xD5,0x35,0xB5,0x75,0xF5, +0x0D,0x8D,0x4D,0xCD,0x2D,0xAD,0x6D,0xED,0x1D,0x9D,0x5D,0xDD,0x3D,0xBD,0x7D,0xFD, +0x03,0x83,0x43,0xC3,0x23,0xA3,0x63,0xE3,0x13,0x93,0x53,0xD3,0x33,0xB3,0x73,0xF3, +0x0B,0x8B,0x4B,0xCB,0x2B,0xAB,0x6B,0xEB,0x1B,0x9B,0x5B,0xDB,0x3B,0xBB,0x7B,0xFB, +0x07,0x87,0x47,0xC7,0x27,0xA7,0x67,0xE7,0x17,0x97,0x57,0xD7,0x37,0xB7,0x77,0xF7, +0x0F,0x8F,0x4F,0xCF,0x2F,0xAF,0x6F,0xEF,0x1F,0x9F,0x5F,0xDF,0x3F,0xBF,0x7F,0xFF, +}; + +static void *av_malloc_array(size_t nmemb, size_t size) +{ + return malloc(nmemb * size); +} + +static void *av_realloc_f(void *ptr, size_t nelem, size_t esize) +{ + void *r = realloc(ptr, esize * nelem); + if (!r) + free(ptr); + return r; +} + +static int alloc_table(VLC *vlc, int size, int use_static) +{ + int index = vlc->table_size; + + vlc->table_size += size; + if (vlc->table_size > vlc->table_allocated) { + if (use_static) + abort(); // cannot do anything, init_vlc() is used with too little memory + vlc->table_allocated += (1 << vlc->bits); + vlc->table = av_realloc_f(vlc->table, vlc->table_allocated, sizeof(*vlc->table)); + if (!vlc->table) { + vlc->table_allocated = 0; + vlc->table_size = 0; + return AVERROR(ENOMEM); + } + memset(vlc->table + vlc->table_allocated - (1 << vlc->bits), 0, sizeof(*vlc->table) << vlc->bits); + } + return index; +} + +#define LOCALBUF_ELEMS 1500 // the maximum currently needed is 1296 by rv34 + +static av_always_inline uint32_t bitswap_32(uint32_t x) +{ + return (uint32_t)ff_reverse[ x & 0xFF] << 24 | + (uint32_t)ff_reverse[(x >> 8) & 0xFF] << 16 | + (uint32_t)ff_reverse[(x >> 16) & 0xFF] << 8 | + (uint32_t)ff_reverse[ x >> 24]; +} + +typedef struct VLCcode { + uint8_t bits; + VLCBaseType symbol; + /** codeword, with the first bit-to-be-read in the msb + * (even if intended for a little-endian bitstream reader) */ + uint32_t code; +} VLCcode; + +static int vlc_common_init(VLC *vlc, int nb_bits, int nb_codes, + VLCcode **buf, int flags) +{ + vlc->bits = nb_bits; + vlc->table_size = 0; + if (flags & INIT_VLC_USE_NEW_STATIC) { + av_assert0(nb_codes <= LOCALBUF_ELEMS); + } else { + vlc->table = NULL; + vlc->table_allocated = 0; + } + if (nb_codes > LOCALBUF_ELEMS) { + *buf = av_malloc_array(nb_codes, sizeof(VLCcode)); + if (!*buf) + return AVERROR(ENOMEM); + } + + return 0; +} + +static int compare_vlcspec(const void *a, const void *b) +{ + const VLCcode *sa = a, *sb = b; + return (sa->code >> 1) - (sb->code >> 1); +} + +/** + * Build VLC decoding tables suitable for use with get_vlc(). + * + * @param vlc the context to be initialized + * + * @param table_nb_bits max length of vlc codes to store directly in this table + * (Longer codes are delegated to subtables.) + * + * @param nb_codes number of elements in codes[] + * + * @param codes descriptions of the vlc codes + * These must be ordered such that codes going into the same subtable are contiguous. + * Sorting by VLCcode.code is sufficient, though not necessary. + */ +static int build_table(VLC *vlc, int table_nb_bits, int nb_codes, + VLCcode *codes, int flags) +{ + int table_size, table_index; + VLCElem *table; + + if (table_nb_bits > 30) + return AVERROR(EINVAL); + table_size = 1 << table_nb_bits; + table_index = alloc_table(vlc, table_size, flags & INIT_VLC_USE_NEW_STATIC); + ff_dlog(NULL, "new table index=%d size=%d\n", table_index, table_size); + if (table_index < 0) + return table_index; + table = &vlc->table[table_index]; + + /* first pass: map codes and compute auxiliary table sizes */ + for (int i = 0; i < nb_codes; i++) { + int n = codes[i].bits; + uint32_t code = codes[i].code; + int symbol = codes[i].symbol; + ff_dlog(NULL, "i=%d n=%d code=0x%"PRIx32"\n", i, n, code); + if (n <= table_nb_bits) { + /* no need to add another table */ + int j = code >> (32 - table_nb_bits); + int nb = 1 << (table_nb_bits - n); + int inc = 1; + + if (flags & INIT_VLC_OUTPUT_LE) { + j = bitswap_32(code); + inc = 1 << n; + } + for (int k = 0; k < nb; k++) { + int bits = table[j].len; + int oldsym = table[j].sym; + ff_dlog(NULL, "%4x: code=%d n=%d\n", j, i, n); + if ((bits || oldsym) && (bits != n || oldsym != symbol)) { + av_log(NULL, AV_LOG_ERROR, "incorrect codes\n"); + return AVERROR_INVALIDDATA; + } + table[j].len = n; + table[j].sym = symbol; + j += inc; + } + } else { + /* fill auxiliary table recursively */ + uint32_t code_prefix; + int index, subtable_bits, j, k; + + n -= table_nb_bits; + code_prefix = code >> (32 - table_nb_bits); + subtable_bits = n; + codes[i].bits = n; + codes[i].code = code << table_nb_bits; + for (k = i + 1; k < nb_codes; k++) { + n = codes[k].bits - table_nb_bits; + if (n <= 0) + break; + code = codes[k].code; + if (code >> (32 - table_nb_bits) != code_prefix) + break; + codes[k].bits = n; + codes[k].code = code << table_nb_bits; + subtable_bits = FFMAX(subtable_bits, n); + } + subtable_bits = FFMIN(subtable_bits, table_nb_bits); + j = (flags & INIT_VLC_OUTPUT_LE) ? bitswap_32(code_prefix) >> (32 - table_nb_bits) : code_prefix; + table[j].len = -subtable_bits; + ff_dlog(NULL, "%4x: n=%d (subtable)\n", + j, codes[i].bits + table_nb_bits); + index = build_table(vlc, subtable_bits, k-i, codes+i, flags); + if (index < 0) + return index; + /* note: realloc has been done, so reload tables */ + table = &vlc->table[table_index]; + table[j].sym = index; + if (table[j].sym != index) { + return AVERROR_PATCHWELCOME; + } + i = k-1; + } + } + + for (int i = 0; i < table_size; i++) { + if (table[i].len == 0) + table[i].sym = -1; + } + + return table_index; +} + +static int vlc_common_end(VLC *vlc, int nb_bits, int nb_codes, VLCcode *codes, + int flags, VLCcode localbuf[LOCALBUF_ELEMS]) +{ + int ret = build_table(vlc, nb_bits, nb_codes, codes, flags); + + if (flags & INIT_VLC_USE_NEW_STATIC) { + if (vlc->table_size != vlc->table_allocated && + !(flags & (INIT_VLC_STATIC_OVERLONG & ~INIT_VLC_USE_NEW_STATIC))) + av_log(NULL, AV_LOG_ERROR, "needed %d had %d\n", vlc->table_size, vlc->table_allocated); + av_assert0(ret >= 0); + } else { + if (codes != localbuf) + av_free(codes); + if (ret < 0) { + av_freep(&vlc->table); + return ret; + } + } + return 0; +} + +/* Build VLC decoding tables suitable for use with get_vlc(). + + 'nb_bits' sets the decoding table size (2^nb_bits) entries. The + bigger it is, the faster is the decoding. But it should not be too + big to save memory and L1 cache. '9' is a good compromise. + + 'nb_codes' : number of vlcs codes + + 'bits' : table which gives the size (in bits) of each vlc code. + + 'codes' : table which gives the bit pattern of of each vlc code. + + 'symbols' : table which gives the values to be returned from get_vlc(). + + 'xxx_wrap' : give the number of bytes between each entry of the + 'bits' or 'codes' tables. + + 'xxx_size' : gives the number of bytes of each entry of the 'bits' + or 'codes' tables. Currently 1,2 and 4 are supported. + + 'wrap' and 'size' make it possible to use any memory configuration and types + (byte/word/long) to store the 'bits', 'codes', and 'symbols' tables. +*/ +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags) +{ + VLCcode localbuf[LOCALBUF_ELEMS], *buf = localbuf; + int j, ret; + + ret = vlc_common_init(vlc, nb_bits, nb_codes, &buf, flags); + if (ret < 0) + return ret; + + av_assert0(symbols_size <= 2 || !symbols); + j = 0; +#define COPY(condition)\ + for (int i = 0; i < nb_codes; i++) { \ + unsigned len; \ + GET_DATA(len, bits, i, bits_wrap, bits_size); \ + if (!(condition)) \ + continue; \ + if (len > 3*nb_bits || len > 32) { \ + av_log(NULL, AV_LOG_ERROR, "Too long VLC (%u) in init_vlc\n", len);\ + if (buf != localbuf) \ + av_free(buf); \ + return AVERROR(EINVAL); \ + } \ + buf[j].bits = len; \ + GET_DATA(buf[j].code, codes, i, codes_wrap, codes_size); \ + if (buf[j].code >= (1LL<<buf[j].bits)) { \ + av_log(NULL, AV_LOG_ERROR, "Invalid code %"PRIx32" for %d in " \ + "init_vlc\n", buf[j].code, i); \ + if (buf != localbuf) \ + av_free(buf); \ + return AVERROR(EINVAL); \ + } \ + if (flags & INIT_VLC_INPUT_LE) \ + buf[j].code = bitswap_32(buf[j].code); \ + else \ + buf[j].code <<= 32 - buf[j].bits; \ + if (symbols) \ + GET_DATA(buf[j].symbol, symbols, i, symbols_wrap, symbols_size) \ + else \ + buf[j].symbol = i; \ + j++; \ + } + COPY(len > nb_bits); + // qsort is the slowest part of init_vlc, and could probably be improved or avoided + AV_QSORT(buf, j, struct VLCcode, compare_vlcspec); + COPY(len && len <= nb_bits); + nb_codes = j; + + return vlc_common_end(vlc, nb_bits, nb_codes, buf, + flags, localbuf); +} + +void ff_free_vlc(VLC *vlc) +{ + av_freep(&vlc->table); +} diff --git a/libs/ffmpegindeo/vlc.h b/libs/ffmpegindeo/vlc.h new file mode 100644 index 00000000000..1b6d0a17099 --- /dev/null +++ b/libs/ffmpegindeo/vlc.h @@ -0,0 +1,69 @@ +/* + * This file is part of FFmpeg. + * + * FFmpeg is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * FFmpeg is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with FFmpeg; if not, write to the Free Software + * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA + */ + +#ifndef AVCODEC_VLC_H +#define AVCODEC_VLC_H + +#include <stdint.h> + +// When changing this, be sure to also update tableprint_vlc.h accordingly. +typedef int16_t VLCBaseType; + +typedef struct VLCElem { + VLCBaseType sym, len; +} VLCElem; + +typedef struct VLC { + int bits; + VLCElem *table; + int table_size, table_allocated; +} VLC; + +typedef struct RL_VLC_ELEM { + int16_t level; + int8_t len; + uint8_t run; +} RL_VLC_ELEM; + +#define init_vlc(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + flags) \ + ff_init_vlc_sparse(vlc, nb_bits, nb_codes, \ + bits, bits_wrap, bits_size, \ + codes, codes_wrap, codes_size, \ + NULL, 0, 0, flags) + +int ff_init_vlc_sparse(VLC *vlc, int nb_bits, int nb_codes, + const void *bits, int bits_wrap, int bits_size, + const void *codes, int codes_wrap, int codes_size, + const void *symbols, int symbols_wrap, int symbols_size, + int flags); + +void ff_free_vlc(VLC *vlc); + +/* If INIT_VLC_INPUT_LE is set, the LSB bit of the codes used to + * initialize the VLC table is the first bit to be read. */ +#define INIT_VLC_INPUT_LE 2 +/* If set the VLC is intended for a little endian bitstream reader. */ +#define INIT_VLC_OUTPUT_LE 8 +#define INIT_VLC_LE (INIT_VLC_INPUT_LE | INIT_VLC_OUTPUT_LE) +#define INIT_VLC_USE_NEW_STATIC 4 +#define INIT_VLC_STATIC_OVERLONG (1 | INIT_VLC_USE_NEW_STATIC) + +#endif /* AVCODEC_VLC_H */