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