This video codec is used by games such as Richman 4, and Zwei: The Arges Adventure.
The decoder logic is based on code from the FFmpeg project.
-- v2: loader/wine.inf: Enable ir50_32 video codec. ir50_32: Implement decompression to 15-bit RGB.
From: Shaun Ren sren@codeweavers.com
--- configure | 2 + configure.ac | 1 + dlls/ir50_32/Makefile.in | 8 ++ dlls/ir50_32/ir50.c | 176 ++++++++++++++++++++++++++++++++++++ dlls/ir50_32/ir50_32.rc | 29 ++++++ dlls/ir50_32/ir50_32.spec | 1 + dlls/ir50_32/ir50_compat.h | 27 ++++++ dlls/ir50_32/ir50_private.h | 27 ++++++ 8 files changed, 271 insertions(+) create mode 100644 dlls/ir50_32/Makefile.in create mode 100644 dlls/ir50_32/ir50.c create mode 100644 dlls/ir50_32/ir50_32.rc create mode 100644 dlls/ir50_32/ir50_32.spec create mode 100644 dlls/ir50_32/ir50_compat.h create mode 100644 dlls/ir50_32/ir50_private.h
diff --git a/configure b/configure index 76ac7311e6d..b5d69827ce3 100755 --- a/configure +++ b/configure @@ -1165,6 +1165,7 @@ enable_inkobj enable_inseng enable_iphlpapi enable_iprop +enable_ir50_32 enable_irprops_cpl enable_itircl enable_itss @@ -21645,6 +21646,7 @@ wine_fn_config_makefile dlls/inseng enable_inseng wine_fn_config_makefile dlls/iphlpapi enable_iphlpapi wine_fn_config_makefile dlls/iphlpapi/tests enable_tests wine_fn_config_makefile dlls/iprop enable_iprop +wine_fn_config_makefile dlls/ir50_32 enable_ir50_32 wine_fn_config_makefile dlls/irprops.cpl enable_irprops_cpl wine_fn_config_makefile dlls/itircl enable_itircl wine_fn_config_makefile dlls/itss enable_itss diff --git a/configure.ac b/configure.ac index 423f883b6a8..b240c273dec 100644 --- a/configure.ac +++ b/configure.ac @@ -2738,6 +2738,7 @@ WINE_CONFIG_MAKEFILE(dlls/inseng) WINE_CONFIG_MAKEFILE(dlls/iphlpapi) WINE_CONFIG_MAKEFILE(dlls/iphlpapi/tests) WINE_CONFIG_MAKEFILE(dlls/iprop) +WINE_CONFIG_MAKEFILE(dlls/ir50_32) WINE_CONFIG_MAKEFILE(dlls/irprops.cpl) WINE_CONFIG_MAKEFILE(dlls/itircl) WINE_CONFIG_MAKEFILE(dlls/itss) diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in new file mode 100644 index 00000000000..2b04f338317 --- /dev/null +++ b/dlls/ir50_32/Makefile.in @@ -0,0 +1,8 @@ +EXTRADEFS = -DWINE_NO_LONG_TYPES +MODULE = ir50_32.dll +IMPORTS = user32 + +C_SRCS = \ + ir50.c + +RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c new file mode 100644 index 00000000000..63ca0ecf633 --- /dev/null +++ b/dlls/ir50_32/ir50.c @@ -0,0 +1,176 @@ +/* + * Intel Indeo 5 Video Decoder + * 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 + * + */ + +#include <stdarg.h> +#include <stdlib.h> +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "vfw.h" +#include "mmsystem.h" +#include "ir50_private.h" +#include "ir50_compat.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(ir50_32); + +static HINSTANCE IR50_32_hModule; + +static LRESULT +IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT +IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_DecompressBegin( AVCodecContext *avctx, LPBITMAPINFO in, LPBITMAPINFO out ) +{ + FIXME("ICM_DECOMPRESS_BEGIN %p %p %p\n", avctx, in, out); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_Decompress( AVCodecContext *avctx, ICDECOMPRESS *icd, DWORD size ) +{ + FIXME("ICM_DECOMPRESS %p %p %u\n", avctx, icd, size); + return ICERR_UNSUPPORTED; +} + +static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) +{ + FIXME("ICM_GETINFO %p %u\n", icinfo, dwSize); + return ICERR_UNSUPPORTED; +} + +/*********************************************************************** + * DriverProc (IR50_32.@) + */ +LRESULT WINAPI IV50_DriverProc( DWORD_PTR dwDriverId, HDRVR hdrvr, UINT msg, + LPARAM lParam1, LPARAM lParam2 ) +{ + AVCodecContext *avctx = (AVCodecContext *) dwDriverId; + LRESULT r = ICERR_UNSUPPORTED; + + TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2); + + switch( msg ) + { + case DRV_LOAD: + TRACE("Loaded\n"); + r = 1; + break; + + case DRV_ENABLE: + break; + + case DRV_OPEN: + FIXME("DRV_OPEN\n"); + break; + + case DRV_CLOSE: + FIXME("DRV_CLOSE\n"); + break; + + case DRV_DISABLE: + break; + + case DRV_FREE: + break; + + case ICM_GETINFO: + r = IV50_GetInfo( (ICINFO *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_QUERY: + r = IV50_DecompressQuery( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_FORMAT: + r = IV50_DecompressGetFormat( (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_GET_PALETTE: + FIXME("ICM_DECOMPRESS_GET_PALETTE\n"); + break; + + case ICM_DECOMPRESS: + r = IV50_Decompress( avctx, (ICDECOMPRESS *) lParam1, (DWORD) lParam2 ); + break; + + case ICM_DECOMPRESS_BEGIN: + r = IV50_DecompressBegin( avctx, (LPBITMAPINFO) lParam1, (LPBITMAPINFO) lParam2 ); + break; + + case ICM_DECOMPRESS_END: + r = ICERR_OK; + break; + + case ICM_DECOMPRESSEX_QUERY: + FIXME("ICM_DECOMPRESSEX_QUERY\n"); + break; + + case ICM_DECOMPRESSEX: + FIXME("ICM_DECOMPRESSEX\n"); + break; + + case ICM_COMPRESS_QUERY: + r = ICERR_BADFORMAT; + /* fall through */ + case ICM_COMPRESS_GET_FORMAT: + case ICM_COMPRESS_END: + case ICM_COMPRESS: + FIXME("compression not implemented\n"); + break; + + case ICM_CONFIGURE: + break; + + default: + FIXME("Unknown message: %04x %Id %Id\n", msg, lParam1, lParam2); + } + + return r; +} + +/*********************************************************************** + * DllMain + */ +BOOL WINAPI DllMain(HINSTANCE hModule, DWORD dwReason, LPVOID lpReserved) +{ + TRACE("(%p,%u,%p)\n", hModule, dwReason, lpReserved); + + switch (dwReason) + { + case DLL_PROCESS_ATTACH: + DisableThreadLibraryCalls(hModule); + IR50_32_hModule = hModule; + break; + } + return TRUE; +} diff --git a/dlls/ir50_32/ir50_32.rc b/dlls/ir50_32/ir50_32.rc new file mode 100644 index 00000000000..ceb5a60c5c3 --- /dev/null +++ b/dlls/ir50_32/ir50_32.rc @@ -0,0 +1,29 @@ +/* + * 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 + */ + +#include "ir50_private.h" + +#pragma makedep po + +LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT + +STRINGTABLE +{ + IDS_NAME "#msgctxt#do not translate#IV50" + IDS_DESCRIPTION "Indeo Video Interactive version 5 video codec" +} diff --git a/dlls/ir50_32/ir50_32.spec b/dlls/ir50_32/ir50_32.spec new file mode 100644 index 00000000000..e5c54ef9c56 --- /dev/null +++ b/dlls/ir50_32/ir50_32.spec @@ -0,0 +1 @@ +@ stdcall -private DriverProc(long long long long long) IV50_DriverProc diff --git a/dlls/ir50_32/ir50_compat.h b/dlls/ir50_32/ir50_compat.h new file mode 100644 index 00000000000..dcaf8d990a5 --- /dev/null +++ b/dlls/ir50_32/ir50_compat.h @@ -0,0 +1,27 @@ +/* + * 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/dlls/ir50_32/ir50_private.h b/dlls/ir50_32/ir50_private.h new file mode 100644 index 00000000000..09b2142e8f5 --- /dev/null +++ b/dlls/ir50_32/ir50_private.h @@ -0,0 +1,27 @@ +/* + * 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_PRIVATE_H +#define __IR50_PRIVATE_H + +#include <windef.h> + +#define IDS_NAME 100 +#define IDS_DESCRIPTION 101 + +#endif /* __IR50_PRIVATE_H */
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 22 ++++++++++++++++++++-- 1 file changed, 20 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 63ca0ecf633..7a2676c43fb 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -36,6 +36,9 @@ WINE_DEFAULT_DEBUG_CHANNEL(ir50_32);
static HINSTANCE IR50_32_hModule;
+#define IV50_MAGIC mmioFOURCC('I', 'V', '5', '0') + + static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { @@ -64,8 +67,23 @@ static LRESULT IV50_Decompress( AVCodecContext *avctx, ICDECOMPRESS *icd, DWORD
static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) { - FIXME("ICM_GETINFO %p %u\n", icinfo, dwSize); - return ICERR_UNSUPPORTED; + TRACE("ICM_GETINFO %p %u\n", icinfo, dwSize); + + if (!icinfo) return sizeof(ICINFO); + if (dwSize < sizeof(ICINFO)) return 0; + + icinfo->dwSize = sizeof(ICINFO); + icinfo->fccType = ICTYPE_VIDEO; + icinfo->fccHandler = IV50_MAGIC; + icinfo->dwFlags = 0; + icinfo->dwVersion = ICVERSION; + icinfo->dwVersionICM = ICVERSION; + + LoadStringW(IR50_32_hModule, IDS_NAME, icinfo->szName, ARRAY_SIZE(icinfo->szName)); + LoadStringW(IR50_32_hModule, IDS_DESCRIPTION, icinfo->szDescription, ARRAY_SIZE(icinfo->szDescription)); + /* msvfw32 will fill icinfo->szDriver for us */ + + return sizeof(ICINFO); }
/***********************************************************************
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 54 +++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 52 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 7a2676c43fb..3dae56561b2 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -42,8 +42,58 @@ static HINSTANCE IR50_32_hModule; static LRESULT IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_QUERY %p %p\n", in, out); - return ICERR_UNSUPPORTED; + TRACE("ICM_DECOMPRESS_QUERY %p %p\n", in, out); + + TRACE("in->planes = %d\n", in->bmiHeader.biPlanes); + TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount); + TRACE("in->height = %d\n", in->bmiHeader.biHeight); + TRACE("in->width = %d\n", in->bmiHeader.biWidth); + TRACE("in->compr = %#x\n", in->bmiHeader.biCompression); + + if ( in->bmiHeader.biCompression != IV50_MAGIC ) + { + TRACE("can't do %#x compression\n", in->bmiHeader.biCompression); + return ICERR_BADFORMAT; + } + + if ( in->bmiHeader.biBitCount != 24 ) + { + TRACE("can't do %d bpp\n", in->bmiHeader.biBitCount); + return ICERR_BADFORMAT; + } + + /* output must be same dimensions as input */ + if ( out ) + { + 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.biCompression != BI_RGB ) + { + TRACE("incompatible compression requested\n"); + return ICERR_BADFORMAT; + } + + if ( out->bmiHeader.biBitCount != 24 ) + { + TRACE("incompatible depth requested\n"); + return ICERR_BADFORMAT; + } + + if ( in->bmiHeader.biPlanes != out->bmiHeader.biPlanes || + abs( in->bmiHeader.biHeight ) != out->bmiHeader.biHeight || + in->bmiHeader.biWidth != out->bmiHeader.biWidth ) + { + TRACE("incompatible output dimensions requested\n"); + return ICERR_BADFORMAT; + } + } + + TRACE("OK!\n"); + return ICERR_OK; }
static LRESULT
From: Shaun Ren sren@codeweavers.com
--- dlls/ir50_32/ir50.c | 24 ++++++++++++++++++++++-- 1 file changed, 22 insertions(+), 2 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 3dae56561b2..7c8e9e05dda 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -99,8 +99,28 @@ IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) static LRESULT IV50_DecompressGetFormat( LPBITMAPINFO in, LPBITMAPINFO out ) { - FIXME("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); - return ICERR_UNSUPPORTED; + DWORD size; + + TRACE("ICM_DECOMPRESS_GETFORMAT %p %p\n", in, out); + + if ( !in ) + return ICERR_BADPARAM; + + if ( in->bmiHeader.biCompression != IV50_MAGIC || in->bmiHeader.biBitCount != 24 ) + return ICERR_BADFORMAT; + + size = in->bmiHeader.biSize; + if ( out ) + { + memcpy( out, in, size ); + out->bmiHeader.biHeight = abs( in->bmiHeader.biHeight ); + out->bmiHeader.biCompression = BI_RGB; + out->bmiHeader.biBitCount = 24; + out->bmiHeader.biSizeImage = out->bmiHeader.biWidth * out->bmiHeader.biHeight * 3; + return ICERR_OK; + } + + return size; }
static LRESULT IV50_DecompressBegin( AVCodecContext *avctx, LPBITMAPINFO in, LPBITMAPINFO out )
From: Shaun Ren sren@codeweavers.com
The decoder logic is based on the indeo5 codec in FFmpeg. --- dlls/ir50_32/Makefile.in | 4 + dlls/ir50_32/get_bits.h | 443 ++++++++++ dlls/ir50_32/indeo5.c | 825 +++++++++++++++++++ dlls/ir50_32/indeo5.h | 9 + dlls/ir50_32/ir50.c | 144 +++- dlls/ir50_32/ir50_compat.h | 65 ++ dlls/ir50_32/ivi.c | 1572 ++++++++++++++++++++++++++++++++++++ dlls/ir50_32/ivi.h | 321 ++++++++ dlls/ir50_32/ivi_dsp.c | 551 +++++++++++++ dlls/ir50_32/ivi_dsp.h | 244 ++++++ dlls/ir50_32/vlc.c | 353 ++++++++ dlls/ir50_32/vlc.h | 69 ++ 12 files changed, 4594 insertions(+), 6 deletions(-) create mode 100644 dlls/ir50_32/get_bits.h create mode 100644 dlls/ir50_32/indeo5.c create mode 100644 dlls/ir50_32/indeo5.h create mode 100644 dlls/ir50_32/ivi.c create mode 100644 dlls/ir50_32/ivi.h create mode 100644 dlls/ir50_32/ivi_dsp.c create mode 100644 dlls/ir50_32/ivi_dsp.h create mode 100644 dlls/ir50_32/vlc.c create mode 100644 dlls/ir50_32/vlc.h
diff --git a/dlls/ir50_32/Makefile.in b/dlls/ir50_32/Makefile.in index 2b04f338317..86616d3266b 100644 --- a/dlls/ir50_32/Makefile.in +++ b/dlls/ir50_32/Makefile.in @@ -3,6 +3,10 @@ MODULE = ir50_32.dll IMPORTS = user32
C_SRCS = \ + ivi.c \ + ivi_dsp.c \ + vlc.c \ + indeo5.c \ ir50.c
RC_SRCS = ir50_32.rc diff --git a/dlls/ir50_32/get_bits.h b/dlls/ir50_32/get_bits.h new file mode 100644 index 00000000000..9437e389090 --- /dev/null +++ b/dlls/ir50_32/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 "ir50_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/dlls/ir50_32/indeo5.c b/dlls/ir50_32/indeo5.c new file mode 100644 index 00000000000..4bd081d5462 --- /dev/null +++ b/dlls/ir50_32/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 "ir50_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/dlls/ir50_32/indeo5.h b/dlls/ir50_32/indeo5.h new file mode 100644 index 00000000000..ab546943488 --- /dev/null +++ b/dlls/ir50_32/indeo5.h @@ -0,0 +1,9 @@ +#ifndef __INDEO5_H +#define __INDEO5_H + +#include "ir50_compat.h" +#include "ivi.h" + +int indeo5_decode_init(AVCodecContext *avctx); + +#endif /* __INDEO5_H */ diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index 7c8e9e05dda..b68bd6feeb0 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -29,6 +29,7 @@ #include "mmsystem.h" #include "ir50_private.h" #include "ir50_compat.h" +#include "indeo5.h"
#include "wine/debug.h"
@@ -37,6 +38,74 @@ 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 ); + memset( avctx, 0, sizeof(*avctx) ); +} + +static LRESULT decode_init( AVCodecContext *avctx ) +{ + return indeo5_decode_init( avctx ); +} + + +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; + } +}
static LRESULT @@ -125,14 +194,61 @@ 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 ( in->bmiHeader.biBitCount != 24 || out->bmiHeader.biBitCount != 24 ) + return ICERR_BADFORMAT; + + decode_close( avctx ); + + avctx->width = in->bmiHeader.biWidth; + avctx->height = in->bmiHeader.biHeight; + + 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; + } + + yuv410p_to_bgr24( &frame, icd->lpOutput ); + + return ICERR_OK; }
static LRESULT IV50_GetInfo( ICINFO *icinfo, DWORD dwSize ) @@ -178,11 +294,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_DISABLE: @@ -216,6 +346,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 index dcaf8d990a5..3d4a0930554 100644 --- a/dlls/ir50_32/ir50_compat.h +++ b/dlls/ir50_32/ir50_compat.h @@ -19,6 +19,71 @@ #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; diff --git a/dlls/ir50_32/ivi.c b/dlls/ir50_32/ivi.c new file mode 100644 index 00000000000..060800b3ebe --- /dev/null +++ b/dlls/ir50_32/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 "ir50_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/dlls/ir50_32/ivi.h b/dlls/ir50_32/ivi.h new file mode 100644 index 00000000000..533824a9941 --- /dev/null +++ b/dlls/ir50_32/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 "ir50_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/dlls/ir50_32/ivi_dsp.c b/dlls/ir50_32/ivi_dsp.c new file mode 100644 index 00000000000..c2a383ae204 --- /dev/null +++ b/dlls/ir50_32/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/dlls/ir50_32/ivi_dsp.h b/dlls/ir50_32/ivi_dsp.h new file mode 100644 index 00000000000..3a14148624f --- /dev/null +++ b/dlls/ir50_32/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/dlls/ir50_32/vlc.c b/dlls/ir50_32/vlc.c new file mode 100644 index 00000000000..bd565e61c1c --- /dev/null +++ b/dlls/ir50_32/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 "ir50_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/dlls/ir50_32/vlc.h b/dlls/ir50_32/vlc.h new file mode 100644 index 00000000000..1b6d0a17099 --- /dev/null +++ b/dlls/ir50_32/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 */
From: Shaun Ren sren@codeweavers.com
Required by games such as "Zwei: The Arges Adventure". --- dlls/ir50_32/ir50.c | 101 +++++++++++++++++++++++++++++++++++-- dlls/ir50_32/ir50_compat.h | 4 ++ 2 files changed, 101 insertions(+), 4 deletions(-)
diff --git a/dlls/ir50_32/ir50.c b/dlls/ir50_32/ir50.c index b68bd6feeb0..e82dd73bf46 100644 --- a/dlls/ir50_32/ir50.c +++ b/dlls/ir50_32/ir50.c @@ -44,12 +44,29 @@ static HINSTANCE IR50_32_hModule; 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 ) { - return indeo5_decode_init( 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; }
@@ -107,6 +124,72 @@ static void yuv410p_to_bgr24( AVFrame *frame, uint8_t *out ) } }
+/* 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 IV50_DecompressQuery( LPBITMAPINFO in, LPBITMAPINFO out ) @@ -146,7 +229,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; @@ -205,13 +288,15 @@ static LRESULT IV50_DecompressBegin( AVCodecContext *avctx, LPBITMAPINFO in, LPB TRACE("out->width = %d\n", out->bmiHeader.biWidth); TRACE("out->compr = %#x\n", out->bmiHeader.biCompression);
- if ( in->bmiHeader.biBitCount != 24 || out->bmiHeader.biBitCount != 24 ) + if ( in->bmiHeader.biBitCount != 24 || + (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 ); } @@ -246,7 +331,15 @@ static LRESULT IV50_Decompress( AVCodecContext *avctx, ICDECOMPRESS *icd, DWORD return ICERR_BADFORMAT; }
- yuv410p_to_bgr24( &frame, icd->lpOutput ); + 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; } diff --git a/dlls/ir50_32/ir50_compat.h b/dlls/ir50_32/ir50_compat.h index 3d4a0930554..64fdbe5c960 100644 --- a/dlls/ir50_32/ir50_compat.h +++ b/dlls/ir50_32/ir50_compat.h @@ -87,6 +87,10 @@ typedef struct 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 */
From: Shaun Ren sren@codeweavers.com
--- loader/wine.inf.in | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/loader/wine.inf.in b/loader/wine.inf.in index e7b435ed0f0..5a3a7455a34 100644 --- a/loader/wine.inf.in +++ b/loader/wine.inf.in @@ -2232,7 +2232,7 @@ system.ini, drivers32,,"msacm.msgsm610=msgsm32.acm" system.ini, drivers32,,"vidc.mrle=msrle32.dll" system.ini, drivers32,,"vidc.msvc=msvidc32.dll" system.ini, drivers32,,"vidc.cvid=iccvid.dll" -system.ini, drivers32,,"; vidc.IV50=ir50_32.dll" +system.ini, drivers32,,"vidc.IV50=ir50_32.dll" system.ini, drivers32,,"; vidc.IV31=ir32_32.dll" system.ini, drivers32,,"; vidc.IV32=ir32_32.dll"
Are we confident this isn't patent encumbered?
Then imho it would be simpler to do that through winegstreamer, (as for the mp3 decoders fwiw).
It could be for instance through a custom MFT class if there's normally no MFT/DMO for that codec.
On Tue Nov 8 23:00:21 2022 +0000, Rémi Bernon wrote:
Are we confident this isn't patent encumbered? Then imho it would be simpler to do that through winegstreamer, (as for the mp3 decoders fwiw). It could be for instance through a custom MFT class if there's normally no MFT/DMO for that codec.
Yes, the codec's patent is from 1994, it should have expired by now.
I suppose one advantage with this approach is that the dll can be used as a drop-in replacement for the ir50_32.dll on Windows. Microsoft has disabled it due to [security concerns](https://support.microsoft.com/en-us/topic/microsoft-security-advisory-vulner...).
Regardless of legal issues, or importing the code or not, is there a way to test this? With some publicly available media and some kind of test media player program.
Zebediah Figura (@zfigura) commented about dlls/ir50_32/ir50_32.rc:
- 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
- */
+#include "ir50_private.h"
+#pragma makedep po
+LANGUAGE LANG_ENGLISH, SUBLANG_DEFAULT
+STRINGTABLE +{
- IDS_NAME "#msgctxt#do not translate#IV50"
As far as I can tell this isn't part of public API or anything, so if it's not translated we probably shouldn't have it in the string table either. (We should probably fix msvidc32 and msrle32, and probably iccvid as well.)
Zebediah Figura (@zfigura) commented about dlls/ir50_32/ir50.c:
LPARAM lParam1, LPARAM lParam2 )
+{
- AVCodecContext *avctx = (AVCodecContext *) dwDriverId;
- LRESULT r = ICERR_UNSUPPORTED;
- TRACE("%Id %p %04x %08Ix %08Ix\n", dwDriverId, hdrvr, msg, lParam1, lParam2);
- switch( msg )
- {
- case DRV_LOAD:
TRACE("Loaded\n");
r = 1;
break;
- case DRV_ENABLE:
break;
I assume this was copy-pasted from another driver, but since we're introducing new code, we could probably simplify this by combining some cases.
Zebediah Figura (@zfigura) commented about dlls/ir50_32/ir50.c:
- TRACE("in->bpp = %d\n", in->bmiHeader.biBitCount);
- TRACE("in->height = %d\n", in->bmiHeader.biHeight);
- TRACE("in->width = %d\n", in->bmiHeader.biWidth);
- TRACE("in->compr = %#x\n", in->bmiHeader.biCompression);
- if ( in->bmiHeader.biCompression != IV50_MAGIC )
- {
TRACE("can't do %#x compression\n", in->bmiHeader.biCompression);
return ICERR_BADFORMAT;
- }
- if ( in->bmiHeader.biBitCount != 24 )
- {
TRACE("can't do %d bpp\n", in->bmiHeader.biBitCount);
return ICERR_BADFORMAT;
- }
Is the compressed bit depth meaningful for IV50? (Same for the patch implementing decompression later). Or if we need to care about validating this anyway, it'd be nice to at least have a test for that in the tree.
On Tue Nov 15 21:09:09 2022 +0000, Nikolay Sivov wrote:
Regardless of legal issues, or importing the code or not, is there a way to test this? With some publicly available media and some kind of test media player program.
There are some public available videos, e.g. `https://samples.mplayerhq.hu/V-codecs/IV50/haegemonia.avi%60. A simple test program can be used to play the media:
```c #include <stdio.h> #include <windows.h> #include <mmsystem.h> #include <mmreg.h>
int main() { MCIERROR error; if (error = mciSendStringA("open test.avi alias vid", NULL, 0, NULL)) return error; if (error = mciSendStringA("play vid wait", NULL, 0, NULL)) return error; return 0; } ```