diff options
Diffstat (limited to 'jpegxr')
45 files changed, 33867 insertions, 0 deletions
diff --git a/jpegxr/APP.rc b/jpegxr/APP.rc new file mode 100644 index 000000000..96f5b915b --- /dev/null +++ b/jpegxr/APP.rc @@ -0,0 +1,103 @@ +// Microsoft Visual C++ generated resource script. +// +#include "app_resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "app_resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,2008,324 + PRODUCTVERSION 0,1,2008,324 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x1L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "JPEG-XR Sample Application" + VALUE "CompanyName", "Microsoft Corporation" + VALUE "FileDescription", "JPEG-XR Sample Application" + VALUE "FileVersion", "0, 1, 2008, 0324" + VALUE "InternalName", "JPEGXR-EXE" + VALUE "LegalCopyright", "Copyright (C) 2008 Microsoft Corporation. All rights reserved." + VALUE "OriginalFilename", "jpegxr.exe" + VALUE "ProductName", "JPEG-XR Sample Application" + VALUE "ProductVersion", "0, 1, 2008, 0324" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/jpegxr/APP.vcproj b/jpegxr/APP.vcproj new file mode 100644 index 000000000..8009e8f62 --- /dev/null +++ b/jpegxr/APP.vcproj @@ -0,0 +1,246 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="APP" + ProjectGUID="{FA1F4A8C-4C1F-4560-9750-351432EE6D8A}" + RootNamespace="APP" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + Description="generate qp C code if necessary" + CommandLine="" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + AdditionalIncludeDirectories="my_getopt-1.5" + PreprocessorDefinitions="DETAILED_DEBUG;_CRT_SECURE_NO_WARNINGS;WIN32;_WIN32;_DEBUG;_CONSOLE" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + WarnAsError="false" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + CompileAs="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="jpegxr.lib" + OutputFile="$(OutDir)\jpegxr.exe" + LinkIncremental="2" + AdditionalLibraryDirectories="$(OutDir)" + GenerateDebugInformation="true" + SubSystem="1" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="1" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + Description="generate qp C code if necessary" + CommandLine="" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + AdditionalIncludeDirectories="my_getopt-1.5" + PreprocessorDefinitions="_CRT_SECURE_NO_WARNINGS;WIN32;_WIN32;NDEBUG;_CONSOLE" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CompileAs="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + AdditionalDependencies="jpegxr.lib" + OutputFile="$(OutDir)\jpegxr.exe" + LinkIncremental="1" + AdditionalLibraryDirectories="$(OutDir)" + GenerateDebugInformation="true" + SubSystem="1" + OptimizeReferences="2" + EnableCOMDATFolding="2" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\file.c" + > + </File> + <File + RelativePath=".\jpegxr.c" + > + </File> + <File + RelativePath=".\my_getopt-1.5\my_getopt.c" + > + </File> + <File + RelativePath=".\qp.tab.c" + > + </File> + <File + RelativePath=".\qp_lexor.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\file.h" + > + </File> + <File + RelativePath=".\my_getopt-1.5\getopt.h" + > + </File> + <File + RelativePath=".\my_getopt-1.5\my_getopt.h" + > + </File> + <File + RelativePath=".\qp.tab.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + <File + RelativePath=".\APP.rc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/jpegxr/COPYRIGHT.txt b/jpegxr/COPYRIGHT.txt new file mode 100644 index 000000000..df46e6594 --- /dev/null +++ b/jpegxr/COPYRIGHT.txt @@ -0,0 +1,40 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ diff --git a/jpegxr/DLL.rc b/jpegxr/DLL.rc new file mode 100644 index 000000000..1aeb5bfb0 --- /dev/null +++ b/jpegxr/DLL.rc @@ -0,0 +1,103 @@ +// Microsoft Visual C++ generated resource script. +// +#include "dll_resource.h" + +#define APSTUDIO_READONLY_SYMBOLS +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 2 resource. +// +#include "afxres.h" + +///////////////////////////////////////////////////////////////////////////// +#undef APSTUDIO_READONLY_SYMBOLS + +///////////////////////////////////////////////////////////////////////////// +// English (U.S.) resources + +#if !defined(AFX_RESOURCE_DLL) || defined(AFX_TARG_ENU) +#ifdef _WIN32 +LANGUAGE LANG_ENGLISH, SUBLANG_ENGLISH_US +#pragma code_page(1252) +#endif //_WIN32 + +#ifdef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// TEXTINCLUDE +// + +1 TEXTINCLUDE +BEGIN + "dll_resource.h\0" +END + +2 TEXTINCLUDE +BEGIN + "#include ""afxres.h""\r\n" + "\0" +END + +3 TEXTINCLUDE +BEGIN + "\r\n" + "\0" +END + +#endif // APSTUDIO_INVOKED + + +///////////////////////////////////////////////////////////////////////////// +// +// Version +// + +VS_VERSION_INFO VERSIONINFO + FILEVERSION 0,1,2008,324 + PRODUCTVERSION 0,1,2008,324 + FILEFLAGSMASK 0x17L +#ifdef _DEBUG + FILEFLAGS 0x1L +#else + FILEFLAGS 0x0L +#endif + FILEOS 0x4L + FILETYPE 0x2L + FILESUBTYPE 0x0L +BEGIN + BLOCK "StringFileInfo" + BEGIN + BLOCK "040904b0" + BEGIN + VALUE "Comments", "JPEG-XR Dynamic Link Library" + VALUE "CompanyName", "Microsoft Corporation" + VALUE "FileDescription", "JPEG-XR Dynamic Link Library" + VALUE "FileVersion", "0, 1, 2008, 0324" + VALUE "InternalName", "JPEGXR-DLL" + VALUE "LegalCopyright", "Copyright (C) 2008 Microsoft Corporation. All rights reserved." + VALUE "OriginalFilename", "jpegxr.dll" + VALUE "ProductName", "JPEG-XR Dynamic Link Library" + VALUE "ProductVersion", "0, 1, 2008, 0324" + END + END + BLOCK "VarFileInfo" + BEGIN + VALUE "Translation", 0x409, 1200 + END +END + +#endif // English (U.S.) resources +///////////////////////////////////////////////////////////////////////////// + + + +#ifndef APSTUDIO_INVOKED +///////////////////////////////////////////////////////////////////////////// +// +// Generated from the TEXTINCLUDE 3 resource. +// + + +///////////////////////////////////////////////////////////////////////////// +#endif // not APSTUDIO_INVOKED + diff --git a/jpegxr/DLL.vcproj b/jpegxr/DLL.vcproj new file mode 100644 index 000000000..08373556b --- /dev/null +++ b/jpegxr/DLL.vcproj @@ -0,0 +1,289 @@ +<?xml version="1.0" encoding="Windows-1252"?> +<VisualStudioProject + ProjectType="Visual C++" + Version="9.00" + Name="DLL" + ProjectGUID="{969C2750-EF0E-428F-9A85-20256796BC5C}" + RootNamespace="DLL" + Keyword="Win32Proj" + TargetFrameworkVersion="196613" + > + <Platforms> + <Platform + Name="Win32" + /> + </Platforms> + <ToolFiles> + </ToolFiles> + <Configurations> + <Configuration + Name="Debug|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="0" + PreprocessorDefinitions="DETAILED_DEBUG;JXR_DLL_EXPORTS;WIN32;_DEBUG;_WINDOWS;_USRDLL;DLL_EXPORTS" + MinimalRebuild="true" + BasicRuntimeChecks="3" + RuntimeLibrary="3" + UsePrecompiledHeader="0" + WarningLevel="3" + WarnAsError="false" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="4" + CompileAs="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + ShowProgress="0" + OutputFile="$(OutDir)\jpegxr_dll.dll" + LinkIncremental="2" + GenerateDebugInformation="true" + GenerateMapFile="true" + MapExports="true" + SubSystem="2" + ImportLibrary="$(TargetDir)jpegxr.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + <Configuration + Name="Release|Win32" + OutputDirectory="$(SolutionDir)$(ConfigurationName)" + IntermediateDirectory="$(ConfigurationName)" + ConfigurationType="2" + CharacterSet="1" + WholeProgramOptimization="1" + > + <Tool + Name="VCPreBuildEventTool" + /> + <Tool + Name="VCCustomBuildTool" + /> + <Tool + Name="VCXMLDataGeneratorTool" + /> + <Tool + Name="VCWebServiceProxyGeneratorTool" + /> + <Tool + Name="VCMIDLTool" + /> + <Tool + Name="VCCLCompilerTool" + Optimization="2" + EnableIntrinsicFunctions="true" + PreprocessorDefinitions="JXR_DLL_EXPORTS;WIN32;NDEBUG;_WINDOWS;_USRDLL;DLL_EXPORTS" + RuntimeLibrary="2" + EnableFunctionLevelLinking="true" + UsePrecompiledHeader="0" + WarningLevel="3" + Detect64BitPortabilityProblems="true" + DebugInformationFormat="3" + CompileAs="2" + /> + <Tool + Name="VCManagedResourceCompilerTool" + /> + <Tool + Name="VCResourceCompilerTool" + /> + <Tool + Name="VCPreLinkEventTool" + /> + <Tool + Name="VCLinkerTool" + OutputFile="$(OutDir)\jpegxr.dll" + LinkIncremental="1" + GenerateDebugInformation="true" + SubSystem="2" + OptimizeReferences="2" + EnableCOMDATFolding="2" + ImportLibrary="$(TargetDir)jpegxr.lib" + TargetMachine="1" + /> + <Tool + Name="VCALinkTool" + /> + <Tool + Name="VCManifestTool" + /> + <Tool + Name="VCXDCMakeTool" + /> + <Tool + Name="VCBscMakeTool" + /> + <Tool + Name="VCFxCopTool" + /> + <Tool + Name="VCAppVerifierTool" + /> + <Tool + Name="VCPostBuildEventTool" + /> + </Configuration> + </Configurations> + <References> + </References> + <Files> + <Filter + Name="Source Files" + Filter="cpp;c;cc;cxx;def;odl;idl;hpj;bat;asm;asmx" + UniqueIdentifier="{4FC737F1-C7A5-4376-A066-2A32D752A2FF}" + > + <File + RelativePath=".\algo.c" + > + </File> + <File + RelativePath=".\api.c" + > + </File> + <File + RelativePath=".\cr_parse.c" + > + </File> + <File + RelativePath=".\cw_emit.c" + > + </File> + <File + RelativePath=".\dllmain.c" + > + </File> + <File + RelativePath=".\flags.c" + > + </File> + <File + RelativePath=".\init.c" + > + </File> + <File + RelativePath=".\io.c" + > + </File> + <File + RelativePath=".\jpegxr_pixelformat.c" + > + </File> + <File + RelativePath=".\r_parse.c" + > + </File> + <File + RelativePath=".\r_strip.c" + > + </File> + <File + RelativePath=".\r_tile_frequency.c" + > + </File> + <File + RelativePath=".\r_tile_spatial.c" + > + </File> + <File + RelativePath=".\w_emit.c" + > + </File> + <File + RelativePath=".\w_strip.c" + > + </File> + <File + RelativePath=".\w_tile_frequency.c" + > + </File> + <File + RelativePath=".\w_tile_spatial.c" + > + </File> + <File + RelativePath=".\x_strip.c" + > + </File> + </Filter> + <Filter + Name="Header Files" + Filter="h;hpp;hxx;hm;inl;inc;xsd" + UniqueIdentifier="{93995380-89BD-4b04-88EB-625FBE52EBFB}" + > + <File + RelativePath=".\jpegxr.h" + > + </File> + <File + RelativePath=".\jxr_priv.h" + > + </File> + <File + RelativePath=".\stdint_minimal.h" + > + </File> + </Filter> + <Filter + Name="Resource Files" + Filter="rc;ico;cur;bmp;dlg;rc2;rct;bin;rgs;gif;jpg;jpeg;jpe;resx;tiff;tif;png;wav" + UniqueIdentifier="{67DA6AB6-F800-4c08-8B7A-83BB121AAD01}" + > + <File + RelativePath=".\DLL.rc" + > + </File> + </Filter> + </Files> + <Globals> + </Globals> +</VisualStudioProject> diff --git a/jpegxr/JPEG-XR.sln b/jpegxr/JPEG-XR.sln new file mode 100644 index 000000000..d43de8ee4 --- /dev/null +++ b/jpegxr/JPEG-XR.sln @@ -0,0 +1,29 @@ + +Microsoft Visual Studio Solution File, Format Version 10.00 +# Visual Studio 2008 +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "DLL", "DLL.vcproj", "{969C2750-EF0E-428F-9A85-20256796BC5C}" +EndProject +Project("{8BC9CEB8-8B4A-11D0-8D11-00A0C91BC942}") = "APP", "APP.vcproj", "{FA1F4A8C-4C1F-4560-9750-351432EE6D8A}" + ProjectSection(ProjectDependencies) = postProject + {969C2750-EF0E-428F-9A85-20256796BC5C} = {969C2750-EF0E-428F-9A85-20256796BC5C} + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|Win32 = Debug|Win32 + Release|Win32 = Release|Win32 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {969C2750-EF0E-428F-9A85-20256796BC5C}.Debug|Win32.ActiveCfg = Debug|Win32 + {969C2750-EF0E-428F-9A85-20256796BC5C}.Debug|Win32.Build.0 = Debug|Win32 + {969C2750-EF0E-428F-9A85-20256796BC5C}.Release|Win32.ActiveCfg = Release|Win32 + {969C2750-EF0E-428F-9A85-20256796BC5C}.Release|Win32.Build.0 = Release|Win32 + {FA1F4A8C-4C1F-4560-9750-351432EE6D8A}.Debug|Win32.ActiveCfg = Debug|Win32 + {FA1F4A8C-4C1F-4560-9750-351432EE6D8A}.Debug|Win32.Build.0 = Debug|Win32 + {FA1F4A8C-4C1F-4560-9750-351432EE6D8A}.Release|Win32.ActiveCfg = Release|Win32 + {FA1F4A8C-4C1F-4560-9750-351432EE6D8A}.Release|Win32.Build.0 = Release|Win32 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/jpegxr/Makefile b/jpegxr/Makefile new file mode 100644 index 000000000..75f4fa667 --- /dev/null +++ b/jpegxr/Makefile @@ -0,0 +1,63 @@ + +# Change these to suit. +#CFLAGS = -Wall -g -DDETAILED_DEBUG +#CFLAGS = -Wall -O +CFLAGS = -g + +# The "jpegxr" command is build as a demonstration for the +# libjpegxr library. +O = jpegxr.o file.o qp.tab.o qp_lexor.o + +jpegxr: $O libjpegxr.a + +qp.tab.o: qp.tab.c jpegxr.h +qp_lexor.o: qp_lexor.c qp.tab.h jpegxr.h + +jpegxr.o: jpegxr.c jpegxr.h file.h +file.o: file.c file.h + +qp_c_code: qp.tab.c qp.tab.h qp_lexor.c + +# Use this rule (i.e. make dist_files) to pre-generate the C files +# for distribution to systems that do not have a working bison/flex. +dist_files: qp.tab.c qp.tab.h qp_lexor.c + sed -e "/<unistd.h>/ c /* #include <unistd.h> ...is not needed */" qp_lexor.c > tmp.c + mv tmp.c qp_lexor.c + +qp.tab.c qp.tab.h: qp_parse.y + bison -d -p qp_ -b qp qp_parse.y + +qp_lexor.c: qp_lexor.lex + flex -oqp_lexor.c -Pqp_ qp_lexor.lex + +# The library files are here. Note that it is the library that is +# the reference code for JPEG XR. The "jpegxr" command that is +# built above (and the source files that go into it) is only an +# example program that demonstrates this library. +L = algo.o api.o w_emit.o flags.o init.o io.o cr_parse.o cw_emit.o r_parse.o jpegxr_pixelformat.o\ +r_strip.o r_tile_spatial.o r_tile_frequency.o w_strip.o w_tile_spatial.o w_tile_frequency.o x_strip.o +libjpegxr.a: $L + -rm -f $@ + ar cq $@ $L + + +algo.o: algo.c jxr_priv.h jpegxr.h +api.o: api.c jxr_priv.h jpegxr.h +w_emit.o: w_emit.c jxr_priv.h jpegxr.h +flags.o: flags.c jxr_priv.h jpegxr.h +init.o: init.c jxr_priv.h jpegxr.h +io.o: io.c jxr_priv.h jpegxr.h +r_parse.o: r_parse.c jxr_priv.h jpegxr.h +r_strip.o: r_strip.c jxr_priv.h jpegxr.h +w_strip.o: w_strip.c jxr_priv.h jpegxr.h +x_strip.o: x_strip.c jxr_priv.h jpegxr.h +jpegxr_pixelformat.o: jpegxr_pixelformat.c jxr_priv.h +cr_parse.o: cr_parse.c jxr_priv.h jpegxr.h +cw_emit.o: cw_emit.c jxr_priv.h jpegxr.h + +r_tile_frequency.o: r_tile_frequency.c jxr_priv.h jpegxr.h +r_tile_spatial.o: r_tile_spatial.c jxr_priv.h jpegxr.h +w_tile_spatial.o: w_tile_spatial.c jxr_priv.h jpegxr.h +w_tile_frequency.o: w_tile_frequency.c jxr_priv.h jpegxr.h + + diff --git a/jpegxr/README.txt b/jpegxr/README.txt new file mode 100644 index 000000000..dadaf51d9 --- /dev/null +++ b/jpegxr/README.txt @@ -0,0 +1,478 @@ +ITU-T Rec. T.835 (ex T.JXR-5) | ISO/IEC 29199-5 + +"Information technology – JPEG XR image coding system – Reference software" + +============== + READ-ME FILE +============== + +********************************************************************* +* * +* NOTE: the software in folder my_getopt-1.5 is used solely for * +* facilitating handling of the command line interface paramenters, * +* and it is not part of the algorithimic implementation of JPEG-XR. * +* * +********************************************************************* + +JPEG XR reference software 1.8 (September 2009) +------------------------------------------------------------------- + +This version constitutes changes to the encoder only. Two bugs were fixed: +1. Fix a crashing bug for tiling. +2. Fix a bug in the overlap operators. Overlap code was using row indices relative to the tile instead of relative to the image. + +No changes were made to the usage text. + +JPEG XR reference software 1.7 (July 2009) +------------------------------------------------------------------- + +This version constitutes a change to the encoder only. A bug related to using a detailed quantization information file +without specifying tile sizes (or without tiling) was fixed. + +No changes were made to the usage text. + +JPEG XR reference software 1.6 (29 May 2009) +------------------------------------------------------------------- + +This version constitutes several improvements to both the sample +encoder and reference decoder. + + +Changes related to the decoder are as follows: +1. Add support for upsampling for non zero values of CHROMA_CENTERING_X and CHROMA_CENTERING_Y +2. Enhance container handling to test conformance relationship of tag based container format and codestream +3. Add fix by Thomas Richter for issue caused by some compilers treating unsigned long as 64 bit data +4. Fix a bug in decoding of interleaved YCC/CMYKDIRECT formats + +Changes related to the encoder are as follows: +1. Add support for separate alpha image plane +2. Add support for YCC OUTPUT_CLR_FMT (YUV444, YUV422, YUV420) +3. Add support for CMYKDIRECT +4. Add support for WINDOWING_FLAG +5. Add support for the following pixel formats - 24bppBGR, 32bppBGRA, 32bppBGR, 32bppPGBGRA, 64bppPRGBA, 128bppPRGBA +6. Add code to write IFD tags in the image container. The code for optional tags are in a macro which is disabled by default. +7. Fix a bug related to encoding 40bppCMYKA and 80bppCMYKA using interleaved alpha mode + + + +New usage text: +Usage: Debug\jpegxr.exe <flags> <input_file.jxr> +Usage: e:\rjsourcedepot\multimedia\dmd\CodecDSP\jxrRefCode\current\Debug\jpegxr.exe <flags> <input_file.jxr> + DECODER FLAGS: + [-o <path>] [-w] [-P 44|55|66|111] [-L 4|8|16|32|64|128|255] + + -o: selects output file name (.raw/.tif/.pnm) + (PNM output can be used only for 24bpp RGB and 8bpp gray Output) + (TIF output can be used for all formats except the following: + N channels, BGR, RGBE, YCC, CMYKDirect & Premultiplied RGB) + (RAW output can be used for all formats) + -w: tests whether LONG_WORD_FLAG needs to be equal to TRUE + (will still decode the image) + -P: selects the maximum accepted profile value + (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced) + -L: selects the maximum accepted level value + (4|8|16|32|64|128) + + ENCODER FLAGS: (Temporary (.tmp) files may be used in encoding) + -c [-o <path>] [-b ALL|NOFLEXBITS|NOHIGHPASS|DCONLY] [-a 0|1|2] [-p] + [-f YUV444|YUV422|YUV420] [-F bits] [-h] [-m] [-l 0|1|2] + [-q q1[:q2[:q3]]] [-Q <path>] [-d] [-w] [-U rows:columns] + [-C width1[:width2>[:width3...]]] [-R height1[:height2[:height3...]]] + [-P 44|55|66|111] [-L 4|8|16|32|64|128|255] [-s top|left|bottom|right] + [-r -W width -H height -M 3|4|...|18 [-B 8|16]] + + -c: selects encoding instead of decoding + this flag is necessary for encoding + -o: selects the output file name (.jxr) + -b: selects the bands to encode + (ALL<Default>|NOFLEXBITS|NOHIGHPASS|DCONLY) + -a: selects encoder alpha mode + (0: no alpha|1:interleaved alpha|2:separate alpha) + Default: For tif input files, based on the information in the + PhotometricInterpretation and SamplesPerPixel tags in the container, + the encoder chooses an input pixel format. If the number + of components is 4 and photometric is 2, RGBA input is inferred and + the encoder assumes the presence of an alpha channel while encoding. + If the number of components is 5 and photometric is 5, CMYKA input is + inferred. In both these cases, the encoder infers a pixel format with + an alpha channel. In such cases, the default alpha encoder mode is 2. + For raw input files, when the -M parameter specified by the user is + 9, 10, 11, 12 13, 14, 23, 24, 25, 26 or 28, + the default alpha encoder mode is 2 + In all other cases, the default alpha encoder mode is 0. + -p: selects an input pixel format with a padding channel + With tif input, when the encoder infers that the input file has an + alpha channel (see explanation for -a), this flag causes the encoder + to treat the alpha channel as a padding channel instead + -f: selects the internal color format + (YUV444<Default>|YUV422|YUV420) + -F: selects the number of flexbits to trim + (0<default> - 15) + -h: selects hard tile boundaries + (soft tile boundaries by default) + -m: encode in frequency order codestream + (spatial order by default) + -l: selects the overlapped block filtering + (0:off|1:HP only<Default>|2:all) + + -q: sets the quantization values separately, or one per band + (0<default, lossless> - 255) + -Q: specifies a file containing detailed quantization information + See sample.qp + -d: selects quantization for U/V channels derived from Y channel + + -U: selects uniform tile sizes + -C: selects the number of tile columns and the width of each + -R: selects the number of tile rows and the height of each + + -w: sets LONG_WORD_FLAG equal to FALSE + -P: selects the profile value + (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced) + -L: selects the level value + (4|8|16|32|64|128) + -s: sets the top, left, bottom, and right margins + + -r: selects encoding with RAW images + must also specify -W, -H and -M, optional -B + -W: RAW image width when encoding with RAW images + -H: RAW image height when encoding with RAW images + -M: RAW image format when encoding with RAW images + 3: 3-channel + 4: 4-channel + 5: 5-channel + 6: 6-channel + 7: 7-channel + 8: 8-channel + 9: 3-channel Alpha + 10: 4-channel Alpha + 11: 5-channel Alpha + 12: 6-channel Alpha + 13: 7-channel Alpha + 14: 8-channel Alpha + 15: 32bppRGBE + 16: 16bppBGR555 + 17: 16bppBGR565 + 18: 32bppBGR101010 + 19: YCC420 + 20: YCC422 + 21: YCC444 + 22: YCC444 Fixed Point + 23: YCC420 Alpha + 24: YCC422 Alpha + 25: YCC444 Alpha + 26: YCC444 Fixed Point Alpha + 27: CMYKDIRECT + 28: CMYKDIRECT Alpha + 29: 24bppBGR + 30: 32bppBGR + 31: 32bppBGRA + 32: 32bppPBGRA + 33: 64bppPRGBA + 34: 128bppPRGBAFloat + -B: RAW image bit/channel when encoding with RAW images + 8: 8-bit/channel (default) + 10: 10-bit/channel + 16: 16-bit/channel + + +Raw File Description: +The raw file makes it possible to store the results of the output formatting process . The raw file output consists of either interleaved or sequential data from each of the channels in the image, without any header information. Buffers are stored in a raster scan order. +If OUTPUT_CLR_FMT is equal to YUV_420, YUV_422, YUV_444 or CMYKDirect, the buffer for each channel is stored sequentially. For example, when OUTPUT_CLR_FMT equals YUV_444 all Y samples are stored in the output file, followed by all U samples, followed by all V samples. If OUTPUT_CLR_FMT is equal to YUV422, half as many bytes used for the Y channel will be used to store the U and V channels. Otherwise, uf OUTPUT_CLR_FMT is equal to YUV420, one quarter as many bytes as used for the Y channel will be used to store the U and V channels. If OUTPUT_CLR_FMT is equal to YUV444 or YUV422 and OUTPUT_BITDEPTH is equal to BD10, 2 bytes are used per sample, and the 10 bits are stored in the LSBs of each 2 byte pair. Samples decoded from the alpha image plane (when present), are concatenated with the output obtained from the primary image. +Otherwise, if OUTPUT_CLR_FMT is not equal to YUV_420, YUV_422, YUV_444 or CMYKDirect, the raw file output consists of interleaved data from each channel. The number of bytes used to store each sample is contingent upon the value of OUTPUT_BITDEPTH and whether the format is a packed output format or not. The samples decoded from the image alpha plane (when present), are interleaved with the samples decoded from the primary image. + + +JPEG XR reference software 1.5 (13 Apr 2009) +------------------------------------------------------------------- + +This version constitutes several improvements to both the sample +encoder and reference decoder. + +Decoder changes: +-Add support for fixed point formats +-Add support for floating point formats +-Add support for half formats +-Add support for separate alpha image plane +-Add support for interleaved alpha image plane +-Add support for YCC OUTPUT_CLR_FMT (YUV444, YUV422, YUV420) +-Add support for CMYKDIRECT +-Add support for n-Component formats +-Add support for RGBE format +-Add support for packed output formats +-Add support for LONG_WORD_FLAG +-Add support for Profiles/Levels +-Fix a bug related to USE_DC_QP_FLAG and USE_LP_QP_FLAG +-Add support for raw image buffer output file format +-Add support for WINDOWING_FLAG +-Fix a bug with respect to the index table and spatial ordered + bitstreams +-Improve usage text + +Encoder changes: +-Fix a bug with CMYK encoding +-Add support for frequency mode +-Add support for tiling +-Add support for fixed point formats +-Add support for floating point formats +-Add support for half formats +-Add support for interleaved alpha image plane +-Add support for n-Component formats +-Add support for RGBE format +-Add support for packed output formats +-Add support for LONG_WORD_FLAG +-Add support for Profiles/Levels +-Improve usage text + +New usage text: +Usage: Release\jpegxr.exe <flags> <input_file.jxr> + DECODER FLAGS: + [-o <path>] [-w] [-P 44|55|66|111] [-L 4|8|16|32|64|128|255] + + -o: selects output file name (.raw/.tif/.pnm) + -w: tests whether LONG_WORD_FLAG needs to be equal to TRUE + (will still decode the image) + -P: selects the maximum accepted profile value + (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced) + -L: selects the maximum accepted level value + (4|8|16|32|64|128) + + ENCODER FLAGS: (Temporary (.tmp) files may be used in encoding) + -c [-o <path>] [-b ALL|NOFLEXBITS|NOHIGHPASS|DCONLY] [-a 0|1|2] + [-f YUV444|YUV422|YUV420] [-F bits] [-h] [-m] [-l 0|1|2] + [-q q1[:q2[:q3]]] [-Q <path>] [-d] [-w] [-U rows:columns] + [-C width1[:width2>[:width3...]]] [-R height1[:height2[:height3...]]] + [-P 44|55|66|111] [-L 4|8|16|32|64|128|255] + [-r -W width -H height -M 3|4|5|6|7|8|15|16|17|18 [-B 8|16]] + + -c: selects encoding instead of decoding + this flag is necessary for encoding + -o: selects the output file name (.jxr) + -b: selects the bands to encode + (ALL<Default>|NOFLEXBITS|NOHIGHPASS|DCONLY) + -a: selects encoder alpha mode + (0:no alpha|1:interleaved alpha|2:separate alpha) + -f: selects the internal color format + (YUV444<Default>|YUV422|YUV420) + -F: selects the number of flexbits to trim + (0<default> - 15) + -h: selects hard tile boundaries + (soft tile boundaries by default) + -m: encode in frequency order codestream + (spatial order by default) + -l: selects the overlapped block filtering + (0:off|1:HP only<Default>|2:all) + + -q: sets the quantization values separately, or one per band + (0<default, lossless> - 255) + -Q: specifies a file containing detailed quantization information + See sample.qp + -d: selects quantization for U/V channels derived from Y channel + + -U: selects uniform tile sizes + -C: selects the number of tile columns and the width of each + -R: selects the number of tile rows and the height of each + + -w: sets LONG_WORD_FLAG equal to FALSE + -P: selects the profile value + (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced) + -L: selects the level value + (4|8|16|32|64|128) + + -r: selects encoding with RAW images + must also specify -W, -H and -M, optional -B + -W: RAW image width when encoding with RAW images + -H: RAW image height when encoding with RAW images + -M: RAW image format when encoding with RAW images + 3: 3-channel + 4: 4-channel + 5: 5-channel + 6: 6-channel + 7: 7-channel + 8: 8-channel + 9: 3-channel Alpha + 10: 4-channel Alpha + 11: 5-channel Alpha + 12: 6-channel Alpha + 13: 7-channel Alpha + 14: 8-channel Alpha + 15: 32bppRGBE + 16: 16bppBGR555 + 17: 16bppBGR565 + 18: 32bppBGR101010 + -B: RAW image bit/channel when encoding with RAW images + 8: 8-bit/channel (default) + 16: 16-bit/channel + +Raw File Description: +The raw file makes it possible to store the results of the output formatting process . The raw file output consists of either interleaved or sequential data from each of the channels in the image, without any header information. Buffers are stored in a raster scan order. +If OUTPUT_CLR_FMT is equal to YUV_420, YUV_422, YUV_444 or CMYKDirect, the buffer for each channel is stored sequentially. For example, when OUTPUT_CLR_FMT equals YUV_444 all Y samples are stored in the output file, followed by all U samples, followed by all V samples. If OUTPUT_CLR_FMT is equal to YUV422, half as many bytes used for the Y channel will be used to store the U and V channels. Otherwise, uf OUTPUT_CLR_FMT is equal to YUV420, one quarter as many bytes as used for the Y channel will be used to store the U and V channels. If OUTPUT_CLR_FMT is equal to YUV444 or YUV422 and OUTPUT_BITDEPTH is equal to BD10, 2 bytes are used per sample, and the 10 bits are stored in the LSBs of each 2 byte pair. Samples decoded from the alpha image plane (when present), are concatenated with the output obtained from the primary image. +Otherwise, if OUTPUT_CLR_FMT is not equal to YUV_420, YUV_422, YUV_444 or CMYKDirect, the raw file output consists of interleaved data from each channel. The number of bytes used to store each sample is contingent upon the value of OUTPUT_BITDEPTH and whether the format is a packed output format or not. The samples decoded from the image alpha plane (when present), are interleaved with the samples decoded from the primary image. + + +JPEG XR reference software 1.4 (31 Dec 2008) +------------------------------------------------------------------- + +This version contains a bug fix and integrates the hard tile proposal. +Indentations have been reformatted. It fixes a bug related to decoding of +multiple tile images with quantization step sizes varying across tiles. + +JPEG XR reference software 1.3 (30 Sept 2008) +------------------------------------------------------------------- + +This version was circulated for CD ballot. In has the same +technical design as the 1.2 version. Some renaming of +variables and strings was performed to replace references to +"HD Photo" (and "hdp") with references to "JPEG XR" (and "jxr"). +Some minor header reformatting was performed. + +JPEG XR reference software 1.2 +------------------------------------------------------------------- + +This version integrates the fixed POT filter proposed by +Microsoft. To enable or disable this filter, edit the +line setting FIXED_POT in jxr_priv.h. It is by default enabled +now. + +JPEG XR reference software 1.1 +------------------------------------------------------------------- + +This is an updated/modified version of the 1.0 release of the +reference software, originally provided by Microsoft and Picture +Elements. Modifications for release 1.1 were made by the University +of Stuttgart (Thomas Richter), and are provided under the same +licence terms as release 1.0. + +The following modifications have been made for this release: + +- The main program prints a summary of its command line arguments +if an input file is missing. + +- A new flag "-d" has been added that derives the quantization +parameter for the color planes in the same way the DPK software +derived its quantization parameters from the Y plane. This makes the +reference software backwards compatible to the DPK. + + + +JPEG XR reference software 1.0 +------------------------------------------------------------------- + + +SUMMARY + +The jpegxr program is an example program that uses the jpegxr.h +compression/decompression API. + +USAGE + +jpegxr <flags> <input-file> + +FLAGS + +* -c + +Compress. Normally, jpegxr decompresses the input file. This flag +requests compression instead. + +* -b ALL|NOFLEXBITS|NOHIGHPASS|DCONLY + +When compressing, this flag selects the subbands to use. The names are +taken from the JPEG XR standard. The default is '-b ALL'. This is +only useful for compression. + +* -f <flag> + +Set various encode/decode options. + +* -F <bits> + +Enable FLEXBIT trimming. If FLEXBITS are enabled (-b ALL) then the +<bits> value is the number of bits to trim. The useful value ranges +from 0 to 15 inclusive. -F 0 keeps the most FLEXBITS, and -F 15 keeps +the fewest bits. This is only useful for compression. + +* -l [0|1|2] + +Enable overlap pre-filtering. The default is '-l 0' which turns off +filtering. Values 1 and 2 enable first pass only or first and second +pass filters respectively. + +* -o <path> + +Give the output file destination. If comression is enabled (-c) then +this is the path to the output compressed file. Otherwise, this is the +path where image data is written. + +* -q q1:q2:q3... + +Give the quantization code for each channel. If only 1 value is +given, then use the same quantization value for all channels. if +multiple values are given, separated by a ':', then each is assigned +to a channel. If fewer values are given then there are channels, then +the last value is used for all the remaining channels. For example, +one can use '-q 2:4' to specify Q=2 for Y and Q=4 for U and V channels +of a color image. The default is '-q 0', which along with '-b ALL' +makes compression lossless. The useful range for this value is 0..255. + +* -d + +Derived quantization. If this parameter is specified, only one argument +for -q is required and the code derives more suitable quantization values +for the Cb and Cr chroma components itself, similar to the DPK code. +This option improves coding efficency noticably whenever the color +transformation is run. + +* -Q <path> + +Give an ASCII source file that contains detailed information about the +quantization to use, down to a macroblock level. + + +ENCODE/DECODE OPTIONS + +The -f argument can take any of a variety of options that control +encode decode. The -f flag can appear as often as needed, with one +flag at a time. The currently supported flags are: + + YUV444 -- Encode full color, with no subsampling of UV planes. + + YUV422 -- Encode color by subsampling the UV planes of YUV444. + + YUV420 -- Encode color by subsampling the UV planes of YUV444. + +QP_FILE SYNTAX + +Comments start with a '#' character and continue to the end of the +line. A comment can start anywhere in the line. + +The keywords are: + + DC, LP, HP + channel + independent + separate + tile + uniform + +A NUMBER is an unsigned decimal value. + +A file consists of a number of tile descriptors, one tile descriptor +for each expected tile in the image. A tile descripter is: + + tile ( <n>, <n> ) { tile_comp_mode tile_body } + +A tile_comp_mode is one of the keywords: uniform, separate, or +independent. The tile_body is an unordered list of tile_items: + + channel <n> { channel_body } + LP [ map_list ] + HP [ map_list ] + +The channel_body gives channel-specific information. How many channels +depends on the number of channels and the tile_comp_mode. A channel +body is one each of these channel items: + + DC { <n> } + LP { <n>... } + HP { <n>... } + +--END
\ No newline at end of file diff --git a/jpegxr/algo.c b/jpegxr/algo.c new file mode 100644 index 000000000..28c1522f7 --- /dev/null +++ b/jpegxr/algo.c @@ -0,0 +1,1774 @@ +/* +** +** $Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $ +** +** +*/ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $") +#else +#ident "$Id: algo.c,v 1.3 2008-05-13 13:47:11 thor Exp $" +#endif + +/* +* This file contains many common algorithms of JPEGXR processing. +*/ + +# include "jxr_priv.h" +# include <stdio.h> +# include <stdlib.h> +# include <limits.h> +# include <assert.h> + +static void InitVLCTable2(jxr_image_t image, int vlc_select); + +const int _jxr_hp_scan_map[16] = { 0, 1, 4, 5, +2, 3, 6, 7, +8, 9,12,13, +10,11,14,15 }; + +static const unsigned ScanTotals[15] ={32, 30, 28, 26, 24, 22, 20, 18, 16, 14, 12, 10, 8, 6, 4}; +static int long_word_flag = 0; + +/* +* These two functions implemented floor(x/2) and ceil(x/2). Note that +* in C/C++ x/2 is NOT the same as floor(x/2) if x<0. It may be on +* some systems, but not in general. So we do all arithmetic with +* positive values and get the floor/ceil right by manipulating signs +* and rounding afterwards. The YUV444 --> RGB transform must get this +* rounding exactly right or there may be losses in the lossless transform. +*/ +int _jxr_floor_div2(int x) +{ + if (x >= 0) + return x/2; + else + return -((-x+1)/2); +} + +int _jxr_ceil_div2(int x) +{ + if (x >= 0) + return (x+1)/2; + else + return -((-x)/2); +} + +int _jxr_quant_map(jxr_image_t image, int x, int shift) +{ + int man, exp; + + if (x == 0) + return 1; + + if (image->scaled_flag) { + if (x < 16) { + man = x; + exp = shift; + } else { + man = 16 + (x%16); + exp = ((x>>4) - 1) + shift; + } + } else { + if (x < 32) { + man = (x + 3) >> 2; + exp = 0; + } else if (x < 48) { + man = (16 + (x%16) + 1) >> 1; + exp = (x>>4) - 2; + } else { + man = 16 + (x%16); + exp = (x>>4) - 3; + } + } + + return man << exp; +} + +int _jxr_vlc_select(int band, int chroma_flag) +{ + int vlc_select = 0; + + /* Based on the band and the chroma flag, select the vlc table + that we want to use for the ABSLEVEL_INDEX decoder. */ + switch (band) { + case 0: /* DC */ + if (chroma_flag) + vlc_select = AbsLevelIndDCChr; + else + vlc_select = AbsLevelIndDCLum; + break; + case 1: /* LP */ + if (chroma_flag) + vlc_select = AbsLevelIndLP1; + else + vlc_select = AbsLevelIndLP0; + break; + case 2: /* HP */ + if (chroma_flag) + vlc_select = AbsLevelIndHP1; + else + vlc_select = AbsLevelIndHP0; + break; + default: + assert(0); + break; + } + + return vlc_select; +} + +void _jxr_InitVLCTable(jxr_image_t image, int vlc_select) +{ + struct adaptive_vlc_s*table = image->vlc_table + vlc_select; + table->table = 0; + table->deltatable = 0; + table->discriminant = 0; +} + +static void InitVLCTable2(jxr_image_t image, int vlc_select) +{ + struct adaptive_vlc_s*table = image->vlc_table + vlc_select; + table->table = 1; + table->deltatable = 0; + table->delta2table = 1; + table->discriminant = 0; + table->discriminant2 = 0; +} + +/* +* This function is for running the adapt for VLC machines that have +* only 2 tables. In this case, only the table and discriminant +* members are used, and the table is 0 or 1. +*/ +void _jxr_AdaptVLCTable(jxr_image_t image, int vlc_select) +{ + const int cLowerBound = -8; + const int cUpperBound = 8; + + struct adaptive_vlc_s*table = image->vlc_table + vlc_select; + const int max_index = 1; /* Only 2 code tables. */ + + table->deltatable = 0; + if ((table->discriminant < cLowerBound) && (table->table != 0)) { + table->table -= 1; + table->discriminant = 0; + } else if ((table->discriminant > cUpperBound) && (table->table != max_index)) { + table->table += 1; + table->discriminant = 0; + } else { + if (table->discriminant < -64) table->discriminant = -64; + if (table->discriminant > 64) table->discriminant = 64; + } +} + +static void AdaptVLCTable2(jxr_image_t image, int vlc_select, int max_index) +{ + const int LOWER_BOUND = -8; + const int UPPER_BOUND = 8; + + struct adaptive_vlc_s*table = image->vlc_table + vlc_select; + + int disc_lo = table->discriminant; + int disc_hi = table->discriminant2; + + int change_flag = 0; + + if (disc_lo < LOWER_BOUND && table->table > 0) { + table->table -= 1; + change_flag = 1; + + } else if (disc_hi > UPPER_BOUND && table->table < max_index) { + table->table += 1; + change_flag = 1; + } + + + if (change_flag) { + table->discriminant = 0; + table->discriminant2 = 0; + + if (table->table == max_index) { + table->deltatable = table->table - 1; + table->delta2table = table->table - 1; + } else if (table->table == 0) { + table->deltatable = table->table; + table->delta2table = table->table; + } else { + table->deltatable = table->table - 1; + table->delta2table = table->table; + } + + } else { + if (table->discriminant < -64) table->discriminant = -64; + if (table->discriminant > 64) table->discriminant = 64; + if (table->discriminant2 < -64) table->discriminant2 = -64; + if (table->discriminant2 > 64) table->discriminant2 = 64; + } +} + +void _jxr_AdaptLP(jxr_image_t image) +{ + AdaptVLCTable2(image, DecFirstIndLPLum, 4); + AdaptVLCTable2(image, DecIndLPLum0, 3); + AdaptVLCTable2(image, DecIndLPLum1, 3); + AdaptVLCTable2(image, DecFirstIndLPChr, 4); + AdaptVLCTable2(image, DecIndLPChr0, 3); + AdaptVLCTable2(image, DecIndLPChr1, 3); + + _jxr_AdaptVLCTable(image, AbsLevelIndLP0); + _jxr_AdaptVLCTable(image, AbsLevelIndLP1); + + DEBUG(" AdaptLP: DecFirstIndLPLum=%d\n", image->vlc_table[DecFirstIndLPLum].table); + DEBUG(" : DecIndLPLum0=%d\n", image->vlc_table[DecIndLPLum0].table); + DEBUG(" : DecIndLPLum1=%d\n", image->vlc_table[DecIndLPLum1].table); + DEBUG(" : DecFirstIndLPChr=%d\n", image->vlc_table[DecFirstIndLPChr].table); + DEBUG(" : DecIndLPChr0=%d\n", image->vlc_table[DecIndLPChr0].table); + DEBUG(" : DecIndLPChr1=%d\n", image->vlc_table[DecIndLPChr1].table); +} + +void _jxr_AdaptHP(jxr_image_t image) +{ + AdaptVLCTable2(image, DecFirstIndHPLum, 4); + AdaptVLCTable2(image, DecIndHPLum0, 3); + AdaptVLCTable2(image, DecIndHPLum1, 3); + AdaptVLCTable2(image, DecFirstIndHPChr, 4); + AdaptVLCTable2(image, DecIndHPChr0, 3); + AdaptVLCTable2(image, DecIndHPChr1, 3); + + _jxr_AdaptVLCTable(image, AbsLevelIndHP0); + _jxr_AdaptVLCTable(image, AbsLevelIndHP1); + + _jxr_AdaptVLCTable(image, DecNumCBP); + _jxr_AdaptVLCTable(image, DecNumBlkCBP); +} + +/* +* Despite the name, this function doesn't actually reset a +* context. It uses the tx (X position of the time) and mx (X position +* of the macroblock in the tile) to calculate true or false that the +* caller should invoke a context reset. +*/ +int _jxr_InitContext(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + if (mx == 0 && my == 0) + return 1; + else + return 0; +} + +/* +* This function guards Adapt?? functions that are called during the +* parse. At the end of a MB where this function returns true, the +* processing function will call the Adapt?? function. +* +* NOTE: It is *correct* that this function is true for the first and +* the last macroblock. This allows some far right context of a tile +* to inform the first column of the next line, but also allows crazy +* differences to be adapted away. +*/ +int _jxr_ResetContext(jxr_image_t image, unsigned tx, unsigned mx) +{ + assert(tx < image->tile_columns); + assert(image->tile_column_width); + /* Return true for every 16 macroblocks in the tile. */ + if (mx%16 == 0) + return 1; + /* Return true for the final macroblock in the tile. */ + if (image->tile_column_width[tx] == mx+1) + return 1; + + return 0; +} + +int _jxr_ResetTotals(jxr_image_t image, unsigned mx) +{ + if (mx%16 == 0) + return 1; + else return 0; +} + +void _jxr_InitializeModelMB(struct model_s*model, int band) +{ + assert(band <= 2); + + model->state[0] = 0; + model->state[1] = 0; + model->bits[0] = (2-band) * 4; + model->bits[1] = (2-band) * 4; +} + +void _jxr_UpdateModelMB(jxr_image_t image, int lap_mean[2], struct model_s*model, int band) +{ + const int modelweight = 70; + static const int weight0[3] = { 240, 12, 1 }; + static const int weight1[3][MAX_CHANNELS] = { + {0,240,120,80, 60,48,40,34, 30,27,24,22, 20,18,17,16 }, + {0,12,6,4, 3,2,2,2, 2,1,1,1, 1,1,1,1 }, + {0,16,8,5, 4,3,3,2, 2,2,2,1, 1,1,1,1 } + }; + static const int weight2[6] = { 120,37,2, 120,18,1 }; + int j; + + assert(band < 3); + + lap_mean[0] *= weight0[band]; + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + lap_mean[1] *= weight2[band]; + break; + case 2: /* YUV422 */ + lap_mean[1] *= weight2[3+band]; + break; + default: + lap_mean[1] *= weight1[band][image->num_channels-1]; + if (band == 2 /*HP*/) + lap_mean[1] >>= 4; + break; + } + + for (j = 0; j < 2; j += 1) { + int ms = model->state[j]; + int delta = (lap_mean[j] - modelweight) >> 2; + + if (delta <= -8) { + delta += 4; + if (delta < -16) + delta = -16; + ms += delta; + if (ms < -8) { + if (model->bits[j] == 0) { + ms = -8; + } else { + ms = 0; + model->bits[j] -= 1; + } + } + } else if (delta >= 8) { + delta -= 4; + if (delta > 15) + delta = 15; + ms += delta; + if (ms > 8) { + if (model->bits[j] >= 15) { + model->bits[j] = 15; + ms = 8; + } else { + ms = 0; + model->bits[j] += 1; + } + } + } + model->state[j] = ms; + /* If clr_fmt == YONLY, then we really only want to do + this loop once, for j==0. */ + if (image->use_clr_fmt == 0/*YONLY*/) + break; + } +} + +void _jxr_InitializeCountCBPLP(jxr_image_t image) +{ + image->count_max_CBPLP = 1; + image->count_zero_CBPLP = 1; +} + +void _jxr_UpdateCountCBPLP(jxr_image_t image, int cbplp, int max) +{ + image->count_zero_CBPLP += 1; + if (cbplp == 0) + image->count_zero_CBPLP -= 4; + if (image->count_zero_CBPLP > 7) + image->count_zero_CBPLP = 7; + if (image->count_zero_CBPLP < -8) + image->count_zero_CBPLP = -8; + + image->count_max_CBPLP += 1; + if (cbplp == max) + image->count_max_CBPLP -= 4; + if (image->count_max_CBPLP > 7) + image->count_max_CBPLP = 7; + if (image->count_max_CBPLP < -8) + image->count_max_CBPLP = -8; +} + +void _jxr_InitLPVLC(jxr_image_t image) +{ + DEBUG(" ... InitLPVLC\n"); + InitVLCTable2(image, DecFirstIndLPLum); + InitVLCTable2(image, DecIndLPLum0); + InitVLCTable2(image, DecIndLPLum1); + InitVLCTable2(image, DecFirstIndLPChr); + InitVLCTable2(image, DecIndLPChr0); + InitVLCTable2(image, DecIndLPChr1); + + _jxr_InitVLCTable(image, AbsLevelIndLP0); + _jxr_InitVLCTable(image, AbsLevelIndLP1); +} + +void _jxr_InitializeAdaptiveScanLP(jxr_image_t image) +{ + static const int ScanOrderLP[15] = { 4, 1, 5, + 8, 2, 9, 6, + 12, 3, 10, 13, + 7, 14, 11, 15}; + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + image->lopass_scanorder[idx] = ScanOrderLP[idx]; + image->lopass_scantotals[idx] = ScanTotals[idx]; + } +} + +/* +*/ +void _jxr_InitializeAdaptiveScanHP(jxr_image_t image) +{ + static const unsigned ScanOrderHor[15] ={ 4, 1, 5, + 8, 2, 9, 6, + 12, 3, 10, 13, + 7, 14, 11, 15}; + static const unsigned ScanOrderVer[15] ={ 1, 2, 5, + 4, 3, 6, 9, + 8, 7, 12, 15, + 13, 10, 11, 14}; + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + image->hipass_hor_scanorder[idx] = ScanOrderHor[idx]; + image->hipass_hor_scantotals[idx] = ScanTotals[idx]; + image->hipass_ver_scanorder[idx] = ScanOrderVer[idx]; + image->hipass_ver_scantotals[idx] = ScanTotals[idx]; + } +} + +void _jxr_InitializeCBPModel(jxr_image_t image) +{ + image->hp_cbp_model.state[0] = 0; + image->hp_cbp_model.state[1] = 0; + image->hp_cbp_model.count0[0] = -4; + image->hp_cbp_model.count0[1] = -4; + image->hp_cbp_model.count1[0] = 4; + image->hp_cbp_model.count1[1] = 4; +} + +void _jxr_InitHPVLC(jxr_image_t image) +{ + InitVLCTable2(image, DecFirstIndHPLum); + InitVLCTable2(image, DecIndHPLum0); + InitVLCTable2(image, DecIndHPLum1); + InitVLCTable2(image, DecFirstIndHPChr); + InitVLCTable2(image, DecIndHPChr0); + InitVLCTable2(image, DecIndHPChr1); + + _jxr_InitVLCTable(image, AbsLevelIndHP0); + _jxr_InitVLCTable(image, AbsLevelIndHP1); + + /* _jxr_InitVLCTable(image, DecNumCBP); */ + /* _jxr_InitVLCTable(image, DecNumBlkCBP); */ +} + +void _jxr_InitCBPVLC(jxr_image_t image) +{ + _jxr_InitVLCTable(image, DecNumCBP); + _jxr_InitVLCTable(image, DecNumBlkCBP); +} + +static int num_ones(int val) +{ + int cnt = 0; + + assert(val >= 0); + + while (val > 0) { + if (val&1) cnt += 1; + val >>= 1; + } + return cnt; +} + +# define SAT(x) do { if ((x) > 15) (x)=15 ; else if ((x) < -16) (x)=-16; } while(0); + +static void update_cbp_model(jxr_image_t image, int c1, int norig) +{ + const int ndiff = 3; + + struct cbp_model_s*hp_cbp_model = & (image->hp_cbp_model); + + hp_cbp_model->count0[c1] += norig - ndiff; + SAT(hp_cbp_model->count0[c1]); + + hp_cbp_model->count1[c1] += 16 - norig - ndiff; + SAT(hp_cbp_model->count1[c1]); + + if (hp_cbp_model->count0[c1] < 0) { + if (hp_cbp_model->count0[c1] < hp_cbp_model->count1[c1]) + hp_cbp_model->state[c1] = 1; + else + hp_cbp_model->state[c1] = 2; + + } else if (hp_cbp_model->count1[c1] < 0) { + hp_cbp_model->state[c1] = 2; + + } else { + hp_cbp_model->state[c1] = 0; + } +} + +int _jxr_PredCBP444(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, + unsigned mx, unsigned my) +{ + int chroma_flag = 0; + int cbp; + int norig; + + if (channel > 0) + chroma_flag = 1; + + DEBUG(" PredCBP444: Prediction mode = %d\n", image->hp_cbp_model.state[chroma_flag]); + cbp = diff_cbp[channel]; + if (image->hp_cbp_model.state[chroma_flag] == 0) { + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>10)&1; + } else { + cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>5)&1; + } + + cbp ^= 0x02 & (cbp<<1); + cbp ^= 0x10 & (cbp<<3); + cbp ^= 0x20 & (cbp<<1); + cbp ^= (cbp&0x33) << 2; + cbp ^= (cbp&0xcc) << 6; + cbp ^= (cbp&0x3300) << 2; + + } else if (image->hp_cbp_model.state[chroma_flag] == 2) { + cbp ^= 0xffff; + } + + norig = num_ones(cbp); + DEBUG(" PredCBP444: NOrig=%d, CBPModel.Count0/1[%d]= %d/%d\n", norig, chroma_flag, + image->hp_cbp_model.count0[chroma_flag], + image->hp_cbp_model.count1[chroma_flag]); + update_cbp_model(image, chroma_flag, norig); + DEBUG(" PredCBP444: ...becomes CBPModel.Count0/1[%d]= %d/%d, new state=%d\n", + chroma_flag, image->hp_cbp_model.count0[chroma_flag], + image->hp_cbp_model.count1[chroma_flag], image->hp_cbp_model.state[chroma_flag]); + return cbp; +} + +void _jxr_w_PredCBP444(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) +{ + int chroma_flag = 0; + int cbp; + int norig; + if (ch > 0) + chroma_flag = 1; + + DEBUG(" PredCBP444: Prediction mode = %d\n", image->hp_cbp_model.state[chroma_flag]); + cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); + norig = num_ones(cbp); + + DEBUG(" PredCBP444: ... cbp starts as 0x%x\n", cbp); + + if (image->hp_cbp_model.state[chroma_flag] == 0) { + + cbp ^= (cbp&0x3300) << 2; + cbp ^= (cbp&0xcc) << 6; + cbp ^= (cbp&0x33) << 2; + cbp ^= 0x20 & (cbp<<1); + cbp ^= 0x10 & (cbp<<3); + cbp ^= 0x02 & (cbp<<1); + + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_CUR_HPCBP(image,ch, tx, mx)>>10)&1; + } else { + cbp ^= (MACROBLK_UP1_HPCBP(image,ch, tx, mx-1)>>5)&1; + } + + + } else if (image->hp_cbp_model.state[chroma_flag] == 2){ + cbp ^= 0xffff; + } + + DEBUG(" PredCBP444: ... diff_cbp 0x%04x\n", cbp); + MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; + + update_cbp_model(image, chroma_flag, norig); +} + +int _jxr_PredCBP422(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, + unsigned mx, unsigned my) +{ + int cbp; + int norig; + + assert(channel > 0); + DEBUG(" PredCBP422: Prediction mode = %d, channel=%d, cbp_mode.State[1]=%d\n", + image->hp_cbp_model.state[1], channel, image->hp_cbp_model.state[1]); + cbp = diff_cbp[channel]; + + if (image->hp_cbp_model.state[1] == 0) { + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>6)&1; + } else { + cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>1)&1; + } + + cbp ^= 0x02 & (cbp<<1); + cbp ^= 0x0c & (cbp<<2); + cbp ^= 0x30 & (cbp<<2); + cbp ^= 0xc0 & (cbp<<2); + } else if (image->hp_cbp_model.state[1] == 2) { + cbp ^= 0xff; + } + + norig = num_ones(cbp) * 2; + update_cbp_model(image, 1, norig); + + return cbp; +} + +void _jxr_w_PredCBP422(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) +{ + int cbp; + int norig; + + assert(ch > 0); + DEBUG(" PredCBP422: Prediction mode = %d\n", image->hp_cbp_model.state[1]); + cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); + norig = num_ones(cbp) * 2; + + DEBUG(" PredCBP422: ... cbp[%d] starts as 0x%x\n", ch, cbp); + + if (image->hp_cbp_model.state[1] == 0) { + + cbp ^= 0xc0 & (cbp<<2); + cbp ^= 0x30 & (cbp<<2); + cbp ^= 0x0c & (cbp<<2); + cbp ^= 0x02 & (cbp<<1); + + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_CUR_HPCBP(image, ch, tx, mx)>>6)&1; + } else { + cbp ^= (MACROBLK_UP1_HPCBP(image, ch, tx, mx-1)>>1)&1; + } + + } else if (image->hp_cbp_model.state[1] == 2) { + cbp ^= 0xff; + } + + DEBUG(" PredCBP422: ... diff_cbp 0x%04x\n", cbp); + MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; + + update_cbp_model(image, 1, norig); +} + + +int _jxr_PredCBP420(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, + unsigned mx, unsigned my) +{ + int cbp; + int norig; + assert(channel > 0); + DEBUG(" PredCBP420: Prediction mode = %d, channel=%d, cbp_mode.State[1]=%d\n", + image->hp_cbp_model.state[1], channel, image->hp_cbp_model.state[1]); + cbp = diff_cbp[channel]; + + if (image->hp_cbp_model.state[1] == 0) { + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_UP1_HPCBP(image, channel, tx, mx)>>2)&1; + } else { + cbp ^= (MACROBLK_CUR_HPCBP(image, channel, tx, mx-1)>>1)&1; + } + + cbp ^= 0x02 & (cbp<<1); + cbp ^= 0x0c & (cbp<<2); + } else if (image->hp_cbp_model.state[1] == 2) { + cbp ^= 0xf; + } + + norig = num_ones(cbp) * 4; + update_cbp_model(image, 1, norig); + + return cbp; +} + +void _jxr_w_PredCBP420(jxr_image_t image, int ch, unsigned tx, unsigned mx, int my) +{ + int cbp; + int norig; + assert(ch > 0); + DEBUG(" PredCBP420: Prediction mode = %d\n", image->hp_cbp_model.state[1]); + cbp = MACROBLK_UP1_HPCBP(image,ch,tx,mx); + norig = num_ones(cbp) * 4; + + DEBUG(" PredCBP420: ... cbp[%d] starts as 0x%x\n", ch, cbp); + + if (image->hp_cbp_model.state[1] == 0) { + + cbp ^= 0x0c & (cbp<<2); + cbp ^= 0x02 & (cbp<<1); + + if (mx == 0) { + if (my == 0) + cbp ^= 1; + else + cbp ^= (MACROBLK_CUR_HPCBP(image, ch, tx, mx)>>2)&1; + } else { + cbp ^= (MACROBLK_UP1_HPCBP(image, ch, tx, mx-1)>>1)&1; + } + + } else if (image->hp_cbp_model.state[1] == 2) { + cbp ^= 0xf; + } + + DEBUG(" PredCBP420: ... diff_cbp 0x%04x\n", cbp); + MACROBLK_UP1(image,ch,tx,mx).hp_diff_cbp = cbp; + + update_cbp_model(image, 1, norig); +} + +void _jxr_ResetTotalsAdaptiveScanLP(jxr_image_t image) +{ + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + image->lopass_scantotals[idx] = ScanTotals[idx]; + } +} + +void _jxr_ResetTotalsAdaptiveScanHP(jxr_image_t image) +{ + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + image->hipass_hor_scantotals[idx] = ScanTotals[idx]; + image->hipass_ver_scantotals[idx] = ScanTotals[idx]; + } +} + +static int +calculate_mbdc_mode(jxr_image_t image, int tx, int mx, int my) +{ + long left; + long top; + long topleft; + long strhor; + long strvert; + + if (mx == 0 && my == 0) + return 3; /* No prediction. */ + + if (mx == 0) + return 1; /* Predictions from top only. */ + + if (my == 0) + return 0; /* prediction from left only */ + + left = MACROBLK_CUR_DC(image, 0, tx, mx-1); + top = MACROBLK_UP_DC(image, 0, tx, mx); + topleft = MACROBLK_UP_DC(image, 0, tx, mx-1); + + strhor = 0; + strvert = 0; + if (image->use_clr_fmt==0 || image->use_clr_fmt==6) {/* YONLY or NCOMPONENT */ + + strhor = labs(topleft - left); + strvert = labs(topleft - top); + } else { + long left_u = MACROBLK_CUR_DC(image, 1, tx, mx-1); + long top_u = MACROBLK_UP_DC(image, 1, tx, mx); + long topleft_u = MACROBLK_UP_DC(image, 1, tx, mx-1); + long left_v = MACROBLK_CUR_DC(image, 2, tx, mx-1); + long top_v = MACROBLK_UP_DC(image, 2, tx, mx); + long topleft_v = MACROBLK_UP_DC(image, 2, tx, mx-1); + + long scale = 2; + if (image->use_clr_fmt == 2 /*YUV422*/) + scale = 4; + if (image->use_clr_fmt == 1 /*YUV420*/) + scale = 8; + + strhor = labs(topleft - left)*scale + labs(topleft_u - left_u) + labs(topleft_v - left_v); + strvert = labs(topleft - top)*scale + labs(topleft_u - top_u) + labs(topleft_v - top_v); + } + + if ((strhor*4) < strvert) + return 1; + + if ((strvert*4) < strhor) + return 0; + + return 2; +} + +static void predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); +static void predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode); +static void predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); + +void _jxr_complete_cur_dclp(jxr_image_t image, int tx, int mx, int my) +{ + /* Calculate the mbcd prediction mode. This mode is used for + all the planes of DC data. */ + int mbdc_mode = calculate_mbdc_mode(image, tx, mx, image->cur_my); + int mblp_mode; + /* Now process all the planes of DC data. */ + int ch; + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + long left = mx>0? MACROBLK_CUR_DC(image,ch,tx,mx-1) : 0; + long top = MACROBLK_UP_DC(image,ch,tx,mx); + + DEBUG(" MBDC_MODE=%d for TX=%d, MBx=%d, MBy=%d (cur_my=%d), ch=%d, left=0x%lx, top=0x%lx, cur=0x%x\n", + mbdc_mode, tx, mx, my, image->cur_my, ch, left, top, MACROBLK_CUR_DC(image,ch,tx,mx)); + + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0] = MACROBLK_CUR_DC(image,ch,tx,mx); + CHECK1(image->lwf_test, MACROBLK_CUR_DC(image,ch,tx,mx)); + switch (mbdc_mode) { + case 0: /* left */ + MACROBLK_CUR_DC(image,ch,tx,mx) += left; + break; + case 1: /* top */ + MACROBLK_CUR_DC(image,ch,tx,mx) += top; + break; + case 2:/* top and left */ + /* Note that we really MEAN >>1 and NOT /2. in + particular, if the sum is -1, we want the + result to also be -1. That extra stuff after + the "|" is there to make sure the sign bit is + not lost. Also, the chroma planes for YUV42X + formats round *up* the mean, where all other + planes round down. */ + if (ch>0 && (image->use_clr_fmt==1/*YUV420*/||image->use_clr_fmt==2/*YUV422*/)) + MACROBLK_CUR_DC(image,ch,tx,mx) += (left+top+1) >> 1 | ((left+top+1)&~INT_MAX); + else + MACROBLK_CUR_DC(image,ch,tx,mx) += (left+top) >> 1 | ((left+top)&~INT_MAX); + break; + default: + break; + } + } + + mblp_mode = 0; + if (mbdc_mode==0 && MACROBLK_CUR_LP_QUANT(image,0,tx,mx) == MACROBLK_CUR_LP_QUANT(image,0,tx,mx-1)) { + mblp_mode = 0; + } else if (mbdc_mode==1 && MACROBLK_CUR_LP_QUANT(image,0,tx,mx) == MACROBLK_UP1_LP_QUANT(image,0,tx,mx)) { + mblp_mode = 1; + + } else { + mblp_mode = 2; + } + + DEBUG(" MBLP_MODE=%d for MBx=%d, MBy=%d (lp_quant=%d,lp_quant_ctx=%d)\n", mblp_mode, mx, image->cur_my, + MACROBLK_CUR_LP_QUANT(image,0,tx,mx), + mbdc_mode==0? MACROBLK_CUR_LP_QUANT(image,0,tx,mx-1) : mbdc_mode==1 ? MACROBLK_UP1_LP_QUANT(image,0,tx,mx) : -1); + + predict_lp444(image, tx, mx, my, 0, mblp_mode); + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + predict_lp420(image, tx, mx, my, ch, mblp_mode); + break; + case 2: /* YUV422 */ + predict_lp422(image, tx, mx, my, ch, mblp_mode, mbdc_mode); + break; + default: + predict_lp444(image,tx, mx, my, ch, mblp_mode); + break; + } + } +} + +static void predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) +{ +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Difference:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0]); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 46, ""); + } + DEBUG("\n"); + } +#endif + + switch (mblp_mode) { + case 0: /* left */ + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,7), MACROBLK_CUR_LP(image,ch,tx,mx,11)); + MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[4]; + MACROBLK_CUR_LP(image,ch,tx,mx,7) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[5]; + MACROBLK_CUR_LP(image,ch,tx,mx,11)+= MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[6]; + break; + case 1: /* up */ + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,2)); + MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1]; + MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[2]; + MACROBLK_CUR_LP(image,ch,tx,mx,2) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[3]; + break; + case 2: + break; + } + +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Predicted:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 45, ""); + } + DEBUG("\n"); + } +#endif + + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[3] = MACROBLK_CUR_LP(image,ch,tx,mx,2); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[4] = MACROBLK_CUR_LP(image,ch,tx,mx,3); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[5] = MACROBLK_CUR_LP(image,ch,tx,mx,7); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[6] = MACROBLK_CUR_LP(image,ch,tx,mx,11); +} + +static void predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode) +{ +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Difference:", my, tx, mx, ch); + DEBUG(" 0x%08x", MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0]); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 52, ""); + } + DEBUG("\n"); + } +#endif + + switch (mblp_mode) { +case 0: /* left */ + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,5)); + MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[4]; + MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[2]; + MACROBLK_CUR_LP(image,ch,tx,mx,5) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[6]; + break; +case 1: /* up */ + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,4)); + MACROBLK_CUR_LP(image,ch,tx,mx,3) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[4]; + MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[5]; + MACROBLK_CUR_LP(image,ch,tx,mx,4) += MACROBLK_CUR_LP(image,ch,tx,mx,0); + break; +case 2: + if (mbdc_mode == 1) + { + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,4)); + MACROBLK_CUR_LP(image,ch,tx,mx,4) += MACROBLK_CUR_LP(image,ch,tx,mx,0); + } + break; + } + +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Predicted:", my, tx, mx, ch); + DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 51, ""); + } + DEBUG("\n"); + } +#endif + + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[4] = MACROBLK_CUR_LP(image,ch,tx,mx,3); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[5] = MACROBLK_CUR_LP(image,ch,tx,mx,4); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[6] = MACROBLK_CUR_LP(image,ch,tx,mx,5); +} + +static void predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) +{ + switch (mblp_mode) { + case 0: /* left */ + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,1)); + MACROBLK_CUR_LP(image,ch,tx,mx,1) += MACROBLK_CUR(image,ch,tx,mx-1).pred_dclp[2]; + break; + case 1: /* up */ + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0)); + MACROBLK_CUR_LP(image,ch,tx,mx,0) += MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1]; + break; + } + +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, tx=%d, mbx=%4d, ch=%d) Predicted:", tx, my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_CUR_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 3 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_CUR_LP(image,ch,tx,mx,jdx)); + } + DEBUG("\n"); + } +#endif + + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1] = MACROBLK_CUR_LP(image,ch,tx,mx,0); + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2] = MACROBLK_CUR_LP(image,ch,tx,mx,1); +} + +/* +* TRANSFORM functions, forward and inverse. +*/ +static void _InvPermute(int*coeff) +{ + static const int inverse[16] = {0, 8, 4, 13, + 2, 15, 3, 14, + 1, 12, 5, 9, + 7, 11, 6, 10}; + int t[16]; + int idx; + + for (idx = 0 ; idx < 16 ; idx += 1) + t[inverse[idx]] = coeff[idx]; + for (idx = 0 ; idx < 16 ; idx += 1) + coeff[idx] = t[idx]; +} + +static void _FwdPermute(int*coeff) +{ + static const int fwd[16] = {0, 8, 4, 6, + 2, 10, 14, 12, + 1, 11, 15, 13, + 9, 3, 7, 5}; + + int t[16]; + int idx; + for (idx = 0 ; idx < 16 ; idx += 1) + t[fwd[idx]] = coeff[idx]; + for (idx = 0 ; idx < 16 ; idx += 1) + coeff[idx] = t[idx]; +} + +static void _2x2T_h(int*a, int*b, int*c, int*d, int R_flag) +{ + int t1; + int t2; + *a += *d; + *b -= *c; + + t1 = ((*a - *b + R_flag) >> 1); + t2 = *c; + + *c = t1 - *d; + *d = t1 - t2; + CHECK5(long_word_flag, *a, *b, t1, *c, *d); + *a -= *d; + *b += *c; + CHECK2(long_word_flag, *a, *b); +} + +static void _2x2T_h_POST(int*a, int*b, int*c, int*d) +{ + int t1; + *b -= *c; + *a += (*d * 3 + 4) >> 3; + *d -= *b >> 1; + t1 = ((*a - *b) >> 1) - *c; + CHECK4(long_word_flag, *b, *a, *d, t1); + *c = *d; + *d = t1; + *a -= *d; + *b += *c; + CHECK2(long_word_flag, *a, *b); +} + +static void _2x2T_h_Enc(int*a, int*b, int*c, int*d) +{ + int t1; + int t2; + *a += *d; + *b -= *c; + CHECK2(long_word_flag, *a, *b); + t1 = *d; + t2 = *c; + *c = ((*a - *b) >> 1) - t1; + *d = t2 + (*b >> 1); + *b += *c; + *a -= (*d * 3 + 4) >> 3; + CHECK4(long_word_flag, *c, *d, *b, *a); +} + +static void _InvT_odd(int*a, int*b, int*c, int*d) +{ + *b += *d; + *a -= *c; + *d -= *b >> 1; + *c += (*a + 1) >> 1; + CHECK4(long_word_flag, *a, *b, *c, *d); + + *a -= ((*b)*3 + 4) >> 3; + *b += ((*a)*3 + 4) >> 3; + *c -= ((*d)*3 + 4) >> 3; + *d += ((*c)*3 + 4) >> 3; + CHECK4(long_word_flag, *a, *b, *c, *d); + + *c -= (*b + 1) >> 1; + *d = ((*a + 1) >> 1) - *d; + *b += *c; + *a -= *d; + CHECK4(long_word_flag, *a, *b, *c, *d); +} + +static void _InvT_odd_odd(int*a, int*b, int*c, int*d) +{ + int t1, t2; + *d += *a; + *c -= *b; + t1 = *d >> 1; + t2 = *c >> 1; + *a -= t1; + *b += t2; + CHECK4(long_word_flag, *a, *b, *c, *d); + + *a -= ((*b)*3 + 3) >> 3; + *b += ((*a)*3 + 3) >> 2; + CHECK2(long_word_flag, *a, *b); + *a -= ((*b)*3 + 4) >> 3; + + *b -= t2; + CHECK2(long_word_flag, *a, *b); + *a += t1; + *c += *b; + *d -= *a; + + *b = -*b; + *c = -*c; + CHECK4(long_word_flag, *a, *b, *c, *d); +} + +static void _InvT_odd_odd_POST(int*a, int*b, int*c, int*d) +{ + int t1, t2; + + *d += *a; + *c -= *b; + t1 = *d >> 1; + t2 = *c >> 1; + *a -= t1; + *b += t2; + CHECK4(long_word_flag, *d, *c, *a, *b); + + *a -= (*b * 3 + 6) >> 3; + *b += (*a * 3 + 2) >> 2; + CHECK2(long_word_flag, *a, *b); + *a -= (*b * 3 + 4) >> 3; + + *b -= t2; + CHECK2(long_word_flag, *a, *b); + *a += t1; + *c += *b; + *d -= *a; + CHECK3(long_word_flag, *a, *c, *d); +} + +static void _T_odd(int*a, int*b, int*c, int*d) +{ + *b -= *c; + *a += *d; + *c += (*b + 1) >> 1; + *d = ((*a + 1) >> 1) - *d; + CHECK4(long_word_flag, *b, *a, *c, *d); + + *b -= (*a * 3 + 4) >> 3; + *a += (*b * 3 + 4) >> 3; + *d -= (*c * 3 + 4) >> 3; + *c += (*d * 3 + 4) >> 3; + CHECK4(long_word_flag, *b, *a, *d, *c); + + *d += *b >> 1; + *c -= (*a + 1) >> 1; + *b -= *d; + *a += *c; + CHECK4(long_word_flag, *d, *c, *b, *a); +} + +static void _T_odd_odd(int*a, int*b, int*c, int*d) +{ + int t1; + int t2; + *b = -*b; + *c = -*c; + CHECK2(long_word_flag, *b, *c); + + *d += *a; + *c -= *b; + t1 = *d >> 1; + t2 = *c >> 1; + *a -= t1; + *b += t2; + CHECK4(long_word_flag, *d, *c, *a, *b); + + *a += (*b * 3 + 4) >> 3; + *b -= (*a * 3 + 3) >> 2; + CHECK2(long_word_flag, *a, *b); + *a += (*b * 3 + 3) >> 3; + + *b -= t2; + CHECK2(long_word_flag, *a, *b); + *a += t1; + *c += *b; + *d -= *a; + CHECK3(long_word_flag, *a, *c, *d); +} + +void _jxr_InvPermute2pt(int*a, int*b) +{ + int t1 = *a; + *a = *b; + *b = t1; +} + +void _jxr_2ptT(int*a, int*b) +{ + *a -= (*b + 1) >> 1; + *b += *a; + CHECK2(long_word_flag, *a, *b); +} + +/* This is the inverse of the 2ptT function */ +void _jxr_2ptFwdT(int*a, int*b) +{ + *b -= *a; + *a += (*b + 1) >> 1; + CHECK2(long_word_flag, *b, *a); +} + +void _jxr_2x2IPCT(int*coeff) +{ + _2x2T_h(coeff+0, coeff+1, coeff+2, coeff+3, 0); + /* _2x2T_h(coeff+0, coeff+2, coeff+1, coeff+3, 0); */ +} + +void _jxr_4x4IPCT(int*coeff) +{ + /* Permute */ + _InvPermute(coeff); + +#if defined(DETAILED_DEBUG) && 0 + { + int idx; + DEBUG(" InvPermute:\n%*s", 4, ""); + for (idx = 0 ; idx < 16 ; idx += 1) { + DEBUG(" 0x%08x", coeff[idx]); + if (idx%4 == 3 && idx != 15) + DEBUG("\n%*s", 4, ""); + } + DEBUG("\n"); + } +#endif + _2x2T_h (coeff+0, coeff+ 1, coeff+4, coeff+ 5, 1); + _InvT_odd(coeff+2, coeff+ 3, coeff+6, coeff+ 7); + _InvT_odd(coeff+8, coeff+12, coeff+9, coeff+13); + _InvT_odd_odd(coeff+10, coeff+11, coeff+14, coeff+15); +#if defined(DETAILED_DEBUG) && 0 + { + int idx; + DEBUG(" stage 1:\n%*s", 4, ""); + for (idx = 0 ; idx < 16 ; idx += 1) { + DEBUG(" 0x%08x", coeff[idx]); + if (idx%4 == 3 && idx != 15) + DEBUG("\n%*s", 4, ""); + } + DEBUG("\n"); + } +#endif + + _2x2T_h(coeff+0, coeff+3, coeff+12, coeff+15, 0); + _2x2T_h(coeff+5, coeff+6, coeff+ 9, coeff+10, 0); + _2x2T_h(coeff+1, coeff+2, coeff+13, coeff+14, 0); + _2x2T_h(coeff+4, coeff+7, coeff+ 8, coeff+11, 0); +} + +void _jxr_4x4PCT(int*coeff) +{ + _2x2T_h(coeff+0, coeff+3, coeff+12, coeff+15, 0); + _2x2T_h(coeff+5, coeff+6, coeff+ 9, coeff+10, 0); + _2x2T_h(coeff+1, coeff+2, coeff+13, coeff+14, 0); + _2x2T_h(coeff+4, coeff+7, coeff+ 8, coeff+11, 0); + + _2x2T_h (coeff+0, coeff+ 1, coeff+4, coeff+ 5, 1); + _T_odd(coeff+2, coeff+ 3, coeff+6, coeff+ 7); + _T_odd(coeff+8, coeff+12, coeff+9, coeff+13); + _T_odd_odd(coeff+10, coeff+11, coeff+14, coeff+15); + + _FwdPermute(coeff); +} + +static void _InvRotate(int*a, int*b) +{ + *a -= (*b + 1) >> 1; + *b += (*a + 1) >> 1; + CHECK2(long_word_flag, *a, *b); +} + +static void _InvScale(int*a, int*b) +{ + *a += *b; + *b = (*a >> 1) - *b; + CHECK2(long_word_flag, *a, *b); + *a += (*b * 3 + 0) >> 3; + *b -= *a >> 10; + CHECK2(long_word_flag, *a, *b); + *b += *a >> 7; + *b += (*a * 3 + 0) >> 4; + CHECK1(long_word_flag, *b); +} + +void _jxr_4x4OverlapFilter(int*a, int*b, int*c, int*d, + int*e, int*f, int*g, int*h, + int*i, int*j, int*k, int*l, + int*m, int*n, int*o, int*p) +{ + _2x2T_h(a, d, m, p, 0); + _2x2T_h(b, c, n, o, 0); + _2x2T_h(e, h, i, l, 0); + _2x2T_h(f, g, j, k, 0); + + _InvRotate(n, m); + _InvRotate(j, i); + _InvRotate(h, d); + _InvRotate(g, c); + _InvT_odd_odd_POST(k, l, o, p); + + _InvScale(a, p); + _InvScale(b, o); + _InvScale(e, l); + _InvScale(f, k); + + _2x2T_h_POST(a, d, m, p); + _2x2T_h_POST(b, c, n, o); + _2x2T_h_POST(e, h, i, l); + _2x2T_h_POST(f, g, j, k); +} + +void _jxr_4OverlapFilter(int*a, int*b, int*c, int*d) +{ + *a += *d; + *b += *c; + *d -= ((*a + 1) >> 1); + *c -= ((*b + 1) >> 1); + CHECK4(long_word_flag, *a, *b, *d, *c); + _InvScale(a, d); + _InvScale(b, c); + *a += ((*d * 3 + 4) >> 3); + *b += ((*c * 3 + 4) >> 3); + *d -= (*a >> 1); + *c -= (*b >> 1); + CHECK4(long_word_flag, *a, *b, *d, *c); + *a += *d; + *b += *c; + *d *= -1; + *c *= -1; + CHECK4(long_word_flag, *a, *b, *d, *c); + _InvRotate(c, d); + *d += ((*a + 1) >> 1); + *c += ((*b + 1) >> 1); + *a -= *d; + *b -= *c; + CHECK4(long_word_flag, *a, *b, *d, *c); +} + +void _jxr_2x2OverlapFilter(int*a, int*b, int*c, int*d) +{ + *a += *d; + *b += *c; + *d -= (*a + 1) >> 1; + *c -= (*b + 1) >> 1; + CHECK4(long_word_flag, *a, *b, *d, *c); + *b += (*a + 2) >> 2; + *a += (*b + 1) >> 1; + + *a += (*b >> 5); + *a += (*b >> 9); + *a += (*b >> 13); + CHECK2(long_word_flag, *a, *b); + + *b += (*a + 2) >> 2; + + *d += (*a + 1) >> 1; + *c += (*b + 1) >> 1; + *a -= *d; + CHECK4(long_word_flag, *a, *b, *d, *c); + *b -= *c; + CHECK1(long_word_flag, *b); +} + +void _jxr_2OverlapFilter(int*a, int*b) +{ + *b += ((*a + 2) >> 2); + *a += ((*b + 1) >> 1); + *a += (*b >> 5); + *a += (*b >> 9); + CHECK2(long_word_flag, *a, *b); + *a += (*b >> 13); + *b += ((*a + 2) >> 2); + CHECK2(long_word_flag, *a, *b); +} + +/* Prefiltering... */ + +static void fwdT_Odd_Odd_PRE(int*a, int*b, int*c, int*d) +{ + int t1; + int t2; + *d += *a; + *c -= *b; + t1 = *d >> 1; + t2 = *c >> 1; + *a -= t1; + *b += t2; + CHECK4(long_word_flag, *d, *c, *a, *b); + *a += (*b * 3 + 4) >> 3; + *b -= (*a * 3 + 2) >> 2; + CHECK2(long_word_flag, *a, *b); + *a += (*b * 3 + 6) >> 3; + *b -= t2; + CHECK2(long_word_flag, *a, *b); + *a += t1; + *c += *b; + *d -= *a; + CHECK3(long_word_flag, *a, *c, *d); +} + +static void fwdScale(int*a, int*b) +{ + *b -= (*a * 3 + 0) >> 4; + CHECK1(long_word_flag, *b); + *b -= *a >> 7; + CHECK1(long_word_flag, *b); + *b += *a >> 10; + *a -= (*b * 3 + 0) >> 3; + CHECK2(long_word_flag, *b, *a); + *b = (*a >> 1) - *b; + *a -= *b; + CHECK2(long_word_flag, *b, *a); +} + +static void fwdRotate(int*a, int*b) +{ + *b -= (*a + 1) >> 1; + *a += (*b + 1) >> 1; + CHECK2(long_word_flag, *b, *a); +} + +void _jxr_4x4PreFilter(int*a, int*b, int*c, int*d, + int*e, int*f, int*g, int*h, + int*i, int*j, int*k, int*l, + int*m, int*n, int*o, int*p) +{ + _2x2T_h_Enc(a, d, m, p); + _2x2T_h_Enc(b, c, n, o); + _2x2T_h_Enc(e, h, i, l); + _2x2T_h_Enc(f, g, j, k); + + fwdScale(a, p); + fwdScale(b, o); + fwdScale(e, l); + fwdScale(f, k); + + fwdRotate(n, m); + fwdRotate(j, i); + fwdRotate(h, d); + fwdRotate(g, c); + fwdT_Odd_Odd_PRE(k, l, o, p); + + _2x2T_h(a, m, d, p, 0); + _2x2T_h(b, c, n, o, 0); + _2x2T_h(e, h, i, l, 0); + _2x2T_h(f, g, j, k, 0); +} + +void _jxr_4PreFilter(int*a, int*b, int*c, int*d) +{ + *a += *d; + *b += *c; + *d -= ((*a + 1) >> 1); + *c -= ((*b + 1) >> 1); + CHECK4(long_word_flag, *a, *b, *d, *c); + fwdRotate(c, d); + *d *= -1; + *c *= -1; + *a -= *d; + *b -= *c; + CHECK4(long_word_flag, *d, *c, *a, *b); + *d += (*a >> 1); + *c += (*b >> 1); + *a -= ((*d * 3 + 4) >> 3); + *b -= ((*c * 3 + 4) >> 3); + CHECK4(long_word_flag, *d, *c, *a, *b); + fwdScale(a, d); + fwdScale(b, c); + *d += ((*a + 1) >> 1); + *c += ((*b + 1) >> 1); + *a -= *d; + *b -= *c; + CHECK4(long_word_flag, *d, *c, *a, *b); +} + +void _jxr_2x2PreFilter(int*a, int*b, int*c, int*d) +{ + *a += *d; + *b += *c; + *d -= ((*a + 1) >> 1); + *c -= ((*b + 1) >> 1); + CHECK4(long_word_flag, *a, *b, *d, *c); + *b -= ((*a + 2) >> 2); + *a -= (*b >> 5); + CHECK2(long_word_flag, *b, *a); + *a -= (*b >> 9); + CHECK1(long_word_flag, *a); + *a -= (*b >> 13); + CHECK1(long_word_flag, *a); + *a -= ((*b + 1) >> 1); + *b -= ((*a + 2) >> 2); + *d += ((*a + 1) >> 1); + *c += ((*b + 1) >> 1); + CHECK4(long_word_flag, *a, *b, *d, *c); + *a -= *d; + *b -= *c; + CHECK2(long_word_flag, *a, *b); +} + +void _jxr_2PreFilter(int*a, int*b) +{ + *b -= ((*a + 2) >> 2); + *a -= (*b >> 13); + CHECK2(long_word_flag, *b, *a); + *a -= (*b >> 9); + CHECK1(long_word_flag, *a); + *a -= (*b >> 5); + CHECK1(long_word_flag, *a); + *a -= ((*b + 1) >> 1); + *b -= ((*a + 2) >> 2); + CHECK2(long_word_flag, *a, *b); +} + +uint8_t _jxr_read_lwf_test_flag() +{ + return long_word_flag; +} + +/* +* $Log: algo.c,v $ +* +* Revision 1.58 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.57 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.56 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.55 2008-05-13 13:47:11 thor +* Some experiments with a smarter selection for the quantization size, +* does not yet compile. +* +* Revision 1.54 2008-05-09 19:57:48 thor +* Reformatted for unix LF. +* +* Revision 1.53 2008-04-15 14:28:12 thor +* Start of the repository for the jpegxr reference software. +* +* Revision 1.52 2008/03/20 18:11:50 steve +* Clarify MBLPMode calculations. +* +* Revision 1.51 2008/03/14 00:54:08 steve +* Add second prefilter for YUV422 and YUV420 encode. +* +* Revision 1.50 2008/03/13 22:32:26 steve +* Fix CBP prediction for YUV422, mode==0. +* +* Revision 1.49 2008/03/13 17:49:31 steve +* Fix problem with YUV422 CBP prediction for UV planes +* +* Add support for YUV420 encoding. +* +* Revision 1.48 2008/03/13 00:07:22 steve +* Encode HP of YUV422 +* +* Revision 1.47 2008/03/12 21:10:27 steve +* Encode LP of YUV422 +* +* Revision 1.46 2008/03/11 22:12:48 steve +* Encode YUV422 through DC. +* +* Revision 1.45 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.44 2008/02/22 23:01:33 steve +* Compress macroblock HP CBP packets. +* +* Revision 1.43 2008/02/01 22:49:52 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.42 2008/01/08 23:23:32 steve +* Minor math error in overlap code. +* +* Revision 1.41 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.40 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.39 2008/01/01 01:08:23 steve +* Compile warning. +* +* Revision 1.38 2008/01/01 01:07:25 steve +* Add missing HP prediction. +* +* Revision 1.37 2007/12/30 00:16:00 steve +* Add encoding of HP values. +* +* Revision 1.36 2007/12/17 23:02:57 steve +* Implement MB_CBP encoding. +* +* Revision 1.35 2007/12/14 17:10:39 steve +* HP CBP Prediction +* +* Revision 1.34 2007/12/12 00:36:46 steve +* Use T_odd instead of InvT_odd for PCT transform. +* +* Revision 1.33 2007/12/06 23:12:40 steve +* Stubs for LP encode operations. +* +* Revision 1.32 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.31 2007/11/21 23:24:09 steve +* Account for tiles selecting LP_QUANT for pred math. +* +* Revision 1.30 2007/11/16 20:03:57 steve +* Store MB Quant, not qp_index. +* +* Revision 1.29 2007/11/13 03:27:23 steve +* Add Frequency mode LP support. +* +* Revision 1.28 2007/10/30 21:32:46 steve +* Support for multiple tile columns. +* +* Revision 1.27 2007/10/23 00:34:12 steve +* Level1 filtering for YUV422 and YUV420 +* +* Revision 1.26 2007/10/22 21:52:37 steve +* Level2 filtering for YUV420 +* +* Revision 1.25 2007/10/19 22:07:11 steve +* Prediction of YUV420 chroma planes. +* +* Revision 1.24 2007/10/19 16:20:21 steve +* Parse YUV420 HP +* +* Revision 1.23 2007/10/17 23:43:19 steve +* Add support for YUV420 +* +* Revision 1.22 2007/10/04 00:30:47 steve +* Fix prediction of HP CBP for YUV422 data. +* +* Revision 1.21 2007/10/02 20:36:29 steve +* Fix YUV42X DC prediction, add YUV42X HP parsing. +* +* Revision 1.20 2007/10/01 20:39:33 steve +* Add support for YUV422 LP bands. +* +* Revision 1.19 2007/09/20 18:04:10 steve +* support render of YUV422 images. +* +* Revision 1.18 2007/09/13 23:12:34 steve +* Support color HP bands. +* +* Revision 1.17 2007/09/11 00:40:06 steve +* Fix rendering of chroma to add the missing *2. +* Fix handling of the chroma LP samples +* Parse some of the HP CBP data in chroma. +* +* Revision 1.16 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.15 2007/09/04 19:10:46 steve +* Finish level1 overlap filtering. +* +* Revision 1.14 2007/08/31 23:31:49 steve +* Initialize CBP VLC tables at the right time. +* +* Revision 1.13 2007/08/28 21:58:52 steve +* Rewrite filtering to match rewritten 4.7 +* +* Revision 1.12 2007/08/14 23:39:56 steve +* Fix UpdateModelMB / Add filtering functions. +* +* Revision 1.11 2007/08/04 00:10:51 steve +* Fix subtle loss of -1 values during DC prediction. +*/ + diff --git a/jpegxr/api.c b/jpegxr/api.c new file mode 100644 index 000000000..37f14d5a4 --- /dev/null +++ b/jpegxr/api.c @@ -0,0 +1,1206 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: api.c,v 1.18 2008/03/21 18:05:53 steve Exp $") +#else +#ident "$Id: api.c,v 1.18 2008/03/21 18:05:53 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> +# include <stdlib.h> + +void _jxr_send_mb_to_output(jxr_image_t image, int mx, int my, int*data) +{ + if (image->out_fun) + image->out_fun(image, mx, my, data); +} + +void jxr_set_block_output(jxr_image_t image, block_fun_t fun) +{ + image->out_fun = fun; +} + +void _jxr_get_mb_from_input(jxr_image_t image, int mx, int my, int*data) +{ + if (image->inp_fun) + image->inp_fun(image, mx, my, data); +} + +void jxr_set_block_input(jxr_image_t image, block_fun_t fun) +{ + image->inp_fun = fun; +} + +void jxr_set_user_data(jxr_image_t image, void*data) +{ + image->user_data = data; +} + +void* jxr_get_user_data(jxr_image_t image) +{ + return image->user_data; +} + +int jxr_get_IMAGE_CHANNELS(jxr_image_t image) +{ + return image->num_channels; +} + +void jxr_set_INTERNAL_CLR_FMT(jxr_image_t image, jxr_color_fmt_t fmt, int channels) +{ + switch (fmt) { + case JXR_YONLY: + image->use_clr_fmt = fmt; + image->num_channels = 1; + break; + case JXR_YUV420: + case JXR_YUV422: + case JXR_YUV444: + image->use_clr_fmt = fmt; + image->num_channels = 3; + break; + case JXR_YUVK: + image->use_clr_fmt = fmt; + image->num_channels = 4; + break; + case JXR_OCF_NCOMPONENT: + image->use_clr_fmt = fmt; + image->num_channels = channels; + break; + default: + image->use_clr_fmt = fmt; + image->num_channels = channels; + break; + } +} + +void jxr_set_OUTPUT_CLR_FMT(jxr_image_t image, jxr_output_clr_fmt_t fmt) +{ + image->output_clr_fmt = fmt; + + switch (fmt) { + case JXR_OCF_YONLY: /* YONLY */ + image->header_flags_fmt |= 0x00; /* OUTPUT_CLR_FMT==0 */ + break; + case JXR_OCF_YUV420: /* YUV420 */ + image->header_flags_fmt |= 0x10; /* OUTPUT_CLR_FMT==1 */ + break; + case JXR_OCF_YUV422: /* YUV422 */ + image->header_flags_fmt |= 0x20; /* OUTPUT_CLR_FMT==2 */ + break; + case JXR_OCF_YUV444: /* YUV444 */ + image->header_flags_fmt |= 0x30; /* OUTPUT_CLR_FMT==3 */ + break; + case JXR_OCF_CMYK: /* CMYK */ + image->header_flags_fmt |= 0x40; /* OUTPUT_CLR_FMT=4 (CMYK) */ + break; + case JXR_OCF_CMYKDIRECT: /* CMYKDIRECT */ + image->header_flags_fmt |= 0x50; /* OUTPUT_CLR_FMT=5 (CMYKDIRECT) */ + break; + case JXR_OCF_RGB: /* RGB color */ + image->header_flags_fmt |= 0x70; /* OUTPUT_CLR_FMT=7 (RGB) */ + break; + case JXR_OCF_RGBE: /* RGBE color */ + image->header_flags_fmt |= 0x80; /* OUTPUT_CLR_FMT=8 (RGBE) */ + break; + case JXR_OCF_NCOMPONENT: /* N-channel color */ + image->header_flags_fmt |= 0x60; /* OUTPUT_CLR_FMT=6 (NCOMPONENT) */ + break; + default: + fprintf(stderr, "Unsupported external color format (%d)! \n", fmt); + break; + } +} + +jxr_output_clr_fmt_t jxr_get_OUTPUT_CLR_FMT(jxr_image_t image) +{ + return image->output_clr_fmt; +} + + +jxr_bitdepth_t jxr_get_OUTPUT_BITDEPTH(jxr_image_t image) +{ + return (jxr_bitdepth_t) SOURCE_BITDEPTH(image); +} + +void jxr_set_OUTPUT_BITDEPTH(jxr_image_t image, jxr_bitdepth_t bd) +{ + image->header_flags_fmt &= ~0x0f; + image->header_flags_fmt |= bd; +} + +void jxr_set_BANDS_PRESENT(jxr_image_t image, jxr_bands_present_t bp) +{ + image->bands_present = bp; + image->bands_present_of_primary = image->bands_present; +} + +void jxr_set_FREQUENCY_MODE_CODESTREAM_FLAG(jxr_image_t image, int flag) +{ + assert(flag >= 0 && flag <= 1); + image->header_flags1 &= ~0x40; + image->header_flags1 |= (flag << 6); + + /* Enable INDEX_TABLE_PRESENT_FLAG */ + if (flag) { + jxr_set_INDEX_TABLE_PRESENT_FLAG(image, 1); + } +} + +void jxr_set_INDEX_TABLE_PRESENT_FLAG(jxr_image_t image, int flag) +{ + assert(flag >= 0 && flag <= 1); + image->header_flags1 &= ~0x04; + image->header_flags1 |= (flag << 2); +} + +void jxr_set_ALPHA_IMAGE_PLANE_FLAG(jxr_image_t image, int flag) +{ + assert(flag == 0 || flag == 1); + if(flag == 1) + image->header_flags2 |= 0x01; + else + image->header_flags2 &= 0xfe; +} + +void jxr_set_PROFILE_IDC(jxr_image_t image, int profile_idc) +{ + assert(profile_idc >= 0 && profile_idc <= 255); + image->profile_idc = (uint8_t) profile_idc; +} + +void jxr_set_LEVEL_IDC(jxr_image_t image, int level_idc) +{ + assert(level_idc >= 0 && level_idc <= 255); + image->level_idc = (uint8_t) level_idc; +} + +void jxr_set_LONG_WORD_FLAG(jxr_image_t image, int flag) +{ + assert(flag >= 0 && flag <= 1); + image->header_flags2 &= ~0x40; + image->header_flags2 |= (flag << 6); +} + +int jxr_test_PROFILE_IDC(jxr_image_t image, int flag) +{ + /* + ** flag = 0 - encoder + ** flag = 1 - decoder + */ + jxr_bitdepth_t obd = jxr_get_OUTPUT_BITDEPTH(image); + jxr_output_clr_fmt_t ocf = jxr_get_OUTPUT_CLR_FMT(image); + + unsigned char profile = image->profile_idc; + /* + * For forward compatability + * Though only specified profiles are currently applicable, decoder shouldn't reject other profiles. + */ + if (flag) { + if (profile <= 44) + profile = 44; + else if (profile <= 55) + profile = 55; + else if (profile <= 66) + profile = 66; + else if (profile <= 111) + profile = 111; + } + + switch (profile) { + case 44: + if (OVERLAP_INFO(image) == 2) + return JXR_EC_BADFORMAT; + if (LONG_WORD_FLAG(image)) + return JXR_EC_BADFORMAT; + if (image->num_channels != 1 && image->num_channels != 3) + return JXR_EC_BADFORMAT; + if (image->alpha) + return JXR_EC_BADFORMAT; + if ((obd == JXR_BD16) || (obd == JXR_BD16S) || (obd == JXR_BD16F) || (obd == JXR_BD32S) || (obd == JXR_BD32F)) + return JXR_EC_BADFORMAT; + if ((ocf != JXR_OCF_RGB) && (ocf != JXR_OCF_YONLY)) + return JXR_EC_BADFORMAT; + break; + case 55: + if (image->num_channels != 1 && image->num_channels != 3) + return JXR_EC_BADFORMAT; + if (image->alpha) + return JXR_EC_BADFORMAT; + if ((obd == JXR_BD16F) || (obd == JXR_BD32S) || (obd == JXR_BD32F)) + return JXR_EC_BADFORMAT; + if ((ocf != JXR_OCF_RGB) && (ocf != JXR_OCF_YONLY)) + return JXR_EC_BADFORMAT; + break; + case 66: + if ((ocf == JXR_OCF_CMYKDIRECT) || (ocf == JXR_OCF_YUV420) || (ocf == JXR_OCF_YUV422) || (ocf == JXR_OCF_YUV444)) + return JXR_EC_BADFORMAT; + break; + case 111: + break; + default: + return JXR_EC_BADFORMAT; + break; + } + + return JXR_EC_OK; +} + +int jxr_test_LEVEL_IDC(jxr_image_t image, int flag) +{ + /* + ** flag = 0 - encoder + ** flag = 1 - decoder + */ + unsigned tr = image->tile_rows - 1; + unsigned tc = image->tile_columns - 1; + uint64_t h = (uint64_t) image->extended_height - 1; + uint64_t w = (uint64_t) image->extended_width - 1; + uint64_t n = (uint64_t) image->num_channels; + uint64_t buf_size = 1; + + unsigned i; + uint64_t max_tile_width = 0, max_tile_height = 0; + unsigned char level; + for (i = 0; i < image->tile_columns; i++) + max_tile_width = (uint64_t) (image->tile_column_width[i] > max_tile_width ? image->tile_column_width[i] : max_tile_width); + for (i = 0; i < image->tile_rows; i++) + max_tile_height = (uint64_t) (image->tile_row_height[i] > max_tile_height ? image->tile_row_height[i] : max_tile_height); + + if (image->alpha) + n += 1; + + switch (SOURCE_BITDEPTH(image)) { + case 1: /* BD8 */ + buf_size = n * (h + 1) * (w + 1); + break; + case 2: /* BD16 */ + case 3: /* BD16S */ + case 4: /* BD16F */ + buf_size = 2 * n * (h + 1) * (w + 1); + break; + case 6: /* BD32S */ + case 7: /* BD32F */ + buf_size = 4 * n * (h + 1) * (w + 1); + break; + case 0: /* BD1WHITE1 */ + case 15: /* BD1BLACK1 */ + buf_size = ((h + 8) >> 3) * ((w + 8) >> 3) * 8; + break; + case 8: /* BD5 */ + case 10: /* BD565 */ + buf_size = 2 * (h + 1) * (w + 1); + break; + case 9: /* BD10 */ + if (image->output_clr_fmt == JXR_OCF_RGB) + buf_size = 4 * (h + 1) * (w + 1); + else + buf_size = 2 * n * (h + 1) * (w + 1); + break; + default: /* RESERVED */ + return JXR_EC_BADFORMAT; + break; + } + + level = image->level_idc; + /* + * For forward compatability + * Though only specified levels are currently applicable, decoder shouldn't reject other levels. + */ + if (flag) { + if (level >= 255) + level = 255; + else if (level >= 128) + level = 128; + else if (level >= 64) + level = 64; + else if (level >= 32) + level = 32; + else if (level >= 16) + level = 16; + else if (level >= 8) + level = 8; + else if (level >= 4) + level = 4; + } + + switch (level) { + case 4: + if ((w >> 10) || (h >> 10) || (tc >> 4) || (tr >> 4) || (max_tile_width >> 10) || (max_tile_height >> 10) || (buf_size >> 22)) + return JXR_EC_BADFORMAT; + break; + case 8: + if ((w >> 11) || (h >> 11) || (tc >> 5) || (tr >> 5) || (max_tile_width >> 11) || (max_tile_height >> 11) || (buf_size >> 24)) + return JXR_EC_BADFORMAT; + break; + case 16: + if ((w >> 12) || (h >> 12) || (tc >> 6) || (tr >> 6) || (max_tile_width >> 12) || (max_tile_height >> 12) || (buf_size >> 26)) + return JXR_EC_BADFORMAT; + break; + case 32: + if ((w >> 13) || (h >> 13) || (tc >> 7) || (tr >> 7) || (max_tile_width >> 12) || (max_tile_height >> 12) || (buf_size >> 28)) + return JXR_EC_BADFORMAT; + break; + case 64: + if ((w >> 14) || (h >> 14) || (tc >> 8) || (tr >> 8) || (max_tile_width >> 12) || (max_tile_height >> 12) || (buf_size >> 30)) + return JXR_EC_BADFORMAT; + break; + case 128: + if ((w >> 16) || (h >> 16) || (tc >> 10) || (tr >> 10) || (max_tile_width >> 12) || (max_tile_height >> 12) || (buf_size >> 32)) + return JXR_EC_BADFORMAT; + break; + case 255: /* width and height restriction is 2^32 */ + if ((w >> 32) || (h >> 32) || (tc >> 12) || (tr >> 12) || (max_tile_width >> 32) || (max_tile_height >> 32)) + return JXR_EC_BADFORMAT; + break; + default: + return JXR_EC_BADFORMAT; + break; + } + + return JXR_EC_OK; +} + +void jxr_set_container_parameters(jxr_image_t image, jxrc_t_pixelFormat pixel_format, unsigned wid, unsigned hei, unsigned separate, unsigned char image_presence, unsigned char alpha_presence, unsigned char alpha) { + image->container_width = wid; + image->container_height = hei; + image->container_separate_alpha = separate ? 1 : 0; + image->container_image_band_presence = image_presence; + image->container_alpha_band_presence = alpha_presence; + image->container_current_separate_alpha = alpha ? 1 : 0; + + switch (pixel_format) { + case JXRC_FMT_24bppRGB: + case JXRC_FMT_24bppBGR: + case JXRC_FMT_32bppBGR: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_48bppRGB: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_48bppRGBFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_48bppRGBHalf: + image->container_alpha = 0; + image->container_bpc = JXR_BD16F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_96bppRGBFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD32S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_64bppRGBFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_64bppRGBHalf: + image->container_alpha = 0; + image->container_bpc = JXR_BD16F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_128bppRGBFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD32S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_128bppRGBFloat: + image->container_alpha = 0; + image->container_bpc = JXR_BD32F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_32bppBGRA: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_64bppRGBA: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_64bppRGBAFixedPoint: + image->container_alpha = 1; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_64bppRGBAHalf: + image->container_alpha = 1; + image->container_bpc = JXR_BD16F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_128bppRGBAFixedPoint: + image->container_alpha = 1; + image->container_bpc = JXR_BD32S; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_128bppRGBAFloat: + image->container_alpha = 1; + image->container_bpc = JXR_BD32F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_32bppPBGRA: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_64bppPRGBA: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_128bppPRGBAFloat: + image->container_alpha = 1; + image->container_bpc = JXR_BD32F; + image->container_color = JXR_OCF_RGB; + image->container_nc = 4; + break; + case JXRC_FMT_32bppCMYK: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_CMYK; + image->container_nc = 4; + break; + case JXRC_FMT_40bppCMYKAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_CMYK; + image->container_nc = 5; + break; + case JXRC_FMT_64bppCMYK: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_CMYK; + image->container_nc = 4; + break; + case JXRC_FMT_80bppCMYKAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_CMYK; + image->container_nc = 5; + break; + case JXRC_FMT_24bpp3Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 3; + break; + case JXRC_FMT_32bpp4Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 4; + break; + case JXRC_FMT_40bpp5Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 5; + break; + case JXRC_FMT_48bpp6Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 6; + break; + case JXRC_FMT_56bpp7Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 7; + break; + case JXRC_FMT_64bpp8Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 8; + break; + case JXRC_FMT_32bpp3ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 4; + break; + case JXRC_FMT_40bpp4ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 5; + break; + case JXRC_FMT_48bpp5ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 6; + break; + case JXRC_FMT_56bpp6ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 7; + break; + case JXRC_FMT_64bpp7ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 8; + break; + case JXRC_FMT_72bpp8ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 9; + break; + case JXRC_FMT_48bpp3Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 3; + break; + case JXRC_FMT_64bpp4Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 4; + break; + case JXRC_FMT_80bpp5Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 5; + break; + case JXRC_FMT_96bpp6Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 6; + break; + case JXRC_FMT_112bpp7Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 7; + break; + case JXRC_FMT_128bpp8Channels: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 8; + break; + case JXRC_FMT_64bpp3ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 4; + break; + case JXRC_FMT_80bpp4ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 5; + break; + case JXRC_FMT_96bpp5ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 6; + break; + case JXRC_FMT_112bpp6ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 7; + break; + case JXRC_FMT_128bpp7ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 8; + break; + case JXRC_FMT_144bpp8ChannelsAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_NCOMPONENT; + image->container_nc = 9; + break; + case JXRC_FMT_8bppGray: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_16bppGray: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_16bppGrayFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_16bppGrayHalf: + image->container_alpha = 0; + image->container_bpc = JXR_BD16F; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_32bppGrayFixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD32S; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_32bppGrayFloat: + image->container_alpha = 0; + image->container_bpc = JXR_BD32F; + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_BlackWhite: + image->container_alpha = 0; + image->container_bpc = JXR_BD1WHITE1; /* or JXR_BD1BLACK1 */ + image->container_color = JXR_OCF_YONLY; + image->container_nc = 1; + break; + case JXRC_FMT_16bppBGR555: + image->container_alpha = 0; + image->container_bpc = JXR_BD5; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_16bppBGR565: + image->container_alpha = 0; + image->container_bpc = JXR_BD565; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_32bppBGR101010: + image->container_alpha = 0; + image->container_bpc = JXR_BD10; + image->container_color = JXR_OCF_RGB; + image->container_nc = 3; + break; + case JXRC_FMT_32bppRGBE: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_RGBE; + image->container_nc = 3; + break; + case JXRC_FMT_32bppCMYKDIRECT: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_CMYKDIRECT; + image->container_nc = 4; + break; + case JXRC_FMT_64bppCMYKDIRECT: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_CMYKDIRECT; + image->container_nc = 4; + break; + case JXRC_FMT_40bppCMYKDIRECTAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_CMYKDIRECT; + image->container_nc = 5; + break; + case JXRC_FMT_80bppCMYKDIRECTAlpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_CMYKDIRECT; + image->container_nc = 5; + break; + case JXRC_FMT_12bppYCC420: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV420; + image->container_nc = 3; + break; + case JXRC_FMT_16bppYCC422: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 3; + break; + case JXRC_FMT_20bppYCC422: + image->container_alpha = 0; + image->container_bpc = JXR_BD10; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 3; + break; + case JXRC_FMT_32bppYCC422: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 3; + break; + case JXRC_FMT_24bppYCC444: + image->container_alpha = 0; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 3; + break; + case JXRC_FMT_30bppYCC444: + image->container_alpha = 0; + image->container_bpc = JXR_BD10; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 3; + break; + case JXRC_FMT_48bppYCC444: + image->container_alpha = 0; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 3; + break; + case JXRC_FMT_48bppYCC444FixedPoint: + image->container_alpha = 0; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 3; + break; + case JXRC_FMT_20bppYCC420Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV420; + image->container_nc = 4; + break; + case JXRC_FMT_24bppYCC422Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 4; + break; + case JXRC_FMT_30bppYCC422Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD10; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 4; + break; + case JXRC_FMT_48bppYCC422Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_YUV422; + image->container_nc = 4; + break; + case JXRC_FMT_32bppYCC444Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD8; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 4; + break; + case JXRC_FMT_40bppYCC444Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD10; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 4; + break; + case JXRC_FMT_64bppYCC444Alpha: + image->container_alpha = 1; + image->container_bpc = JXR_BD16; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 4; + break; + case JXRC_FMT_64bppYCC444AlphaFixedPoint: + image->container_alpha = 1; + image->container_bpc = JXR_BD16S; + image->container_color = JXR_OCF_YUV444; + image->container_nc = 4; + break; + default: + /* all Guids listed above*/ + assert(0); + break; + } +} + +void jxr_set_NUM_VER_TILES_MINUS1(jxr_image_t image, unsigned num) +{ + assert( num > 0 && num < 4097 ); + image->tile_columns = num; + + if (num > 1) + jxr_set_TILING_FLAG(image, 1); +} + +void jxr_set_TILE_WIDTH_IN_MB(jxr_image_t image, unsigned* list) +{ + unsigned idx, total_width = 0; + + assert(list != 0); + image->tile_column_width = list; + image->tile_column_position = image->tile_column_width + image->tile_columns; + + if (image->tile_column_width[0] == 0) { + total_width = 0; + for ( idx = 0 ; idx < image->tile_columns - 1 ; idx++ ) { + image->tile_column_width[idx] = (image->extended_width >> 4) / image->tile_columns; + image->tile_column_position[idx] = total_width; + total_width += image->tile_column_width[idx]; + } + image->tile_column_width[image->tile_columns - 1] = (image->extended_width >> 4) - total_width; + image->tile_column_position[image->tile_columns - 1] = total_width; + } +} + +void jxr_set_NUM_HOR_TILES_MINUS1(jxr_image_t image, unsigned num) +{ + assert( num > 0 && num < 4097 ); + image->tile_rows = num; + + if (num > 1) + jxr_set_TILING_FLAG(image, 1); +} + +void jxr_set_TILE_HEIGHT_IN_MB(jxr_image_t image, unsigned* list) +{ + unsigned idx, total_height = 0; + + assert(list != 0); + image->tile_row_height = list; + image->tile_row_position = image->tile_row_height + image->tile_rows; + + if (image->tile_row_height[0] == 0) { + total_height = 0; + for ( idx = 0 ; idx < image->tile_rows - 1 ; idx++ ) { + image->tile_row_height[idx] = (image->extended_height >> 4) / image->tile_rows; + image->tile_row_position[idx] = total_height; + total_height += image->tile_row_height[idx]; + } + image->tile_row_height[image->tile_rows - 1] = (image->extended_height >> 4) - total_height; + image->tile_row_position[image->tile_rows - 1] = total_height; + } +} + +void jxr_set_TILING_FLAG(jxr_image_t image, int flag) +{ + assert(flag >= 0 && flag <= 1); + image->header_flags1 &= ~0x80; + image->header_flags1 |= (flag << 7); + + /* Enable INDEX_TABLE_PRESENT_FLAG */ + if (flag) { + jxr_set_INDEX_TABLE_PRESENT_FLAG(image, 1); + } +} + +void jxr_set_TRIM_FLEXBITS(jxr_image_t image, int trim_flexbits) +{ + assert(trim_flexbits >= 0 && trim_flexbits < 16); + image->trim_flexbits = trim_flexbits; +} + +void jxr_set_OVERLAP_FILTER(jxr_image_t image, int flag) +{ + assert(flag >= 0 && flag <= 3); + image->header_flags1 &= ~0x03; + image->header_flags1 |= flag&0x03; +} + +void jxr_set_DISABLE_TILE_OVERLAP(jxr_image_t image, int disable_tile_overlap) +{ + image->disableTileOverlapFlag = disable_tile_overlap; +} + +void jxr_set_QP_LOSSLESS(jxr_image_t image) +{ + unsigned char q[MAX_CHANNELS]; + int idx; + for (idx = 0 ; idx < MAX_CHANNELS ; idx += 1) + q[idx] = 0; + + jxr_set_QP_INDEPENDENT(image, q); + + if (image->num_channels == 1) { + image->dc_component_mode = JXR_CM_UNIFORM; + image->lp_component_mode = JXR_CM_UNIFORM; + image->hp_component_mode = JXR_CM_UNIFORM; + } else if (image->num_channels == 3) { + image->dc_component_mode = JXR_CM_SEPARATE; + image->lp_component_mode = JXR_CM_SEPARATE; + image->hp_component_mode = JXR_CM_SEPARATE; + } +} + +void jxr_set_QP_INDEPENDENT(jxr_image_t image, unsigned char*quant_per_channel) +{ + /* + * SCALED_FLAG MUST be set false if lossless compressing. + * SCALED_FLAG SHOULD be true otherwise. + * + * So assume that we are setting up for lossless compression + * until we find a QP flag that indicates otherwlse. If that + * happens, turn SCALED_FLAG on. + */ + int idx; + + image->scaled_flag = 0; + + if (image->bands_present != JXR_BP_ALL) + image->scaled_flag = 1; + + if (image->num_channels == 1) { + image->dc_component_mode = JXR_CM_UNIFORM; + image->lp_component_mode = JXR_CM_UNIFORM; + image->hp_component_mode = JXR_CM_UNIFORM; + } else { + image->dc_component_mode = JXR_CM_INDEPENDENT; + image->lp_component_mode = JXR_CM_INDEPENDENT; + image->hp_component_mode = JXR_CM_INDEPENDENT; + } + + image->dc_frame_uniform = 1; + image->lp_frame_uniform = 1; + image->hp_frame_uniform = 1; + image->lp_use_dc_qp = 0; + image->hp_use_lp_qp = 0; + + image->num_lp_qps = 1; + image->num_hp_qps = 1; + + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + if (quant_per_channel[idx] >= 1) + image->scaled_flag = 1; + + image->dc_quant_ch[idx] = quant_per_channel[idx]; + image->lp_quant_ch[idx][0] = quant_per_channel[idx]; + image->hp_quant_ch[idx][0] = quant_per_channel[idx]; + } +} + +void jxr_set_QP_UNIFORM(jxr_image_t image, unsigned char quant) +{ + int idx; + + image->scaled_flag = 0; + + image->dc_component_mode = JXR_CM_UNIFORM; + image->lp_component_mode = JXR_CM_UNIFORM; + image->hp_component_mode = JXR_CM_UNIFORM; + + image->dc_frame_uniform = 1; + image->lp_frame_uniform = 1; + image->hp_frame_uniform = 1; + image->lp_use_dc_qp = 0; + image->hp_use_lp_qp = 0; + + image->num_lp_qps = 1; + image->num_hp_qps = 1; + + if (quant >= 1) + image->scaled_flag = 1; + if (image->bands_present != JXR_BP_ALL) + image->scaled_flag = 1; + + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + image->dc_quant_ch[idx] = quant; + image->lp_quant_ch[idx][0] = quant; + image->hp_quant_ch[idx][0] = quant; + } +} + +void jxr_set_QP_SEPARATE(jxr_image_t image, unsigned char*quant_per_channel) +{ + /* + * SCALED_FLAG MUST be set false if lossless compressing. + * SCALED_FLAG SHOULD be true otherwise. + * + * So assume that we are setting up for lossless compression + * until we find a QP flag that indicates otherwlse. If that + * happens, turn SCALED_FLAG on. + */ + int ch; + + image->scaled_flag = 0; + + if (image->bands_present != JXR_BP_ALL) + image->scaled_flag = 1; + + /* XXXX Only thought out how to handle 1 channel. */ + assert(image->num_channels >= 3); + + image->dc_component_mode = JXR_CM_SEPARATE; + image->lp_component_mode = JXR_CM_SEPARATE; + image->hp_component_mode = JXR_CM_SEPARATE; + + image->dc_frame_uniform = 1; + image->lp_frame_uniform = 1; + image->hp_frame_uniform = 1; + image->lp_use_dc_qp = 0; + image->hp_use_lp_qp = 0; + + if (quant_per_channel[0] >= 1) + image->scaled_flag = 1; + + image->dc_quant_ch[0] = quant_per_channel[0]; + image->lp_quant_ch[0][0] = quant_per_channel[0]; + image->hp_quant_ch[0][0] = quant_per_channel[0]; + + if (quant_per_channel[1] >= 1) + image->scaled_flag = 1; + + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + image->dc_quant_ch[ch] = quant_per_channel[1]; + image->lp_quant_ch[ch][0] = quant_per_channel[1]; + image->hp_quant_ch[ch][0] = quant_per_channel[1]; + } +} + +void jxr_set_QP_DISTRIBUTED(jxr_image_t image, struct jxr_tile_qp*qp) +{ + image->dc_frame_uniform = 0; + image->lp_frame_uniform = 0; + image->hp_frame_uniform = 0; + image->lp_use_dc_qp = 0; + image->hp_use_lp_qp = 0; + + image->tile_quant = qp; +} + +void jxr_set_pixel_format(jxr_image_t image, jxrc_t_pixelFormat pixelFormat) +{ + image->ePixelFormat = pixelFormat; +} + +void jxr_set_SHIFT_BITS(jxr_image_t image, unsigned char shift_bits) +{ + image->shift_bits = shift_bits; +} + +void jxr_set_FLOAT(jxr_image_t image, unsigned char len_mantissa, char exp_bias) +{ + image->len_mantissa = len_mantissa; + image->exp_bias = exp_bias; +} + +/* +* $Log: api.c,v $ +* Revision 1.20 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.19 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.18 2008/03/21 18:05:53 steve +* Proper CMYK formatting on input. +* +* Revision 1.17 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.16 2008/03/05 04:04:30 steve +* Clarify constraints on USE_DC_QP in image plane header. +* +* Revision 1.15 2008/03/05 01:27:15 steve +* QP_UNIFORM may use USE_DC_LP optionally. +* +* Revision 1.14 2008/03/05 00:31:17 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.13 2008/03/04 23:01:28 steve +* Cleanup QP API in preparation for distributed QP +* +* Revision 1.12 2008/03/02 19:56:27 steve +* Infrastructure to read write BD16 files. +* +* Revision 1.11 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.10 2008/02/01 22:49:52 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.9 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.8 2008/01/07 16:19:10 steve +* Properly configure TRIM_FLEXBITS_FLAG bit. +* +* Revision 1.7 2008/01/06 01:29:28 steve +* Add support for TRIM_FLEXBITS in compression. +* +* Revision 1.6 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.5 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.4 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.3 2007/11/08 02:52:32 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.2 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/app_resource.h b/jpegxr/app_resource.h new file mode 100644 index 000000000..eac8ab69b --- /dev/null +++ b/jpegxr/app_resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by APP.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/jpegxr/cr_parse.c b/jpegxr/cr_parse.c new file mode 100644 index 000000000..563303a52 --- /dev/null +++ b/jpegxr/cr_parse.c @@ -0,0 +1,1423 @@ + + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: cr_parse.c,v 1.9 2008/03/21 21:23:14 steve Exp $") +#else +#ident "$Id: cr_parse.c,v 1.9 2008/03/21 21:23:14 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <string.h> +# include <stdlib.h> +# include <assert.h> + +static int read_ifd(jxr_container_t container, FILE*fd, int image_number, uint32_t*ifd_next); + +jxr_container_t jxr_create_container(void) +{ + jxr_container_t res = (jxr_container_t) + calloc(1, sizeof (struct jxr_container)); + return res; +} + +void jxr_destroy_container(jxr_container_t container) +{ + if(container == NULL) + return; + free(container); +} + +int jxr_read_image_container(jxr_container_t container, FILE*fd) +{ + unsigned char buf[4]; + size_t rc; + uint32_t ifd_off; + + rc = fread(buf, 1, 4, fd); + if (rc < 4) + return JXR_EC_BADMAGIC; + + if (buf[0] != 0x49) return JXR_EC_BADMAGIC; + if (buf[1] != 0x49) return JXR_EC_BADMAGIC; + if (buf[2] != 0xbc) return JXR_EC_BADMAGIC; + if (buf[3] > 0x01) return JXR_EC_BADMAGIC; /* Version. */ + + rc = fread(buf, 1, 4, fd); + if (rc != 4) return JXR_EC_IO; + + ifd_off = (buf[3] << 24) + (buf[2]<<16) + (buf[1]<<8) + (buf[0]<<0); + container->image_count = 0; + + while (ifd_off != 0) { + uint32_t ifd_next; + + container->image_count += 1; + container->table_cnt = (unsigned*)realloc(container->table_cnt, + container->image_count * sizeof(unsigned)); + container->table = (struct ifd_table**) realloc(container->table, + container->image_count * sizeof(struct ifd_table*)); + + if (ifd_off & 0x1) return JXR_EC_IO; + rc = fseek(fd, ifd_off, SEEK_SET); + rc = read_ifd(container, fd, container->image_count-1, &ifd_next); + if (rc < 0) return (int) rc; + + ifd_off = ifd_next; + } + + return 0; +} + +int jxrc_image_count(jxr_container_t container) +{ + return container->image_count; +} + +int jxrc_document_name(jxr_container_t container, int image, char ** string) +{ + + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x010d) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x010d) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_image_description(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x010e) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x010e) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_equipment_make(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x010f) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x010f) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_equipment_model(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x0110) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x0110) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_page_name(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x011d) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x011d) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_page_number(jxr_container_t container, int image, unsigned short * value) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x0129) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x0129) return -1; + assert(ifd[idx].cnt == 2); + assert(ifd[idx].type == 3); + + value[0] = ifd[idx].value_.v_short[0]; + value[1] = ifd[idx].value_.v_short[1]; + + return 0; +} + +int jxrc_software_name_version(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x0131) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x0131) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_date_time(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned i; + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x0132) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x0132) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + assert(ifd[idx].cnt == 20); + + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + + assert(string[0][4] == 0x3a && string[0][7] == 0x3a && string[0][13] == 0x3a && string[0][16] == 0x3a); + assert(string[0][10] == 0x20); + assert((string[0][5] == '0' && (string[0][6] >= '1' && string[0][6] <= '9')) || (string[0][5] == '1' && (string[0][6] >= '0' && string[0][6] <= '2'))); + assert((string[0][8] == '0' && (string[0][9] >= '1' && string[0][9] <= '9')) || ((string[0][8] == '1' || string[0][8] == '2') && (string[0][9] >= '0' && string[0][9] <= '9')) || (string[0][8] == '3' && (string[0][9] >= '0' && string[0][9] <= '1'))); + assert(((string[0][11] == '0' || string[0][11] == '1') && (string[0][12] >= '0' && string[0][12] <= '9')) || (string[0][11] == '2' && (string[0][12] >= '0' && string[0][12] <= '3'))); + assert(string[0][14] >= '0' && string[0][14] < '6'); + assert(string[0][15] >= '0' && string[0][15] <= '9'); + assert(string[0][17] >= '0' && string[0][17] < '6'); + assert(string[0][18] >= '0' && string[0][18] <= '9'); + + return 0; +} + +int jxrc_artist_name(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x013b) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x013b) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_host_computer(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x013c) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x013c) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +int jxrc_copyright_notice(jxr_container_t container, int image, char ** string) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0x8298) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0x8298) return -1; + assert(ifd[idx].type == 2); + + assert(string[0] == 0); + string[0] = (char *) malloc(ifd[idx].cnt * sizeof(char)); + assert(string[0] != 0); + + if (ifd[idx].cnt <= 4) { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.v_sbyte[i]; + } + else { + unsigned i; + for (i = 0 ; i < ifd[idx].cnt ; i++) + string[0][i] = ifd[idx].value_.p_sbyte[i]; + } + + return 0; +} + +unsigned short jxrc_color_space(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned short value; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xa001) + break; + } + + if (idx >= ifd_cnt) return 0; + if (ifd[idx].tag != 0xa001) return 0; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 3); + + value = ifd[idx].value_.v_short[0]; + if (value != 0x0001) + value = 0xffff; + if (value == 0x0001) { + switch(jxrc_image_pixelformat(container, image)) { + case JXRC_FMT_24bppRGB: + case JXRC_FMT_24bppBGR: + case JXRC_FMT_32bppBGR: + case JXRC_FMT_48bppRGB: + case JXRC_FMT_32bppBGRA: + case JXRC_FMT_64bppRGBA: + case JXRC_FMT_32bppPBGRA: + case JXRC_FMT_64bppPRGBA: + case JXRC_FMT_32bppCMYK: + case JXRC_FMT_40bppCMYKAlpha: + case JXRC_FMT_64bppCMYK: + case JXRC_FMT_80bppCMYKAlpha: + case JXRC_FMT_24bpp3Channels: + case JXRC_FMT_32bpp4Channels: + case JXRC_FMT_40bpp5Channels: + case JXRC_FMT_48bpp6Channels: + case JXRC_FMT_56bpp7Channels: + case JXRC_FMT_64bpp8Channels: + case JXRC_FMT_32bpp3ChannelsAlpha: + case JXRC_FMT_40bpp4ChannelsAlpha: + case JXRC_FMT_48bpp5ChannelsAlpha: + case JXRC_FMT_56bpp6ChannelsAlpha: + case JXRC_FMT_64bpp7ChannelsAlpha: + case JXRC_FMT_72bpp8ChannelsAlpha: + case JXRC_FMT_48bpp3Channels: + case JXRC_FMT_64bpp4Channels: + case JXRC_FMT_80bpp5Channels: + case JXRC_FMT_96bpp6Channels: + case JXRC_FMT_112bpp7Channels: + case JXRC_FMT_128bpp8Channels: + case JXRC_FMT_64bpp3ChannelsAlpha: + case JXRC_FMT_80bpp4ChannelsAlpha: + case JXRC_FMT_96bpp5ChannelsAlpha: + case JXRC_FMT_112bpp6ChannelsAlpha: + case JXRC_FMT_128bpp7ChannelsAlpha: + case JXRC_FMT_144bpp8ChannelsAlpha: + case JXRC_FMT_8bppGray: + case JXRC_FMT_16bppGray: + case JXRC_FMT_BlackWhite: + case JXRC_FMT_16bppBGR555: + case JXRC_FMT_16bppBGR565: + case JXRC_FMT_32bppBGR101010: + case JXRC_FMT_32bppCMYKDIRECT: + case JXRC_FMT_64bppCMYKDIRECT: + case JXRC_FMT_40bppCMYKDIRECTAlpha: + case JXRC_FMT_80bppCMYKDIRECTAlpha: + case JXRC_FMT_12bppYCC420: + case JXRC_FMT_16bppYCC422: + case JXRC_FMT_20bppYCC422: + case JXRC_FMT_32bppYCC422: + case JXRC_FMT_24bppYCC444: + case JXRC_FMT_30bppYCC444: + case JXRC_FMT_48bppYCC444: + case JXRC_FMT_20bppYCC420Alpha: + case JXRC_FMT_24bppYCC422Alpha: + case JXRC_FMT_30bppYCC422Alpha: + case JXRC_FMT_48bppYCC422Alpha: + case JXRC_FMT_32bppYCC444Alpha: + case JXRC_FMT_40bppYCC444Alpha: + case JXRC_FMT_64bppYCC444Alpha: + break; + default: + /* Color space tag can equal 1 only if format is UINT */ + assert(0); + break; + } + } + return value; +} + +jxrc_t_pixelFormat jxrc_image_pixelformat(jxr_container_t container, int imagenum) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + unsigned char guid[16]; + int i; + assert(imagenum < container->image_count); + + ifd_cnt = container->table_cnt[imagenum]; + ifd = container->table[imagenum]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc01) + break; + } + + assert(idx < ifd_cnt); + assert(ifd[idx].tag == 0xbc01); + assert(ifd[idx].cnt == 16); + memcpy(guid, ifd[idx].value_.p_byte, 16); + for(i=0; i< NUM_GUIDS; i++) + { + if(isEqualGUID(guid, jxr_guids[i])) + { + break; + } + } + if(i==NUM_GUIDS) + assert(0); + return (jxrc_t_pixelFormat)i; + +} + +unsigned long jxrc_spatial_xfrm_primary(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long spatial_xfrm; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc02) + break; + } + + if (idx >= ifd_cnt) return 0; + if (ifd[idx].tag != 0xbc02) return 0; + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + spatial_xfrm = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + spatial_xfrm = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + spatial_xfrm = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + if (spatial_xfrm > 7 || spatial_xfrm < 0) + spatial_xfrm = 0; + return spatial_xfrm; +} + +unsigned long jxrc_image_type(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long image_type; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc04) + break; + } + + if (idx >= ifd_cnt) return 0; + if (ifd[idx].tag != 0xbc04) return 0; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 4); + + image_type = ifd[idx].value_.v_long; + image_type &= 0x00000003; + return image_type; +} + +int jxrc_ptm_color_info(jxr_container_t container, int image, unsigned char * buf) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + uint32_t i; + + assert(image < container->image_count); + assert(buf); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc05) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0xbc05) return -1; + assert(ifd[idx].cnt == 4); + assert(ifd[idx].type == 1); + + for (i = 0 ; i < 4 ; i += 1) + buf[i] = ifd[idx].value_.v_byte[i]; + + return 0; +} + +int jxrc_profile_level_container(jxr_container_t container, int image, unsigned char * profile, unsigned char * level) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned char * data; + uint32_t count_remaining; + uint8_t last, last_flag; + + assert(image < container->image_count); + assert(profile); + assert(level); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + data = 0; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc06) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0xbc06) return -1; + assert(ifd[idx].type == 1); + assert(ifd[idx].cnt > 3); + + if (ifd[idx].cnt <= 4) { + data = (unsigned char *) (ifd[idx].value_.v_sbyte); + } + else { + data = (unsigned char *) (ifd[idx].value_.p_sbyte); + } + + count_remaining = ifd[idx].cnt; + for (last = 0 ; last == 0 ; last = last_flag) { + profile[0] = data[0]; + level[0] = data[1]; + last_flag = (data[3] & 0x1); + data += 4; + count_remaining -= 4; + assert(count_remaining == 0 || count_remaining > 3); + } + + return 0; +} + +unsigned long jxrc_image_width(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long width; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc80) + break; + } + + assert(idx < ifd_cnt); + assert(ifd[idx].tag == 0xbc80); + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + width = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + width = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + width = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return width; +} + +unsigned long jxrc_image_height(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long height; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc81) + break; + } + + assert(idx < ifd_cnt); + assert(ifd[idx].tag == 0xbc81); + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + height = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + height = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + height = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return height; +} + +float jxrc_width_resolution(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + float width_resolution; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc82) + break; + } + + if (idx >= ifd_cnt) return 96.0; + if (ifd[idx].tag != 0xbc82) return 96.0; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 11); + + width_resolution = ifd[idx].value_.v_float; + if (width_resolution == 0.0) + width_resolution = 96.0; + return width_resolution; +} + +float jxrc_height_resolution(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + float height_resolution; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbc83) + break; + } + + if (idx >= ifd_cnt) return 96.0; + if (ifd[idx].tag != 0xbc83) return 96.0; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 11); + + height_resolution = ifd[idx].value_.v_float; + if (height_resolution == 0.0) + height_resolution = 96.0; + return height_resolution; +} + +unsigned long jxrc_image_offset(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long pos; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbcc0) + break; + } + + assert(idx < ifd_cnt); + assert(ifd[idx].tag == 0xbcc0); + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + pos = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + pos = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + pos = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return pos; +} + +unsigned long jxrc_image_bytecount(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long pos; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbcc1) + break; + } + + assert(idx < ifd_cnt); + assert(ifd[idx].tag == 0xbcc1); + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + pos = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + pos = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + pos = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return pos; +} + +unsigned long jxrc_alpha_offset(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long pos; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xBCC2) + break; + } + + if (idx >= ifd_cnt) return 0; /* No alpha coded image */ + if (ifd[idx].tag != 0xbcc2) return 0; + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + pos = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + pos = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + pos = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return pos; +} + +unsigned long jxrc_alpha_bytecount(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned long pos; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbcc3) + break; + } + + + if (idx >= ifd_cnt) return 0; /* No alpha coded image */ + if (ifd[idx].tag != 0xbcc3) return 0; + assert(ifd[idx].cnt == 1); + + switch (ifd[idx].type) { + case 4: /* ULONG */ + pos = (unsigned long) ifd[idx].value_.v_long; + break; + case 3: /* USHORT */ + pos = (unsigned long) ifd[idx].value_.v_short[0]; + break; + case 1: /* BYTE */ + pos = (unsigned long) ifd[idx].value_.v_byte[0]; + break; + default: + assert(0); + break; + } + + return pos; +} + +unsigned char jxrc_image_band_presence(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbcc4) + break; + } + + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0xbcc4) return -1; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 1); + + return ifd[idx].value_.v_byte[0]; +} + +unsigned char jxrc_alpha_band_presence(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xbcc5) + break; + } + + + if (idx >= ifd_cnt) return -1; /* tag is not present */ + if (ifd[idx].tag != 0xbcc5) return -1; + assert(ifd[idx].cnt == 1); + assert(ifd[idx].type == 1); + + return ifd[idx].value_.v_byte[0]; +} + +int jxrc_padding_data(jxr_container_t container, int image) +{ + unsigned ifd_cnt; + struct ifd_table*ifd; + unsigned idx; + unsigned char * data; + unsigned i; + + assert(image < container->image_count); + + ifd_cnt = container->table_cnt[image]; + ifd = container->table[image]; + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) { + if (ifd[idx].tag == 0xea1c) + break; + } + + if (idx >= ifd_cnt) return -1; + if (ifd[idx].tag != 0xea1c) return -1; + assert(ifd[idx].type == 7); + assert(ifd[idx].cnt > 1); + + if (ifd[idx].cnt <= 4) + data = (unsigned char *) ifd[idx].value_.v_sbyte; + else + data = (unsigned char *) ifd[idx].value_.p_sbyte; + + assert(data[0] == 0x1c); + assert(data[1] == 0xea); + + return 0; +} + +uint16_t bytes2_to_off(uint8_t*bp) +{ + return (bp[1]<<8) + (bp[0]); +} + +uint32_t bytes4_to_off(uint8_t*bp) +{ + return (bp[3]<<24) + (bp[2]<<16) + (bp[1]<<8) + (bp[0]); +} + +static int read_ifd(jxr_container_t container, FILE*fd, int image_number, uint32_t*ifd_next) +{ + unsigned char buf[16]; + size_t rc; + int idx; + int ifd_tag_prev = 0; + int alpha_tag_check = 0; + uint32_t ifd_off; + struct ifd_table*cur; + uint16_t entry_count; + + *ifd_next = 0; + + rc = fread(buf, 1, 2, fd); + if (rc != 2) return -1; + + entry_count = (buf[1]<<8) + (buf[0]<<0); + container->table_cnt[image_number] = entry_count; + + cur = (struct ifd_table*)calloc(entry_count, sizeof(struct ifd_table)); + assert(cur != 0); + + container->table[image_number] = cur; + + /* First read in the entire directory. Don't interpret the + types yet, just save the values as v_bytes. We will go + through the types later and interpret the values more + precisely. */ + for (idx = 0 ; idx < entry_count ; idx += 1) { + uint16_t ifd_tag; + uint16_t ifd_type; + uint32_t ifd_cnt; + + rc = fread(buf, 1, 12, fd); + assert(rc == 12); + + ifd_tag = (buf[1]<<8) + (buf[0]<<0); + if (ifd_tag == 0xbcc2) + alpha_tag_check += 1; + if (ifd_tag == 0xbcc3) + alpha_tag_check += 2; + if (ifd_tag == 0xbcc5) + alpha_tag_check += 4; + ifd_type = (buf[3]<<8) + (buf[2]<<0); + if (ifd_type == 7) + assert (ifd_tag == 0x8773 || ifd_tag == 0xea1c); + ifd_cnt = (buf[7]<<24) + (buf[6]<<16) + (buf[5]<<8) + buf[4]; + + assert(ifd_tag > ifd_tag_prev); + ifd_tag_prev = ifd_tag; + + cur[idx].tag = ifd_tag; + cur[idx].type = ifd_type; + cur[idx].cnt = ifd_cnt; + + cur[idx].value_.v_byte[0] = buf[8]; + cur[idx].value_.v_byte[1] = buf[9]; + cur[idx].value_.v_byte[2] = buf[10]; + cur[idx].value_.v_byte[3] = buf[11]; + } + /* verify alpha ifd tags appear only in allowed combinations */ + assert(alpha_tag_check == 0 || alpha_tag_check == 3 || alpha_tag_check == 7); + + rc = fread(buf, 1, 4, fd); + assert(rc == 4); + + /* Now interpret the tag types/values for easy access later. */ + for (idx = 0 ; idx < entry_count ; idx += 1) { + switch (cur[idx].type) { + + case 1: /* BYTE */ + case 2: /* UTF8 */ + case 6: /* SBYTE */ + case 7: /* UNDEFINED */ + DEBUG("Container %d: tag 0x%04x BYTE:", image_number, cur[idx].tag); + if (cur[idx].cnt > 4) { + ifd_off = bytes4_to_off(cur[idx].value_.v_byte); + assert((ifd_off & 1) == 0); + fseek(fd, ifd_off, SEEK_SET); + cur[idx].value_.p_byte = (uint8_t*)malloc(cur[idx].cnt); + fread(cur[idx].value_.p_byte, 1, cur[idx].cnt, fd); +#if defined(DETAILED_DEBUG) + { + int bb; + for (bb = 0 ; bb < cur[idx].cnt ; bb += 1) + DEBUG("%02x", cur[idx].value_.p_byte[bb]); + } +#endif + if (cur[idx].type == 2) { + int cc; + for (cc = 1 ; cc < cur[idx].cnt ; cc += 1) + assert((cur[idx].value_.p_byte[cc - 1] != 0) || (cur[idx].value_.p_byte[cc] != 0)); + } + } + else { + if (cur[idx].type == 2) { + int cc; + for (cc = 1 ; cc < cur[idx].cnt ; cc += 1) + assert((cur[idx].value_.v_byte[cc - 1] != 0) || (cur[idx].value_.v_byte[cc] != 0)); + } + } + /* No action required to access individual bytes */ + DEBUG("\n"); + break; + + case 3: /* USHORT */ + case 8: /* SSHORT */ + if (cur[idx].cnt <= 2) { + cur[idx].value_.v_short[0] = bytes2_to_off(cur[idx].value_.v_byte + 0); + cur[idx].value_.v_short[1] = bytes2_to_off(cur[idx].value_.v_byte + 2); + DEBUG("Container %d: tag 0x%04x SHORT %u SHORT %u\n", image_number, + cur[idx].tag, cur[idx].value_.v_short[0], cur[idx].value_.v_short[1]); + } else { + uint16_t cdx; + + ifd_off = bytes4_to_off(cur[idx].value_.v_byte); + assert((ifd_off & 1) == 0); + fseek(fd, ifd_off, SEEK_SET); + cur[idx].value_.p_short = (uint16_t*) calloc(cur[idx].cnt, sizeof(uint16_t)); + + DEBUG("Container %d: tag 0x%04x SHORT\n", image_number, + cur[idx].tag); + for (cdx = 0 ; cdx < cur[idx].cnt ; cdx += 1) { + uint8_t buf[2]; + fread(buf, 1, 2, fd); + cur[idx].value_.p_short[cdx] = bytes2_to_off(buf); + DEBUG(" %u", cur[idx].value_.p_short[cdx]); + } + DEBUG("\n"); + } + break; + + case 4: /* ULONG */ + case 9: /* SLONG */ + case 11: /* FLOAT */ + if (cur[idx].cnt == 1) { + cur[idx].value_.v_long = bytes4_to_off(cur[idx].value_.v_byte); + DEBUG("Container %d: tag 0x%04x LONG %u\n", image_number, + cur[idx].tag, cur[idx].value_.v_long); + } else { + uint32_t cdx; + + ifd_off = bytes4_to_off(cur[idx].value_.v_byte); + assert((ifd_off & 1) == 0); + fseek(fd, ifd_off, SEEK_SET); + cur[idx].value_.p_long = (uint32_t*) calloc(cur[idx].cnt, sizeof(uint32_t)); + + DEBUG("Container %d: tag 0x%04x LONG\n", image_number, + cur[idx].tag); + for (cdx = 0 ; cdx < cur[idx].cnt ; cdx += 1) { + uint8_t buf[4]; + fread(buf, 1, 4, fd); + cur[idx].value_.p_long[cdx] = bytes4_to_off(buf); + DEBUG(" %u", cur[idx].value_.p_long[cdx]); + } + DEBUG("\n"); + } + break; + + case 5: /* URATIONAL */ + case 10: /* SRATIONAL */ + case 12: /* DOUBLE */ + { + uint64_t cdx; + + /* Always offset */ + ifd_off = bytes4_to_off(cur[idx].value_.v_byte); + assert((ifd_off & 1) == 0); + fseek(fd, ifd_off, SEEK_SET); + cur[idx].value_.p_rational = (uint64_t*) calloc(cur[idx].cnt, sizeof(uint64_t)); + + DEBUG("Container %d: tag 0x%04x LONG\n", image_number, + cur[idx].tag); + for (cdx = 0 ; cdx < cur[idx].cnt ; cdx += 1) { + uint8_t buf[4]; + fread(buf, 1, 4, fd); + cur[idx].value_.p_long[2 * cdx + 0] = bytes4_to_off(buf); + fread(buf, 1, 4, fd); + cur[idx].value_.p_long[2 * cdx + 1] = bytes4_to_off(buf); + DEBUG(" %u", cur[idx].value_.p_rational[cdx]); + } + DEBUG("\n"); + } + break; + + default: + DEBUG("Container %d: tag 0x%04x type=%u\n", image_number, cur[idx].tag, cur[idx].type); + break; + } + } + + /* Tell the caller about the next ifd. */ + *ifd_next = (buf[3] << 24) + (buf[2]<<16) + (buf[1]<<8) + (buf[0]<<0); + + return 0; +} + + +/* +* $Log: cr_parse.c,v $ +* Revision 1.11 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.10 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.9 2008/03/21 21:23:14 steve +* Some debug dump of the container. +* +* Revision 1.8 2008/03/05 19:32:02 gus +* *** empty log message *** +* +* Revision 1.7 2008/03/01 02:46:08 steve +* Add support for JXR container. +* +* Revision 1.6 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.5 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.4 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.3 2007/11/07 18:11:35 steve +* Accept magic number version 0 +* +* Revision 1.2 2007/07/30 23:09:57 steve +* Interleave FLEXBITS within HP block. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/cw_emit.c b/jpegxr/cw_emit.c new file mode 100644 index 000000000..cda26feed --- /dev/null +++ b/jpegxr/cw_emit.c @@ -0,0 +1,677 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: cw_emit.c,v 1.2 2008/03/02 18:35:27 steve Exp $") +#else +#ident "$Id: cw_emit.c,v 1.2 2008/03/02 18:35:27 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <string.h> +# include <assert.h> + +int jxrc_start_file(jxr_container_t cp, FILE*fd) +{ + const unsigned char head_bytes[8] = {0x49, 0x49, 0xbc, 0x01, + 0x08, 0x00, 0x00, 0x00 }; + + assert(cp->fd == 0); + + /* initializations */ + cp->separate_alpha_image_plane = 0; + cp->image_count_mark = 0; + cp->alpha_count_mark = 0; + cp->alpha_offset_mark = 0; + cp->alpha_band = 0; + + cp->fd = fd; + cp->file_mark = ftell(cp->fd); + + fwrite(head_bytes, 1, 8, cp->fd); + return 0; +} + +int jxrc_begin_ifd_entry(jxr_container_t cp) +{ + assert(cp->image_count == 0); + cp->image_count = 1; + return 0; +} + + +int jxrc_set_pixel_format(jxr_container_t cp, jxrc_t_pixelFormat fmt) +{ + memcpy(cp->pixel_format, jxr_guids[fmt], 16); + + return 0; +} + +jxrc_t_pixelFormat jxrc_get_pixel_format(jxr_container_t cp) +{ + unsigned char guid[16]; + int i; + + for(i=0; i< NUM_GUIDS; i++) + { + if(isEqualGUID(cp->pixel_format, jxr_guids[i])) + { + break; + } + } + if(i==NUM_GUIDS) + assert(0); + return (jxrc_t_pixelFormat)i; + +} + + +int jxrc_set_image_shape(jxr_container_t cp, unsigned wid, unsigned hei) +{ + cp->wid = wid; + cp->hei = hei; + return 0; +} + +int jxrc_set_image_band_presence(jxr_container_t cp, unsigned bands) +{ + cp->image_band = (uint8_t) bands; + return 0; +} + +/* +This will induce the encoder to write as many of the +IFD tags of table A.4 (the listing of IFD tags) as it can +Off by default. +#define WRITE_OPTIONAL_IFD_TAGS +*/ + +int jxrc_set_separate_alpha_image_plane(jxr_container_t cp, unsigned int alpha_present) +{ + cp->separate_alpha_image_plane = alpha_present; + return 0; +} + +static void emit_ifd(jxr_container_t cp) +{ + unsigned long ifd_mark; + int idx; + struct ifd_table ifd[64]; + unsigned char buf[1024]; + + int num_ifd = 0; + int num_buf = 0; + unsigned long ifd_len; + unsigned char scr[12]; + +#ifdef WRITE_OPTIONAL_IFD_TAGS + int ifd_cnt; + char * input_string; + + /* various sample strings used to test storage */ + char document_name[] = {"JPEG XR image created by JPEG XR sample encoder."}; + char image_description[] = {"The core codestream begins at WMPHOTO"}; + char equipment_make[] = {"???"}; + char equipment_model[] = {"JXR 0X1"}; + char page_name[]={"Test page name"}; + unsigned short page_number[] = {1,2}; + char software_name_version[]={"JPEG XR reference software v1.6"}; + char date_time[]={"2009:04:01 12:34:56"}; + char artist_name[]={"JPEG Committee"}; + char host_computer[]={"JXR"}; + char copyright_notice[]={"©JPEG Committee"}; + unsigned long spatial_xfrm = 0; + unsigned char profile_idc = 111; + unsigned char level_idc = 255; + float width_res = 96.0; + float height_res = 96.0; + + assert(cp->image_count > 0); + if (cp->image_count > 1){ + assert(0); + ifd_mark = 0; + } else { + ifd_mark = 8; + } + + input_string = document_name; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x010d; /* DOCUMENT_NAME */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = image_description; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x010e; /* IMAGE_DESCRIPTION */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = equipment_make; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x010f; /* EQUIPMENT_MAKE */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = equipment_model; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x0110; /* EQUIPMENT_MODEL */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = page_name; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x011d; /* PAGE_NAME */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + ifd[num_ifd].tag = 0x0129; /* PAGE_NUMBER */ + ifd[num_ifd].type = 3; /* USHORT */ + ifd[num_ifd].cnt = 2; + ifd[num_ifd].value_.v_short[0] = page_number[0]; + ifd[num_ifd].value_.v_short[1] = page_number[1]; + num_ifd += 1; + + input_string = software_name_version; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x0131; /* SOFTWARE_NAME_VERSION */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = date_time; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x0132; /* DATE_TIME */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = artist_name; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x013b; /* ARTIST_NAME */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = host_computer; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x013c; /* HOST_COMPUTER */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + input_string = copyright_notice; + ifd_cnt = strlen(input_string) + 1; + ifd[num_ifd].tag = 0x8298; /* COPYRIGHT_NOTICE */ + ifd[num_ifd].type = 2; /* UTF8 */ + ifd[num_ifd].cnt = ifd_cnt; + if (ifd_cnt > 4) + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + else + memcpy(ifd[num_ifd].value_.v_sbyte, input_string, ifd_cnt); + + for (idx = 0 ; idx < ifd_cnt ; idx += 1) + buf[num_buf++] = input_string[idx]; + if (num_buf & 0x1) + buf[num_buf++] = (unsigned char) 0; + num_ifd += 1; + + ifd[num_ifd].tag = 0xa001; /* COLOR_SPACE */ + ifd[num_ifd].type = 3; /* USHORT */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_short[0] = 0xffff; /* Just use this value for testing */ + ifd[num_ifd].value_.v_short[1] = 0; + num_ifd += 1; +#endif + + ifd[num_ifd].tag = 0xbc01; /* PIXEL_FORMAT */ + ifd[num_ifd].type = 1; /* BYTE */ + ifd[num_ifd].cnt = 16; + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + + for (idx = 0 ; idx < 16 ; idx += 1) + buf[num_buf++] = cp->pixel_format[idx]; + num_ifd += 1; + +#ifdef WRITE_OPTIONAL_IFD_TAGS + ifd[num_ifd].tag = 0xbc02; /* SPATIAL_XFRM_PRIMARY */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = spatial_xfrm; + num_ifd += 1; + + /* IMAGE_TYPE should only be present when multiple images are in the image */ + /* Fix this condition if encoder can handle multiple images */ + if (0){ + ifd[num_ifd].tag = 0xbc04; /* IMAGE_TYPE */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = 0; + num_ifd += 1; + } + + ifd[num_ifd].tag = 0xbc05; /* PTM_COLOR_INFO() */ + ifd[num_ifd].type = 1; /* BYTE */ + ifd[num_ifd].cnt = 4; + ifd[num_ifd].value_.v_byte[0] = 2; /* default to unspecified */ + ifd[num_ifd].value_.v_byte[1] = 2; /* default to unspecified */ + ifd[num_ifd].value_.v_byte[2] = 2; /* default to no rotation */ + ifd[num_ifd].value_.v_byte[3] = 0; /* default to no rotation */ + num_ifd += 1; + + ifd[num_ifd].tag = 0xbc06; /* PROFILE_LEVEL_CONTAINER() */ + ifd[num_ifd].type = 1; /* BYTE */ + ifd[num_ifd].cnt = 4; + ifd[num_ifd].value_.v_byte[0] = profile_idc; + ifd[num_ifd].value_.v_byte[1] = level_idc; + ifd[num_ifd].value_.v_byte[2] = 0; + ifd[num_ifd].value_.v_byte[3] = 1; + num_ifd += 1; + +#endif + + ifd[num_ifd].tag = 0xbc80; /* IMAGE_WIDTH */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = cp->wid; + + num_ifd += 1; + + ifd[num_ifd].tag = 0xbc81; /* IMAGE_HEIGHT */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = cp->hei; + + num_ifd += 1; + +#ifdef WRITE_OPTIONAL_IFD_TAGS + ifd[num_ifd].tag = 0xbc82; /* WIDTH_RESOLUTION */ + ifd[num_ifd].type = 11; /* FLOAT */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_float = width_res; + num_ifd += 1; + + ifd[num_ifd].tag = 0xbc83; /* HEIGHT_RESOLUTION */ + ifd[num_ifd].type = 11; /* FLOAT */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_float = height_res; + num_ifd += 1; +#endif + + ifd[num_ifd].tag = 0xbcc0; /* IMAGE_OFFSET */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = 0; + + num_ifd += 1; + + ifd[num_ifd].tag = 0xbcc1; /* IMAGE_COUNT */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = 0; + + num_ifd += 1; + + if (cp->separate_alpha_image_plane) { + ifd[num_ifd].tag = 0xbcc2; /* ALPHA_OFFSET */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = 0; + + num_ifd += 1; + + ifd[num_ifd].tag = 0xbcc3; /* ALPHA_COUNT */ + ifd[num_ifd].type = 4; /* ULONG */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_long = 0; + + num_ifd += 1; + } + +#ifdef WRITE_OPTIONAL_IFD_TAGS + ifd[num_ifd].tag = 0xbcc4; /* IMAGE_BAND_PRESENCE */ + ifd[num_ifd].type = 1; /* BYTE */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_byte[0] = cp->image_band; + num_ifd += 1; + + if (cp->separate_alpha_image_plane) { + ifd[num_ifd].tag = 0xbcc5; /* ALPHA_BAND_PRESENCE */ + ifd[num_ifd].type = 1; /* BYTE */ + ifd[num_ifd].cnt = 1; + ifd[num_ifd].value_.v_byte[0] = cp->alpha_band; + num_ifd += 1; + } + + ifd[num_ifd].tag = 0xea1c; /* PADDING_DATA */ + ifd[num_ifd].type = 7; /* UNDEFINED */ + ifd[num_ifd].cnt = 21; /* Value set arbitrarily to tests this IFD entry */ + ifd[num_ifd].value_.v_long = ifd_mark + num_buf; + + assert(ifd[num_ifd].cnt > 1); + + buf[num_buf++] = 0x1c; + buf[num_buf++] = 0xea; + for (idx = 2 ; idx < ifd[num_ifd].cnt ; idx += 1) + buf[num_buf++] = 0; + num_ifd += 1; +#endif + + ifd_len = 2 + 12*num_ifd + 4; /* NUM_ENTRIES + 12 bytes per entry + ZERO_OR_NEXT_IFD_OFFSET */ + + cp->image_offset_mark = ifd_mark + ifd_len + num_buf; + + for (idx = 0 ; idx < num_ifd ; idx += 1) { + switch (ifd[idx].type) { + case 1: /* BYTE */ + case 2: /* UTF8 */ + case 6: /* SBYTE */ + case 7: /* UNDEFINED */ + if (ifd[idx].cnt > 4) + ifd[idx].value_.v_long += ifd_len; + break; + case 3: /* USHORT */ + case 8: /* SSHORT */ + if (ifd[idx].cnt > 2) + ifd[idx].value_.v_long += ifd_len; + break; + case 4: /* ULONG */ + case 9: /* SLONG */ + case 11: /* FLOAT */ + if (ifd[idx].cnt > 1) + ifd[idx].value_.v_long += ifd_len; + /* If we find the IMAGE_OFFSET, we know its value + now. Write it into v_long */ + if (ifd[idx].tag == 0xbcc0) /* IMAGE_OFFSET */ + ifd[idx].value_.v_long = cp->image_offset_mark; + /* For the following markers, record the locations to be filled in later */ + if (ifd[idx].tag == 0xbcc1) /* IMAGE_COUNT */ + cp->image_count_mark = ifd_mark + 2 + 12*idx + 8; + if (ifd[idx].tag == 0xbcc2) /* ALPHA_OFFSET */ + cp->alpha_offset_mark = ifd_mark + 2 + 12*idx + 8; + if (ifd[idx].tag == 0xbcc3) /* ALPHA_COUNT */ + cp->alpha_count_mark = ifd_mark + 2 + 12*idx + 8; + + break; + case 5: /* URATIONAL */ + case 10: /* SRATIONAL */ + case 12: /* DOUBLE */ + ifd[idx].value_.v_long += ifd_len; + break; + default: /* RESERVED */ + assert(0); + } + } + + scr[0] = (num_ifd>>0) & 0xff; + scr[1] = (num_ifd>>8) & 0xff; + fwrite(scr, 1, 2, cp->fd); + for (idx = 0 ; idx < num_ifd ; idx += 1) { + scr[0] = (ifd[idx].tag >> 0) & 0xff; + scr[1] = (ifd[idx].tag >> 8) & 0xff; + scr[2] = (ifd[idx].type>> 0) & 0xff; + scr[3] = (ifd[idx].type>> 8) & 0xff; + scr[4] = (ifd[idx].cnt >> 0) & 0xff; + scr[5] = (ifd[idx].cnt >> 8) & 0xff; + scr[6] = (ifd[idx].cnt >>16) & 0xff; + scr[7] = (ifd[idx].cnt >>24) & 0xff; + + switch (ifd[idx].type) { + case 1: /* BYTE */ + case 2: /* UTF8 */ + case 6: /* SBYTE */ + case 7: /* UNDEFINED */ + if (ifd[idx].cnt <= 4) { + scr[ 8] = ifd[idx].value_.v_byte[0]; + scr[ 9] = ifd[idx].value_.v_byte[1]; + scr[10] = ifd[idx].value_.v_byte[2]; + scr[11] = ifd[idx].value_.v_byte[3]; + } else { + scr[ 8] = (ifd[idx].value_.v_long >> 0) & 0xff; + scr[ 9] = (ifd[idx].value_.v_long >> 8) & 0xff; + scr[10] = (ifd[idx].value_.v_long >>16) & 0xff; + scr[11] = (ifd[idx].value_.v_long >>24) & 0xff; + } + break; + case 3: /* USHORT */ + case 8: /* SSHORT */ + if (ifd[idx].cnt <= 2) { + scr[ 8] = (ifd[idx].value_.v_short[0] >> 0) & 0xff; + scr[ 9] = (ifd[idx].value_.v_short[0] >> 8) & 0xff; + scr[10] = (ifd[idx].value_.v_short[1] >> 0) & 0xff; + scr[11] = (ifd[idx].value_.v_short[1] >> 8) & 0xff; + } else { + scr[ 8] = (ifd[idx].value_.v_long >> 0) & 0xff; + scr[ 9] = (ifd[idx].value_.v_long >> 8) & 0xff; + scr[10] = (ifd[idx].value_.v_long >>16) & 0xff; + scr[11] = (ifd[idx].value_.v_long >>24) & 0xff; + } + break; + case 4: /* ULONG */ + case 9: /* SLONG */ + case 11: /* FLOAT */ + case 5: /* URATIONAL */ + case 10: /* SRATIONAL */ + case 12: /* DOUBLE */ + scr[ 8] = (ifd[idx].value_.v_long >> 0) & 0xff; + scr[ 9] = (ifd[idx].value_.v_long >> 8) & 0xff; + scr[10] = (ifd[idx].value_.v_long >>16) & 0xff; + scr[11] = (ifd[idx].value_.v_long >>24) & 0xff; + break; + default: + assert(0); + break; + } + fwrite(scr, 1, 12, cp->fd); + } + cp->next_ifd_mark = ftell(cp->fd); + scr[0] = 0; + scr[1] = 0; + scr[2] = 0; + scr[3] = 0; + + fwrite(scr, 1, 4, cp->fd); + + fwrite(buf, 1, num_buf, cp->fd); +} + +int jxrc_begin_image_data(jxr_container_t cp) +{ + emit_ifd(cp); + return 0; +} + +int jxrc_write_container_post(jxr_container_t cp) +{ + uint32_t mark = ftell(cp->fd); + uint32_t count; + unsigned char scr[4]; + + mark = (mark+1)&~1; + + assert(mark > cp->image_offset_mark); + count = mark - cp->image_offset_mark; + + DEBUG("CONTAINER: measured bitstream count=%u\n", count); + + fseek(cp->fd, cp->image_count_mark, SEEK_SET); + + scr[0] = (count >> 0) & 0xff; + scr[1] = (count >> 8) & 0xff; + scr[2] = (count >> 16) & 0xff; + scr[3] = (count >> 24) & 0xff; + fwrite(scr, 1, 4, cp->fd); + + if(cp->separate_alpha_image_plane) + { + fseek(cp->fd, cp->alpha_offset_mark, SEEK_SET); + count = mark; + scr[0] = (count >> 0) & 0xff; + scr[1] = (count >> 8) & 0xff; + scr[2] = (count >> 16) & 0xff; + scr[3] = (count >> 24) & 0xff; + fwrite(scr, 1, 4, cp->fd); + } + fseek(cp->fd, mark, SEEK_SET); + cp->alpha_begin_mark = mark; + return 0; +} + +int jxrc_write_container_post_alpha(jxr_container_t cp) +{ + uint32_t mark = ftell(cp->fd); + uint32_t count; + + mark = (mark+1)&~1; + + count = mark - cp->alpha_begin_mark; + DEBUG("CONTAINER: measured alpha count=%u\n", count); + + if(cp->separate_alpha_image_plane) + { + unsigned char scr[4]; + fseek(cp->fd, cp->alpha_count_mark, SEEK_SET); + count = mark; + scr[0] = (count >> 0) & 0xff; + scr[1] = (count >> 8) & 0xff; + scr[2] = (count >> 16) & 0xff; + scr[3] = (count >> 24) & 0xff; + fwrite(scr, 1, 4, cp->fd); + } + fseek(cp->fd, mark, SEEK_SET); + return 0; +} +/* +* $Log: cw_emit.c,v $ +* Revision 1.2 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.1 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +*/ + diff --git a/jpegxr/dll_resource.h b/jpegxr/dll_resource.h new file mode 100644 index 000000000..e1b08553e --- /dev/null +++ b/jpegxr/dll_resource.h @@ -0,0 +1,14 @@ +//{{NO_DEPENDENCIES}} +// Microsoft Visual C++ generated include file. +// Used by DLL.rc + +// Next default values for new objects +// +#ifdef APSTUDIO_INVOKED +#ifndef APSTUDIO_READONLY_SYMBOLS +#define _APS_NEXT_RESOURCE_VALUE 101 +#define _APS_NEXT_COMMAND_VALUE 40001 +#define _APS_NEXT_CONTROL_VALUE 1001 +#define _APS_NEXT_SYMED_VALUE 101 +#endif +#endif diff --git a/jpegxr/dllmain.c b/jpegxr/dllmain.c new file mode 100644 index 000000000..e56685686 --- /dev/null +++ b/jpegxr/dllmain.c @@ -0,0 +1,75 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +/* dllmain.c : Defines the entry point for the DLL application. */ + +#ifdef _MSC_VER + +#include <windows.h> + +extern "C" BOOL APIENTRY DllMain( HMODULE hModule, + DWORD ul_reason_for_call, + LPVOID lpReserved + ) +{ + switch (ul_reason_for_call) + { + case DLL_PROCESS_ATTACH: + case DLL_THREAD_ATTACH: + case DLL_THREAD_DETACH: + case DLL_PROCESS_DETACH: + break; + } + return TRUE; +} + +#endif + +/* +* $Log: dllmain.c,v $ +* Revision 1.2 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.1 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +*/ + diff --git a/jpegxr/file.c b/jpegxr/file.c new file mode 100644 index 000000000..1a8042fd5 --- /dev/null +++ b/jpegxr/file.c @@ -0,0 +1,3082 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: file.c,v 1.15 2008/03/17 23:34:54 steve Exp $") +#else +#ident "$Id: file.c,v 1.15 2008/03/17 23:34:54 steve Exp $" +#endif + +#include <stdio.h> +#include <stdlib.h> +#include <stdarg.h> +#include <string.h> +#include <ctype.h> +#include <assert.h> +#include "jpegxr.h" +# include "jxr_priv.h" + +#ifndef _MSC_VER +# include <stdint.h> +#else +/* MSVC (as of 2008) does not support C99 or the stdint.h header +file. So include a private little header file here that does the +minimal typedefs that we need. */ +# include "stdint_minimal.h" +/* MSVC doesn't have strcasecmp. Use _stricmp instead */ +# define strcasecmp _stricmp +#endif + +typedef struct context{ + const char *name; /* name of TIFF or PNM file */ + int wid; /* image width in pixels */ + int hei; /* image height in pixels */ + int ncomp; /* num of color components, 1, 3, or 4 */ + int bpi; /* bits per component, 1..16 */ + int ycc_bd10_flag; /* flag to distinguish RGB101010 from YCC BD10 formats*/ + int ycc_format; /* ycc format, 0 (Not Applicable), 1 (YUV420), 2 (YUV422), 3 (YUV444)*/ + short sf; /* sample format, 1 (UINT), 2 (FixedPoint), 3 (float) or 4 (RGBE)*/ + int format; /* component format code 0..15 */ + unsigned swap : 1; /* byte swapping required ? */ + FILE *file; /* input or output file pointer */ + void *buf; /* source or destination data buffer */ + int my; /* last MB strip (of 16 lines) read, init to -1 */ + int nstrips; /* num of TIFF strips, 0 for PNM */ + int strip; /* index of the current TIFF strip, 0 for PNM */ + int nlines; /* num of lines per TIFF strip, height for PNM */ + int line; /* index of current line in current strip */ + short photometric; /* PhotometricInterpretation: + WhiteIsZero 0 + BlackIsZero 1 + RGB 2 + RGB Palette 3 + Transparency mask 4 + CMYK 5 + YCbCr 6 + CIELab 8 + */ + uint32_t offoff; /* offset in TIFF file of StripOffsets ifd entry*/ + int padBytes; + int alpha; /* with alpha channel */ + unsigned int isBgr; + int top_pad; + int top_pad_remaining; + int left_pad; +}context; + +static void error(char *format,...) +{ + va_list args; + fprintf(stderr, "Error: "); + va_start(args, format); + vfprintf(stderr, format, args); + va_end(args); + fprintf(stderr, "\n"); + abort(); +} + +/* YCC/CMYKDIRECT format tests */ + +unsigned int isOutputYUV444(jxr_image_t image) +{ + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_24bppYCC444: + case JXRC_FMT_30bppYCC444: + case JXRC_FMT_48bppYCC444: + case JXRC_FMT_48bppYCC444FixedPoint: + case JXRC_FMT_32bppYCC444Alpha: + case JXRC_FMT_40bppYCC444Alpha: + case JXRC_FMT_64bppYCC444Alpha: + case JXRC_FMT_64bppYCC444AlphaFixedPoint: + return 1; + default: + return 0; + } +} + +unsigned int isOutputYUV422(jxr_image_t image) +{ + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_16bppYCC422: + case JXRC_FMT_20bppYCC422: + case JXRC_FMT_32bppYCC422: + case JXRC_FMT_24bppYCC422Alpha: + case JXRC_FMT_30bppYCC422Alpha: + case JXRC_FMT_48bppYCC422Alpha: + return 1; + default: + return 0; + } +} + +unsigned int isOutputYUV420(jxr_image_t image) +{ + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_12bppYCC420: + case JXRC_FMT_20bppYCC420Alpha: + return 1; + default: + return 0; + } +} + +unsigned int isOutputCMYKDirect(jxr_image_t image) +{ + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_32bppCMYKDIRECT: + case JXRC_FMT_64bppCMYKDIRECT: + case JXRC_FMT_40bppCMYKDIRECTAlpha: + case JXRC_FMT_80bppCMYKDIRECTAlpha: + return 1; + default: + return 0; + } +} + +/* File Reading Primitives: */ + +static void read_data(context *con, void *buf, int size, int count) +{ + size_t rc = fread(buf, size, count, con->file); + if (rc!=count) + error("premature EOF in input file %s", con->name); +} + +static inline void read_uint8(context *con, uint8_t *buf, int count) +{ + read_data(con, buf, 1, count); +} + +static void read_uint16(context *con, uint16_t *buf, int count) +{ + read_data(con, buf, 2, count); + if (con->swap) { + uint8_t *p, *plim, t; + for (p=(uint8_t*)buf, plim=p+count*2; p<plim; p+=2) + t=p[0], p[0]=p[1], p[1]=t; + } +} + +static void read_uint32(context *con, uint32_t *buf, int count) +{ + read_data(con, buf, 4, count); + if (con->swap) { + uint8_t *p, *plim, t; + for (p=(uint8_t*)buf, plim=p+count*4; p<plim; p+=4) + t=p[0], p[0]=p[3], p[3]=t, t=p[1], p[1]=p[2], p[2]=t; + } +} + +static inline uint8_t get_uint8(context *con) +{ + uint8_t c; + read_uint8(con, &c, 1); + return c; +} + +static inline uint16_t get_uint16(context *con) +{ + uint16_t c; + read_uint16(con, &c, 1); + return c; +} + +static inline uint32_t get_uint32(context *con) +{ + uint32_t c; + read_uint32(con, &c, 1); + return c; +} + +static void seek_file(context *con, long offset, int whence) +{ + int rc = fseek(con->file, offset, whence); + if (rc!=0) + error("cannot seek to desired offset in input file %s", con->name); +} + +/* File Writing Primitives: */ + +static void write_data(context *con, const void *buf, int size, int count) +{ + size_t rc = fwrite(buf, size, count, con->file); + if (rc!=count) + error("unable to write to output file %s", con->name); +} + +static inline void write_uint8(context *con, const uint8_t *buf, int count) +{ + write_data(con, buf, 1, count); +} + +static void write_uint16(context *con, uint16_t *buf, int count) +{ + if (con->swap) { /* destructive ! */ + char *p, *plim, t; + for (p=(char*)buf, plim=p+count*2; p<plim; p+=2) + t=p[0], p[0]=p[1], p[1]=t; + } + write_data(con, buf, 2, count); +} + +static void write_uint32(context *con, uint32_t *buf, int count) +{ + if (con->swap) { /* destructive ! */ + char *p, *plim, t; + for (p=(char*)buf, plim=p+count*4; p<plim; p+=4) + t=p[0], p[0]=p[3], p[3]=t, t=p[1], p[1]=p[2], p[2]=t; + } + write_data(con, buf, 4, count); +} + +static inline void put_uint8(context *con, const uint8_t value) +{ + write_uint8(con, &value, 1); +} + +static inline void put_uint16(context *con, const uint16_t value) +{ + uint16_t buf = value; + write_uint16(con, &buf, 1); +} + +static inline void put_uint32(context *con, const uint32_t value) +{ + uint32_t buf = value; + write_uint32(con, &buf, 1); +} + +/* PNM File Header Operations: */ + +static unsigned read_pnm_number(context *con) +{ + int c; + unsigned n=0; + + while (1) { + c = get_uint8(con); + if (c=='#') + while (get_uint8(con)!='\n'); + else if (isdigit(c)) break; + else if (!isspace(c)) + error("unexpected character 0x%02x (%c) found in PNM file %s", c, c, con->name); + } + do { + n = 10*n+c-'0'; + c = get_uint8(con); + } + while (isdigit(c)); + if (!isspace(c)) + error("unexpected character 0x%02x (%c) following max value in PNM file %s", c, c, con->name); + return n; +} + +static void open_pnm_input_file(context *con) +{ + int c, max, one=1; + + rewind(con->file); + c=get_uint8(con); + if (c!='P') + error("unexpected character 0x%02x (%c) at start of PNM file %s", c, c, con->name); + switch (c=get_uint8(con)) { + case '1' : + case '2' : + case '3' : + case '4' : error("unsupported PNM file type P%c in PNM file %s", c, con->name); + case '5' : con->ncomp = 1; break; + case '6' : con->ncomp = 3; break; + default : error("unexpected character 0x%02x (%c) following 'P' in PNM file %s", c, c, con->name); + } + + con->wid = read_pnm_number(con); + if (con->wid<=0) + error("invalid image width %d in PNM file %s",con->wid, con->name); + con->hei = read_pnm_number(con); + if (con->hei<=0) + error("invalid image height %d in PNM file %s", con->hei, con->name); + max=read_pnm_number(con); + if (max>=0x10000) + error("invalid maximum value 0x%02x (%d) in PNM file %s", max, max, con->name); + if (max<0x100) con->swap = 0; + else con->swap = *(char*)&one==1; + for (con->bpi=1; max>(1<<con->bpi); con->bpi++); + + con->nlines = con->hei; +} + +static void start_pnm_output_file(context *con) +{ + int max, one=1; + con->file = fopen(con->name, "wb"); + if (con->file==0) + error("cannot create PNM output file %s",con->name); + max = (1<<con->bpi)-1; + if (max<256) con->swap = 0; + else con->swap = *(char*)&one==1; + fprintf(con->file, "P%c\n%d %d\n%d\n", con->ncomp==1?'5':'6', con->wid, con->hei, max); +} + +/* TIFF File Header Operations: */ + +#define ImageWidth 256 +#define ImageLength 257 +#define BitsPerSample 258 +#define Compression 259 +#define Photometric 262 +#define StripOffsets 273 +#define SamplesPerPixel 277 +#define RowsPerStrip 278 +#define StripByteCounts 279 +#define SampleFormat 339 +#define InkSet 332 + +static void read_tif_ifd_entry(context *con, uint32_t ifdoff, uint16_t *tag, uint16_t *type, uint32_t *count) +{ + seek_file(con, ifdoff, SEEK_SET); + read_uint16(con, tag, 1); + read_uint16(con, type, 1); + read_uint32(con, count, 1); +} + +static void read_tif_data(context *con, uint16_t type, uint32_t count, int index, int nval, void *buf) +{ + int size=0; + + switch (type) { + case 3 : size = 2; break; + case 4 : size = 4; break; + default : return; + } + + if (index+nval>(int)count) + error("data array is to small for read request in TIFF file %s", con->name); + + index *= size; + size *= count; + uint32_t offset = ftell(con->file); + if (size>4) + read_uint32(con, &offset, 1); + seek_file(con, offset+index, SEEK_SET); + switch (type) { + case 3 : read_uint16(con, (uint16_t*)buf, nval); break; + case 4 : read_uint32(con, (uint32_t*)buf, nval); + } +} + +static uint32_t read_tif_datum(context *con, uint16_t type, uint32_t count, int index) +{ + uint8_t buf[4]; + + read_tif_data(con, type, count, index, 1, buf); + switch (type) { + case 3 : return (uint32_t)*(uint16_t*)buf; + case 4 : return (uint32_t)*(uint32_t*)buf; + default : return 0; + } +} + +static uint32_t get_tif_datum(context *con, uint32_t ifdoff, int index) +{ + uint16_t tag, type; + uint32_t count; + + read_tif_ifd_entry(con, ifdoff, &tag, &type, &count); + return read_tif_datum(con, type, count, index); +} + +static void open_tif_input_file(context *con) +{ + int i, one=1; + uint16_t magic, nentry, tag, type; + uint32_t count, diroff; + + rewind(con->file); + read_uint16(con, &magic, 1); + switch (magic) { + case 0x4949 : con->swap = *(char*)&one!=1; break; + case 0x4d4d : con->swap = *(char*)&one==1; break; + default : error("bad magic number 0x%04x found at start of TIFF file %s", magic, con->name); + } + read_uint16(con, &magic, 1); + if (magic!=42) + error("magic number 42 not found in TIFF file %s", con->name); + read_uint32(con, &diroff, 1); + + seek_file(con, diroff, SEEK_SET); + read_uint16(con, &nentry, 1); + for (i=0; i<nentry; i++) { + int ifdoff = diroff+2+12*i; + read_tif_ifd_entry(con, ifdoff, &tag, &type, &count); + uint32_t data = read_tif_datum(con, type, count, 0); + switch (tag) { + case ImageWidth: + con->wid = data; + break; + case ImageLength: + con->hei = data; + break; + case BitsPerSample: + con->bpi = data; + break; + case SamplesPerPixel: + con->ncomp = data; + break; + case Compression: + if (data!=1) + error("TIFF input file %s is compressed", con->name); + break; + case StripOffsets: + con->nstrips = count; + con->offoff = ifdoff; + break; + case RowsPerStrip: + con->nlines = data; + break; + case SampleFormat: + con->sf = data; + break; + case Photometric: + con->photometric = data; + break; + + } + } + + if (con->wid<=0) + error("valid ImageWidth entry not found in directory of TIFF file %s", con->name); + if (con->hei<=0) + error("valid ImageLength entry not found in directory of TIFF file %s", con->name); + if (con->ncomp!=1 && con->ncomp!=3 && con->ncomp!=4 && con->ncomp!=5) + error("valid SamplesPerPixel entry (1, 3, 4, or 5) not found in directory of TIFF file %s", con->name); + if (con->bpi>32) + error("valid BitsPerSample entry not found in directory of TIFF file %s", con->name); + if (con->nstrips<=0 || con->offoff==0) + error("valid StripOffsets entry not found in directory of TIFF file %s", con->name); + if (con->nlines<=0) + error("valid RowsPerStrip entry not found in directory of TIFF file %s", con->name); + con->line = con->nlines; +} + + +static void put_ifd_entry(context *con, int tag, int type, int count, uint32_t offset) +{ + put_uint16(con, tag); + put_uint16(con, type); + put_uint32(con, count); + if (type==3 && count==1) { + put_uint16(con, offset); + put_uint16(con, 0); + } + else put_uint32(con, offset); +} + +unsigned int validate_tif_output(jxrc_t_pixelFormat ePixelFormat) +{ + switch(ePixelFormat) + { + case JXRC_FMT_24bppRGB:return 1; + case JXRC_FMT_24bppBGR: return 0; + case JXRC_FMT_32bppBGR:return 0; + case JXRC_FMT_48bppRGB:return 1; + case JXRC_FMT_48bppRGBFixedPoint: return 1; + case JXRC_FMT_48bppRGBHalf: return 1; + case JXRC_FMT_96bppRGBFixedPoint:return 1; + case JXRC_FMT_64bppRGBFixedPoint:return 1; + case JXRC_FMT_64bppRGBHalf:return 1; + case JXRC_FMT_128bppRGBFixedPoint:return 1; + case JXRC_FMT_128bppRGBFloat:return 1; + case JXRC_FMT_32bppBGRA:return 0; + case JXRC_FMT_64bppRGBA:return 1; + case JXRC_FMT_64bppRGBAFixedPoint:return 1; + case JXRC_FMT_64bppRGBAHalf:return 1; + case JXRC_FMT_128bppRGBAFixedPoint:return 1; + case JXRC_FMT_128bppRGBAFloat:return 1; + case JXRC_FMT_32bppPBGRA:return 0; + case JXRC_FMT_64bppPRGBA:return 0; + case JXRC_FMT_128bppPRGBAFloat:return 0; + case JXRC_FMT_32bppCMYK:return 1; + case JXRC_FMT_40bppCMYKAlpha:return 1; + case JXRC_FMT_64bppCMYK:return 1; + case JXRC_FMT_80bppCMYKAlpha:return 1; + case JXRC_FMT_24bpp3Channels:return 0; + case JXRC_FMT_32bpp4Channels:return 0; + case JXRC_FMT_40bpp5Channels:return 0; + case JXRC_FMT_48bpp6Channels:return 0; + case JXRC_FMT_56bpp7Channels:return 0; + case JXRC_FMT_64bpp8Channels:return 0; + case JXRC_FMT_32bpp3ChannelsAlpha:return 0; + case JXRC_FMT_40bpp4ChannelsAlpha:return 0; + case JXRC_FMT_48bpp5ChannelsAlpha:return 0; + case JXRC_FMT_56bpp6ChannelsAlpha:return 0; + case JXRC_FMT_64bpp7ChannelsAlpha:return 0; + case JXRC_FMT_72bpp8ChannelsAlpha:return 0; + case JXRC_FMT_48bpp3Channels:return 0; + case JXRC_FMT_64bpp4Channels:return 0; + case JXRC_FMT_80bpp5Channels:return 0; + case JXRC_FMT_96bpp6Channels:return 0; + case JXRC_FMT_112bpp7Channels:return 0; + case JXRC_FMT_128bpp8Channels:return 0; + case JXRC_FMT_64bpp3ChannelsAlpha:return 0; + case JXRC_FMT_80bpp4ChannelsAlpha:return 0; + case JXRC_FMT_96bpp5ChannelsAlpha:return 0; + case JXRC_FMT_112bpp6ChannelsAlpha:return 0; + case JXRC_FMT_128bpp7ChannelsAlpha:return 0; + case JXRC_FMT_144bpp8ChannelsAlpha:return 0; + case JXRC_FMT_8bppGray:return 1; + case JXRC_FMT_16bppGray:return 1; + case JXRC_FMT_16bppGrayFixedPoint:return 1; + case JXRC_FMT_16bppGrayHalf:return 1; + case JXRC_FMT_32bppGrayFixedPoint:return 1; + case JXRC_FMT_32bppGrayFloat:return 1; + case JXRC_FMT_BlackWhite:return 1; + case JXRC_FMT_16bppBGR555:return 0; + case JXRC_FMT_16bppBGR565:return 0; + case JXRC_FMT_32bppBGR101010:return 0; + case JXRC_FMT_32bppRGBE:return 0; + case JXRC_FMT_32bppCMYKDIRECT:return 0; + case JXRC_FMT_64bppCMYKDIRECT:return 0; + case JXRC_FMT_40bppCMYKDIRECTAlpha:return 0; + case JXRC_FMT_80bppCMYKDIRECTAlpha:return 0; + case JXRC_FMT_12bppYCC420:return 0; + case JXRC_FMT_16bppYCC422:return 0; + case JXRC_FMT_20bppYCC422:return 0; + case JXRC_FMT_32bppYCC422:return 0; + case JXRC_FMT_24bppYCC444:return 0; + case JXRC_FMT_30bppYCC444:return 0; + case JXRC_FMT_48bppYCC444:return 0; + case JXRC_FMT_48bppYCC444FixedPoint:return 0; + case JXRC_FMT_20bppYCC420Alpha:return 0; + case JXRC_FMT_24bppYCC422Alpha:return 0; + case JXRC_FMT_30bppYCC422Alpha:return 0; + case JXRC_FMT_48bppYCC422Alpha:return 0; + case JXRC_FMT_32bppYCC444Alpha:return 0; + case JXRC_FMT_40bppYCC444Alpha:return 0; + case JXRC_FMT_64bppYCC444Alpha:return 0; + case JXRC_FMT_64bppYCC444AlphaFixedPoint:return 0; + default: return 0; + } +} +unsigned int validate_pnm_output(jxrc_t_pixelFormat ePixelFormat) +{ + switch(ePixelFormat) + { + case JXRC_FMT_24bppRGB:return 1; + case JXRC_FMT_8bppGray:return 1; + default: return 0; + } +} + +static void start_tif_output_file(context *con) +{ + con->file = fopen(con->name, "wb"); + if (con->file==0) + error("cannot create TIFF output file %s", con->name); + con->swap = 0; + + int one = 1; + char magic = *(char*)&one==1 ? 'I' : 'M'; + int nentry = 10; + if (con->ncomp == 4 && !con->alpha) /* CMYK */ + nentry += 1; + int bitsize = con->ncomp>=3 ? 2*con->ncomp : 0; + int bitoff = 8 + 2 + 12*nentry + 4; + int datoff = bitoff + bitsize; + + put_uint8(con, magic); + put_uint8(con, magic); + put_uint16(con, 42); + put_uint32(con, 8); + put_uint16(con, nentry); + put_ifd_entry(con, ImageWidth, 4, 1, con->wid); + put_ifd_entry(con, ImageLength, 4, 1, con->hei); + put_ifd_entry(con, BitsPerSample, 3, con->ncomp, con->ncomp>=3 ? bitoff : con->bpi); + switch (con->format) + { + case 0: /* BD1WHITE1*/ + case 1: /* BD8 */ + case 2: /* BD16 */ + /* case 5: Reserved */ + case 8: /* BD5 */ + case 9: /* BD10 */ + case 15: /* BD1BLACK1 */ + con->sf = 1; + break; + case 3: /* BD16S */ + case 6: /* BD32S */ + con->sf = 2; + break; + case 4: /* BD16F */ + case 7: /* BD32F */ + con->sf = 3; + break; + default: + assert(0); + } + put_ifd_entry(con, SampleFormat, 3, 1, con->sf); + put_ifd_entry(con, Compression, 3, 1, 1); + put_ifd_entry(con, Photometric, 3, 1, con->photometric); + put_ifd_entry(con, StripOffsets, 4, 1, datoff); + if(!con->padBytes) + put_ifd_entry(con, SamplesPerPixel, 3, 1, con->ncomp); + else + put_ifd_entry(con, SamplesPerPixel, 3, 1, con->ncomp + 1); + + put_ifd_entry(con, RowsPerStrip, 4, 1, con->hei); + if(con->bpi == 1) + put_ifd_entry(con, StripByteCounts, 4, 1, ((con->wid+7)>>3) * con->hei * con->ncomp); + else if(!con->padBytes) + put_ifd_entry(con, StripByteCounts, 4, 1, con->wid * con->hei * con->ncomp * ((con->bpi+7)/8)); + else + put_ifd_entry(con, StripByteCounts, 4, 1, con->wid * con->hei * (con->ncomp + 1)* ((con->bpi+7)/8)); + + if (con->ncomp == 4 && !con->alpha) + put_ifd_entry(con, InkSet, 3, 1, 1); + + put_uint32(con, 0); + assert(ftell(con->file)==bitoff); + if (con->ncomp>=3) { + int i; + for (i=0; i<con->ncomp; i++) + put_uint16(con, con->bpi); + } + assert(ftell(con->file)==datoff); +} + +static void start_raw_output_file(context *con) +{ + con->file = fopen(con->name, "w+b"); + if (con->file==0) + error("cannot create RAW output file %s", con->name); + con->swap = 0; +} + +/* Generic File Header Operations: */ + +void *open_input_file(const char *name, const raw_info *raw_info_t, int *alpha_mode, int *padded_format) +{ + context *con; + + con = (context*)malloc(sizeof(context)); + if (con==0) + error("unable to allocate memory"); + + con->name = name; + con->wid = 0; + con->hei = 0; + con->ncomp = 0; + con->bpi = 0; + con->format = 0; + con->sf = 1; + con->swap = 0; + con->buf = 0; + con->my = -1; + con->nstrips = 0; + con->strip = 0; + con->nlines = 0; + con->line = 0; + con->photometric = 0; + con->offoff = 0; + con->ycc_bd10_flag = 0; + con->ycc_format = 0; + + con->file = fopen(name, "rb"); + if (con->file==0) + error("cannot find input file %s", name); + + if (!raw_info_t->is_raw) { + switch (get_uint8(con)) { + case 'P' : open_pnm_input_file(con); break; + case 'I' : + case 'M' : open_tif_input_file(con); break; + default : error("format of input file %s is unrecognized", name); + } + + con->padBytes = 0; + if(con->photometric == 2 && con->ncomp == 4) /* RGBA */ + if( *padded_format == 1) { /* for RGB_NULL, there is a padding channel */ + con->padBytes = 1; + con->ncomp --; + if(*alpha_mode != 0) + { + *alpha_mode = 0; /* Turn off alpha mode */ + fprintf(stderr, "Setting alpha_mode to 0 to encode a padded format \n"); + } + } + else + { + if(*alpha_mode == 0) + { + *alpha_mode = 2; /* Turn on separate alpha */ + } + } + } + else { /* raw input */ + con->wid = raw_info_t->raw_width; + con->hei = raw_info_t->raw_height; + con->nlines = con->hei; + con->bpi = raw_info_t->raw_bpc; + con->sf = 1; /* UINT */ + con->padBytes = 0; + if (con->bpi == 10 && raw_info_t->raw_format > 18) { + con->ycc_bd10_flag = 1; + con->bpi = 16; + } + + if ((raw_info_t->raw_format >= 3) && (raw_info_t->raw_format <= 8)) { /* N-channel */ + con->ncomp = raw_info_t->raw_format; + } + else if ((raw_info_t->raw_format >= 9) && (raw_info_t->raw_format <= 14)) { /* N-channel with Alpha */ + con->ncomp = raw_info_t->raw_format - 5; + } + else if (15 == raw_info_t->raw_format) {/* RGBE */ + con->ncomp = 4; + con->sf = 4; + } + else if (16 == raw_info_t->raw_format) {/* 555 */ + con->ncomp = 3; + con->bpi = 5; + } + else if (17 == raw_info_t->raw_format) {/* 565 */ + con->ncomp = 3; + con->bpi = 6; + } + else if (18 == raw_info_t->raw_format) {/* 101010 */ + con->ncomp = 3; + con->bpi = 10; + } + else if (19 == raw_info_t->raw_format) { + con->ncomp = 3; + con->ycc_format = 1; + } + else if (20 == raw_info_t->raw_format) { + con->ncomp = 3; + con->ycc_format = 2; + } + else if (21 == raw_info_t->raw_format) { + con->ncomp = 3; + con->ycc_format = 3; + } + else if (22 == raw_info_t->raw_format) { + con->ncomp = 3; + con->sf = 2; /* SINT */ + con->ycc_format = 3; + } + else if (23 == raw_info_t->raw_format) { + con->ncomp = 4; + con->ycc_format = 1; + } + else if (24 == raw_info_t->raw_format) { + con->ncomp = 4; + con->ycc_format = 2; + } + else if (25 == raw_info_t->raw_format) { + con->ncomp = 4; + con->ycc_format = 3; + } + else if (26 == raw_info_t->raw_format) { + con->ncomp = 4; + con->sf = 2; /* SINT */ + con->ycc_format = 3; + } + else if (27 == raw_info_t->raw_format) { + con->ncomp = 4; + } + else if (28 == raw_info_t->raw_format) { + con->ncomp = 5; + } + else if(29 == raw_info_t->raw_format) {/* 24bppBGR */ + con->ncomp = 3; + con->bpi = 8; + } + else if(30 == raw_info_t->raw_format) {/* 32bppBGR */ + con->ncomp = 3; + con->bpi = 8; + con->padBytes = 1; + *padded_format = 1; + } + else if(31 == raw_info_t->raw_format) {/* 32bppBGRA */ + con->ncomp = 4; + con->bpi = 8; + } + else if(32 == raw_info_t->raw_format) {/* 32bppPBGRA */ + con->ncomp = 4; + con->bpi = 8; + } + else if(33 == raw_info_t->raw_format) {/* 64bppPRGBA */ + con->ncomp = 4; + con->bpi = 16; + } + else if(34 == raw_info_t->raw_format) {/* 128bppPRGBAFloat */ + con->ncomp = 4; + con->bpi = 32; + con->sf = 3; + con->photometric = 2; + } + } + + if(con->padBytes == 0 && *padded_format) + { + *padded_format = 0; + fprintf(stderr, "Ignoring -p option from command line \n"); + } + + size_t strip_bytes; + if (con->ycc_format == 1) + strip_bytes = 8 * ((4*con->ncomp-6) + con->padBytes) * ((con->bpi+7)/8) * ((con->wid+15)&~15)/2; + else if (con->ycc_format == 2) + strip_bytes = 16 * ((2*con->ncomp-2) + con->padBytes) * ((con->bpi+7)/8) * ((con->wid+15)&~15)/2; + else + strip_bytes = 16 * (con->ncomp + con->padBytes) * ((con->bpi+7)/8) * ((con->wid+15)&~15); + + if (con->bpi == 1) + strip_bytes >>= 3; + else if ((con->bpi == 5) || (con->bpi == 6) || (con->bpi == 10 && !con->ycc_bd10_flag)) + strip_bytes = (strip_bytes << 1) / 3; /* external buffer */ + + con->buf = calloc(strip_bytes, 1); + if (con->buf==0) + error("cannot allocate memory"); + + return con; +} +void set_ncomp(void *input_handle, int ncomp) +{ + context *con = (context *)input_handle; + con->ncomp = ncomp; +} + +void *open_output_file(const char *name) +{ + context *con = (context*)malloc(sizeof(context)); + if (con==0) + error("unable to allocate memory"); + con->file = 0; + con->name = name; + con->wid = 0; + con->hei = 0; + con->ncomp = 0; + con->bpi = 0; + con->format = 0; + con->swap = 0; + con->buf = 0; + return con; +} + +void close_file(void *handle) +{ + if(handle == NULL) + return; + context *con = (context*)handle; + if (con->file) fclose(con->file); + if (con->buf) free(con->buf); + free(con); +} + +void get_file_parameters(void *handle, int *wid, int *hei, int *ncomp, int *bpi, short *sf, short *photometric, int *padBytes) +{ + context *con = (context*)handle; + if (wid) *wid = con->wid; + if (hei) *hei = con->hei; + if (ncomp) *ncomp = con->ncomp; + if (bpi) *bpi = con->bpi; + if (sf) *sf = con->sf; + if (photometric) *photometric = con->photometric; + if (padBytes) *padBytes = con->padBytes; +} + +void set_photometric_interp(context *con, jxrc_t_pixelFormat pixelFormat) +{ + switch(pixelFormat) + { + case JXRC_FMT_32bppCMYK: + case JXRC_FMT_40bppCMYKAlpha: + case JXRC_FMT_64bppCMYK: + case JXRC_FMT_80bppCMYKAlpha: + con->photometric = 5; + return; + case JXRC_FMT_8bppGray: + case JXRC_FMT_16bppGray: + case JXRC_FMT_16bppGrayFixedPoint: + case JXRC_FMT_16bppGrayHalf: + case JXRC_FMT_32bppGrayFixedPoint: + case JXRC_FMT_32bppGrayFloat: + case JXRC_FMT_BlackWhite: + con->photometric = 1; + return; + default: + con->photometric = 2; + return; + } +} + +static void start_output_file(context *con, int ext_width, int ext_height, int width, int height, int ncomp, int format, jxrc_t_pixelFormat pixelFormat) +{ + int bpi=0; + switch (format) { + case 0 : bpi=1; break; + case 1 : bpi=8; break; + case 2 : + case 3 : + case 4 : bpi=16; break; + case 5 : + case 6 : + case 7 : bpi=32; break; + case 8 : bpi=5; break; + case 9 : bpi=10; break; + case 10 : bpi=6; break; + case 15 : bpi=1; break; + default : error("invalid component format code (%d) for output file %s", format, con->name); + } + + if (bpi<1 || bpi>32) + error("invalid bits per sample (%d) for output file %s", bpi, con->name); + if (width<=0 || height<=0) + error("invalid dimensions (%d X %d) for output file %s", width, height, con->name); + + con->wid = width; + con->hei = height; + con->ncomp = ncomp; + con->bpi = bpi; + con->format = format; + /* Add one extra component for possible padding channel */ + con->buf = malloc(((ext_width)/16) * 256 * (ncomp + 1) * ((con->bpi+7)/8)); + if (con->buf==0) error("unable to allocate memory"); + + const char *p = strrchr(con->name, '.'); + if (p==0) + error("output file name %s needs a suffix to determine its format", con->name); + if (!strcasecmp(p, ".pnm") || !strcasecmp(p, ".pgm") || !strcasecmp(p, ".ppm")) + { + if(!validate_pnm_output(pixelFormat)) + { + printf("User error: PixelFormat is incompatible with pnm output, use .raw or .tif extension for output file\n"); + assert(0); + } + start_pnm_output_file(con); + } + else if (!strcasecmp(p, ".tif")) + { + if(!validate_tif_output(pixelFormat) && ncomp != 1) + { + printf("User error: PixelFormat is incompatible with tif output, use .raw extension for output file\n"); + assert(0); + } + set_photometric_interp(con, pixelFormat); + start_tif_output_file(con); + } + else if (!strcasecmp(p, ".raw")) + start_raw_output_file(con); + else error("unrecognized suffix on output file name %s", con->name); +} + +/* File Read and Write Operations: */ + +static int PreScalingBD16F(int hHalf) +{ + int s; + s = (hHalf >> 31); + hHalf = ((hHalf & 0x7fff) ^ s) - s; + return hHalf; +} + +static int PreScalingBD32F(int f, const char _c, const unsigned char _lm) +{ + int _h, e, e1, m, s; + + if (f == 0) + { + _h = 0; + } + else + { + e = (f >> 23) & 0x000000ff;/* here set e as e, not s! e includes s: [s e] 9 bits [31..23] */ + m = (f & 0x007fffff) | 0x800000; /* actual mantissa, with normalizer */ + if (e == 0) { /* denormal-land */ + m ^= 0x800000; /* actual mantissa, removing normalizer */ + e++; /* actual exponent -126 */ + } + + e1 = e - 127 + _c; /* this is basically a division or quantization to a different exponent */ + + if (e1 <= 1) { /* denormal */ + if (e1 < 1) + m >>= (1 - e1); /* shift mantissa right to make exponent 1 */ + e1 = 1; + if ((m & 0x800000) == 0) /* if denormal, set e1 to zero else to 1 */ + e1 = 0; + } + m &= 0x007fffff; + + _h = (e1 << _lm) + ((m + (1 << (23 - _lm - 1))) >> (23 - _lm));/* take 23-bit m, shift (23-lm), get lm-bit m */ + s = (f >> 31); + /* padding to int-32: */ + _h = (_h ^ s) - s; + } + + return _h; +} + +int forwardRGBE (int RGB, int E) +{ + int iResult = 0, iAppend = 1; + + if (E == 0) + return 0; + + E--; + while (((RGB & 0x80) == 0) && (E > 0)) { + RGB = (RGB << 1) + iAppend; + iAppend = 0; + E--; + } + + if (E == 0) { + iResult = RGB; + } + else { + E++; + iResult = (RGB & 0x7f) + (E << 7); + } + + return iResult; +} + +void set_pad_bytes(context *con, jxr_image_t image) +{ + /* Incomplete: Add padding data for other formats as we go */ + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_128bppRGBFloat: + case JXRC_FMT_128bppRGBFixedPoint: + con->padBytes = 32; + break; + case JXRC_FMT_64bppRGBFixedPoint: + case JXRC_FMT_64bppRGBHalf: + con->padBytes = 16; + break; + case JXRC_FMT_32bppBGR: + con->padBytes = 8; + break; + default: + con->padBytes = 0; + break; + } + +} + +void set_bgr_flag(context *con, jxr_image_t image) +{ + con->isBgr = 0; + switch (jxr_get_pixel_format(image)) + { + case JXRC_FMT_24bppBGR: + case JXRC_FMT_32bppBGR: + case JXRC_FMT_32bppBGRA: + case JXRC_FMT_32bppPBGRA: + con->isBgr = 1; + break; + default: + break; + } + return; +} + +void switch_r_b(void *data, int bpi) +{ + uint32_t tmp; + data = (uint8_t*)data; + if(bpi == 8) + { + uint8_t *p = (uint8_t*)data; + tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + + } + + else if(bpi == 16) + { + uint16_t *p = (uint16_t*)data; + tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + } + else if(bpi == 32) + { + uint32_t *p = (uint32_t *)data; + tmp = p[0]; + p[0] = p[2]; + p[2] = tmp; + } + else + { + assert(!"Invalid bpi\n"); + } +} + +static void read_setup(context *con) +{ + if (con->line == con->nlines) { + if (con->strip == con->nstrips) + error("unexpected end of data encountered in input file %s", con->name); + seek_file(con, get_tif_datum(con, con->offoff, con->strip), SEEK_SET); + con->strip++; + } + con->line++; +} + +void read_file_YCC(jxr_image_t image, int mx, int my, int *data) { + /* There are 3 or 4 buffers, depending on whether there is an alpha channel or not */ + context *con = (context*) jxr_get_user_data(image); + int num_channels = con->ncomp; + + unsigned int widthY = con->wid, heightY = con->hei; + unsigned int widthUV = con->wid >> ((con->ycc_format == 1 || con->ycc_format == 2) ? 1 : 0); + unsigned int heightUV = con->hei >> (con->ycc_format == 1 ? 1 : 0); + unsigned int MBheightY = 16; + unsigned int MBheightUV = con->ycc_format == 1 ? 8 : 16; + unsigned int sizeY = widthY * heightY; + unsigned int sizeUV = widthUV * heightUV; + + if (my != con->my) { + if (con->bpi == 8) { + unsigned int offsetY = my * MBheightY * widthY; + unsigned int offsetU = sizeY + my * MBheightUV * widthUV; + unsigned int offsetV = sizeY + sizeUV + my * MBheightUV * widthUV; + unsigned int offsetA = sizeY + 2 * sizeUV + my * MBheightY * widthY; + + uint8_t *sp = (uint8_t*)con->buf; + + seek_file(con, offsetY, SEEK_SET); + memset(sp, 0, widthY * MBheightY); + read_data(con, sp, 1, widthY * MBheightY); + sp += widthY * MBheightY; + + seek_file(con, offsetU, SEEK_SET); + memset(sp, 0, widthUV * MBheightUV); + read_data(con, sp, 1, widthUV * MBheightUV); + sp += widthUV * MBheightUV; + + seek_file(con, offsetV, SEEK_SET); + memset(sp, 0, widthUV * MBheightUV); + read_data(con, sp, 1, widthUV * MBheightUV); + sp += widthUV * MBheightUV; + + if (con->ncomp == 4) { + seek_file(con, offsetA, SEEK_SET); + memset(sp, 0, widthY * MBheightY); + read_data(con, sp, 1, widthY * MBheightY); + sp += widthY * MBheightY; + } + } + else if (con->bpi == 16) { + unsigned int offsetY = 2 * (my * MBheightY * widthY); + unsigned int offsetU = 2 * (sizeY + my * MBheightUV * widthUV); + unsigned int offsetV = 2 * (sizeY + sizeUV + my * MBheightUV * widthUV); + unsigned int offsetA = 2 * (sizeY + 2 * sizeUV + my * MBheightY * widthY); + + uint16_t *sp = (uint16_t*)con->buf; + + seek_file(con, offsetY, SEEK_SET); + memset(sp, 0, 2 * widthY * MBheightY); + read_data(con, sp, 2, widthY * MBheightY); + sp += widthY * MBheightY; + + seek_file(con, offsetU, SEEK_SET); + memset(sp, 0, 2 * widthUV * MBheightUV); + read_data(con, sp, 2, widthUV * MBheightUV); + sp += widthUV * MBheightUV; + + seek_file(con, offsetV, SEEK_SET); + memset(sp, 0, 2 * widthUV * MBheightUV); + read_data(con, sp, 2, widthUV * MBheightUV); + sp += widthUV * MBheightUV; + + if (con->ncomp == 4) { + seek_file(con, offsetA, SEEK_SET); + memset(sp, 0, 2 * widthY * MBheightY); + read_data(con, sp, 2, widthY * MBheightY); + sp += widthY * MBheightY; + } + } + con->my = my; + } + + int idx1, idx2; + int xDiv = 16; + int yDiv = 16; + + if (con->bpi == 8) { + /* Y */ + uint8_t *sp = (uint8_t*)con->buf + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 0] = sp[idx2]; + sp += widthY; + } + + if (con->ycc_format == 2) + xDiv = 8; + + if (con->ycc_format == 1) + xDiv = yDiv = 8; + + /* U */ + sp = (uint8_t*)con->buf + widthY * MBheightY + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 1] = sp[idx2]; + sp += widthUV; + } + + /* V */ + sp = (uint8_t*)con->buf + widthY * MBheightY + widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 2] = sp[idx2]; + sp += widthUV; + } + + if(con->ncomp == 4) + { + xDiv = yDiv = 16; + sp = (uint8_t*)con->buf + widthY * MBheightY + 2 * widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 3] = sp[idx2]; + sp += widthY; + } + } + } + else if (con->bpi == 16 || con->bpi == 10) { + if (con->sf == 1) { + /* Y */ + uint16_t *sp = (uint16_t*)con->buf + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 0] = sp[idx2]; + sp += widthY; + } + + if (con->ycc_format == 2) + xDiv = 8; + + if (con->ycc_format == 1) + xDiv = yDiv = 8; + + /* U */ + sp = (uint16_t*)con->buf + widthY * MBheightY + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 1] = sp[idx2]; + sp += widthUV; + } + + /* V */ + sp = (uint16_t*)con->buf + widthY * MBheightY + widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 2] = sp[idx2]; + sp += widthUV; + } + + if(con->ncomp == 4) + { + xDiv = yDiv = 16; + sp = (uint16_t*)con->buf + widthY * MBheightY + 2 * widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 3] = sp[idx2]; + sp += widthY; + } + } + } + else if (con->sf == 2) { + /* Y */ + short *sp = (short*)con->buf + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 0] = sp[idx2]; + sp += widthY; + } + + if (con->ycc_format == 2) + xDiv = 8; + + if (con->ycc_format == 1) + xDiv = yDiv = 8; + + /* U */ + sp = (short*)con->buf + widthY * MBheightY + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 1] = sp[idx2]; + sp += widthUV; + } + + /* V */ + sp = (short*)con->buf + widthY * MBheightY + widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 2] = sp[idx2]; + sp += widthUV; + } + + if(con->ncomp == 4) + { + xDiv = yDiv = 16; + sp = (short*)con->buf + widthY * MBheightY + 2 * widthUV * MBheightUV + xDiv*mx; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 3] = sp[idx2]; + sp += widthY; + } + } + } + } +} + +void read_file_CMYK(jxr_image_t image, int mx, int my, int *data) { + /* There are 4 or 5 buffers, depending on whether there is an alpha channel or not */ + context *con = (context*) jxr_get_user_data(image); + int num_channels = con->ncomp; + + unsigned int width = con->wid, height = con->hei; + unsigned int MBheight = 16; + unsigned int size = width * height; + + if (my != con->my) { + if (con->bpi == 8) { + unsigned int offsetC = my * MBheight * width + 0 * size; + unsigned int offsetM = my * MBheight * width + 1 * size; + unsigned int offsetY = my * MBheight * width + 2 * size; + unsigned int offsetK = my * MBheight * width + 3 * size; + unsigned int offsetA = my * MBheight * width + 4 * size; + + uint8_t *sp = (uint8_t*)con->buf; + + seek_file(con, offsetC, SEEK_SET); + memset(sp, 0, width * MBheight); + read_data(con, sp, 1, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetM, SEEK_SET); + memset(sp, 0, width * MBheight); + read_data(con, sp, 1, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetY, SEEK_SET); + memset(sp, 0, width * MBheight); + read_data(con, sp, 1, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetK, SEEK_SET); + memset(sp, 0, width * MBheight); + read_data(con, sp, 1, width * MBheight); + sp += width * MBheight; + + if (con->ncomp == 5) { + seek_file(con, offsetA, SEEK_SET); + memset(sp, 0, width * MBheight); + read_data(con, sp, 1, width * MBheight); + sp += width * MBheight; + } + } + else if (con->bpi == 16) { + unsigned int offsetC = 2 * (my * MBheight * width + 0 * size); + unsigned int offsetM = 2 * (my * MBheight * width + 1 * size); + unsigned int offsetY = 2 * (my * MBheight * width + 2 * size); + unsigned int offsetK = 2 * (my * MBheight * width + 3 * size); + unsigned int offsetA = 2 * (my * MBheight * width + 4 * size); + + uint16_t *sp = (uint16_t*)con->buf; + + seek_file(con, offsetC, SEEK_SET); + memset(sp, 0, 2 * width * MBheight); + read_data(con, sp, 2, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetM, SEEK_SET); + memset(sp, 0, 2 * width * MBheight); + read_data(con, sp, 2, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetY, SEEK_SET); + memset(sp, 0, 2 * width * MBheight); + read_data(con, sp, 2, width * MBheight); + sp += width * MBheight; + + seek_file(con, offsetK, SEEK_SET); + memset(sp, 0, 2 * width * MBheight); + read_data(con, sp, 2, width * MBheight); + sp += width * MBheight; + + if (con->ncomp == 5) { + seek_file(con, offsetA, SEEK_SET); + memset(sp, 0, 2 * width * MBheight); + read_data(con, sp, 2, width * MBheight); + sp += width * MBheight; + } + } + con->my = my; + } + + int idx1, idx2; + int xDiv = 16; + int yDiv = 16; + + if (con->bpi == 8) { + /* C */ + uint8_t *sp = (uint8_t*)con->buf + xDiv*mx + 0 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 0] = sp[idx2]; + sp += width; + } + + /* M */ + sp = (uint8_t*)con->buf + xDiv*mx + 1 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 1] = sp[idx2]; + sp += width; + } + + /* Y */ + sp = (uint8_t*)con->buf + xDiv*mx + 2 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 2] = sp[idx2]; + sp += width; + } + + /* K */ + sp = (uint8_t*)con->buf + xDiv*mx + 3 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 3] = sp[idx2]; + sp += width; + } + + if(con->ncomp == 5) + { + sp = (uint8_t*)con->buf + xDiv*mx + 4 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 4] = sp[idx2]; + sp += width; + } + } + } + else if (con->bpi == 16) { + /* C */ + uint16_t *sp = (uint16_t*)con->buf + xDiv*mx + 0 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 0] = sp[idx2]; + sp += width; + } + + /* M */ + sp = (uint16_t*)con->buf + xDiv*mx + 1 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 1] = sp[idx2]; + sp += width; + } + + /* Y */ + sp = (uint16_t*)con->buf + xDiv*mx + 2 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 2] = sp[idx2]; + sp += width; + } + + /* K */ + sp = (uint16_t*)con->buf + xDiv*mx + 3 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 3] = sp[idx2]; + sp += width; + } + + if(con->ncomp == 5) + { + sp = (uint16_t*)con->buf + xDiv*mx + 4 * width * MBheight; + for (idx1 = 0; idx1 < yDiv; idx1 += 1) { + for (idx2 = 0; idx2 < xDiv; idx2 += 1) + data[(idx1 * xDiv + idx2) * num_channels + 4] = sp[idx2]; + sp += width; + } + } + } +} + + +void read_file(jxr_image_t image, int mx, int my, int *data) +{ + context *con = (context*) jxr_get_user_data(image); + unsigned char uExternalNcomp = con->ncomp + con->padBytes; + int block_wid = uExternalNcomp * ((con->wid+15)&~15); + + if((isOutputYUV444(image) || isOutputYUV422(image) || isOutputYUV420(image)) && jxr_get_IMAGE_CHANNELS(image) == 3) + { + /* Use special YCC format only for primary image */ + read_file_YCC(image, mx, my, data); + return; + } + else if(isOutputCMYKDirect(image) && jxr_get_IMAGE_CHANNELS(image) == 4) + { + /* Use special YCC format only for primary image */ + read_file_CMYK(image, mx, my, data); + return; + } + + if(con->ncomp == 3 || con->ncomp == 4) + { + set_bgr_flag(con, image); + } + else + { + con->isBgr = 0; + } + + if (my != con->my) { + int trans = (my*16 + 16 > con->hei) ? con->hei%16 : 16; + int line_wid = uExternalNcomp * con->wid; + int idx; + if (con->bpi == 1) { + uint8_t *sp = (uint8_t*)con->buf; + line_wid = ((line_wid + 7) >> 3); + block_wid >>= 3; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint8(con, sp, line_wid); + sp += block_wid; + } + } + else if ((con->bpi == 5) || (con->bpi == 6)) { + uint16_t *sp = (uint16_t*)con->buf; + block_wid = ((con->wid+15)&~15); + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint16(con, sp, con->wid); + sp += block_wid; + } + } + else if (con->bpi == 8) { + uint8_t *sp = (uint8_t*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint8(con, sp, line_wid); + if(con->isBgr) + { + int i; + for(i = 0; i < con->wid; i ++) + { + int tmp = sp[i*(uExternalNcomp)] ; + sp[i*(uExternalNcomp)] = sp[i*(uExternalNcomp)+ 2]; + sp[i*(uExternalNcomp)+ 2] = tmp; + } + } + sp += block_wid; + } + } + else if (con->bpi == 10) { + uint32_t *sp = (uint32_t*)con->buf; + block_wid = ((con->wid+15)&~15); + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint32(con, sp, con->wid); + sp += block_wid; + } + } + else if (con->bpi == 16) { + if (con->sf == 1) { /* UINT */ + uint16_t *sp = (uint16_t*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint16(con, sp, line_wid); + sp += block_wid; + } + } + else if (con->sf == 2) { /* fixed point */ + short *sp = (short*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint16(con, (uint16_t *)sp, line_wid); + sp += block_wid; + } + } + else if (con->sf == 3) { /* Half float */ + short *sp = (short*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint16(con, (uint16_t *)sp, line_wid); + sp += block_wid; + } + } + } + else if (con->bpi == 32) { + if (con->sf == 2) { /* fixed point */ + uint32_t *sp = (uint32_t*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint32(con, sp, line_wid); + sp += block_wid; + } + } + else if (con->sf == 3) { /* float */ + uint32_t *sp = (uint32_t*)con->buf; + for (idx = 0; idx < trans; idx += 1) { + read_setup(con); + read_uint32(con, sp, line_wid); + sp += block_wid; + } + } + } + con->my = my; + } + + int xdx, ydx, sxdx; + if (con->bpi == 1) { + block_wid = (((con->wid+15)&~15) >> 3); + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + if (con->sf == 1) { + uint8_t *sp = (uint8_t*)con->buf + ydx*block_wid + ((con->ncomp*16*mx) >> 3); + int *dp = data + con->ncomp*16*ydx; + if (!con->photometric) { + for (xdx = 0 ; xdx < con->ncomp*16 ; xdx++) + dp[xdx] = ((sp[xdx >> 3] >> (7 - (xdx & 7))) & 1); + } + else { + for (xdx = 0 ; xdx < con->ncomp*16 ; xdx++) + dp[xdx] = (((~sp[xdx >> 3]) >> (7 - (xdx & 7))) & 1); + } + } + } + } + else if (con->bpi == 5) { + block_wid = ((con->wid+15)&~15); + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + uint16_t *sp = (uint16_t*)con->buf + ydx*block_wid + 16*mx; + int *dp = data + uExternalNcomp*16*ydx; + for (xdx = 0, sxdx = 0; xdx < uExternalNcomp*16 ; xdx += uExternalNcomp, sxdx++) { + dp[xdx] = (sp[sxdx] & 0x1f); + dp[xdx + 1] = ((sp[sxdx] >> 5) & 0x1f); + dp[xdx + 2] = ((sp[sxdx] >> 10) & 0x1f); + } + } + } + else if (con->bpi == 6) { + block_wid = ((con->wid+15)&~15); + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + uint16_t *sp = (uint16_t*)con->buf + ydx*block_wid + 16*mx; + int *dp = data + uExternalNcomp*16*ydx; + for (xdx = 0, sxdx = 0; xdx < uExternalNcomp*16 ; xdx += uExternalNcomp, sxdx++) { + dp[xdx] = ((sp[sxdx] & 0x1f) << 1); + dp[xdx + 1] = ((sp[sxdx] >> 5) & 0x3f); + dp[xdx + 2] = (((sp[sxdx] >> 11) & 0x1f) << 1); + } + } + } + else if (con->bpi == 8) { + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + if (con->sf == 1) { /* UINT */ + uint8_t *sp = (uint8_t*)con->buf + ydx*block_wid + uExternalNcomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + int iCh; + for (xdx = 0 ; xdx < 16 ; xdx++) { + for (iCh = 0; iCh < con->ncomp; iCh ++){ + dp[iCh] = (sp[iCh] >> image->shift_bits); + } + dp += con->ncomp; + sp += uExternalNcomp; + } + } + else if (con->sf == 4){ /* RGBE */ + uint8_t *sp = (uint8_t*)con->buf + ydx*block_wid + con->ncomp*16*mx; /* external ncomp is 4, internal is 3 */ + int *dp = data + 3*16*ydx; + for (xdx = 0, sxdx = 0 ; xdx < 3*16 ; xdx += 3, sxdx +=4) { + dp[xdx] = forwardRGBE((int)sp[sxdx], (int)sp[sxdx + 3]); + dp[xdx + 1] = forwardRGBE((int)sp[sxdx + 1], (int)sp[sxdx + 3]); + dp[xdx + 2] = forwardRGBE((int)sp[sxdx + 2], (int)sp[sxdx + 3]); + } + } + } + } + else if (con->bpi == 10) { + block_wid = ((con->wid+15)&~15); + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + uint32_t *sp = (uint32_t*)con->buf + ydx*block_wid + 16*mx; + int *dp = data + uExternalNcomp*16*ydx; + for (xdx = 0, sxdx = 0; xdx < uExternalNcomp*16 ; xdx += uExternalNcomp, sxdx++) { + dp[xdx] = (sp[sxdx] & 0x3ff); + dp[xdx + 1] = ((sp[sxdx] >> 10) & 0x3ff); + dp[xdx + 2] = ((sp[sxdx] >> 20) & 0x3ff); + } + } + } + else if (con->bpi == 16) { + if (con->sf == 1) { /* UINT */ + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + uint16_t *sp = (uint16_t*)con->buf + ydx*block_wid + con->ncomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + for (xdx = 0 ; xdx < con->ncomp*16 ; xdx++) + dp[xdx] = (sp[xdx] >> image->shift_bits); + } + } + else if (con->sf == 2) { /* fixed point */ + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + short *sp = (short*)con->buf + ydx*block_wid + uExternalNcomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + int iCh; + for (xdx = 0 ; xdx < 16 ; xdx++) { + for (iCh = 0; iCh < con->ncomp; iCh ++){ + dp[iCh] = (sp[iCh] >> image->shift_bits); + } + dp += con->ncomp; + sp += uExternalNcomp; + } + } + } + else if (con->sf == 3) { /* Half float */ + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + short *sp = (short*)con->buf + ydx*block_wid + uExternalNcomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + int iCh; + for (xdx = 0 ; xdx < 16 ; xdx++) { + for (iCh = 0; iCh < con->ncomp; iCh ++) { + dp[iCh] = PreScalingBD16F((int)sp[iCh]); + } + dp += con->ncomp; + sp += uExternalNcomp; + } + } + } + } + else if (con->bpi == 32) { + /* no 32-UINT */ + if (con->sf == 2) { /* fixed point */ + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + int32_t *sp = (int32_t*)con->buf + ydx*block_wid + uExternalNcomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + int iCh; + for (xdx = 0 ; xdx < 16 ; xdx++) { + for (iCh = 0; iCh < con->ncomp; iCh ++) { + dp[iCh] = (sp[iCh] >> image->shift_bits); + } + dp += con->ncomp; + sp += uExternalNcomp; + } + } + } + else if (con->sf == 3) { /* float */ + for (ydx = 0 ; ydx < 16 ; ydx += 1) { + int *sp = (int*)con->buf + ydx*block_wid + uExternalNcomp*16*mx; + int *dp = data + con->ncomp*16*ydx; + int iCh; + for (xdx = 0 ; xdx < 16 ; xdx++) { + for (iCh = 0; iCh < con->ncomp; iCh ++) { + dp[iCh] = PreScalingBD32F(sp[iCh], image->exp_bias, image->len_mantissa); + } + dp += con->ncomp; + sp += uExternalNcomp; + } + } + } + } +} + +void write_file_YCC(jxr_image_t image, int mx, int my, int* data) +{ + /* There are 3 or 4 buffers, depending on whether there is an alpha channel or not */ + /* Write each individual component to its own file and then concatenate(not interleave these files together */ + + int *dataY = data; + int *dataU = dataY + 256; + int *dataV = dataU + 256; + int *dataA = dataV + 256; + static context *conY = NULL; + static context *conU = NULL; + static context *conV = NULL; + static context *conA = NULL; + context *con = (context*) jxr_get_user_data(image); + + + if (con->file==0) + { + con->alpha = jxr_get_ALPHACHANNEL_FLAG(image); + + conY = (context *)malloc(sizeof(context)); + conU = (context *)malloc(sizeof(context)); + conV = (context *)malloc(sizeof(context)); + if(con->alpha) + conA = (context *)malloc(sizeof(context)); + memcpy(conY, con, sizeof(context)); + memcpy(conU, con, sizeof(context)); + memcpy(conV, con, sizeof(context)); + if(con->alpha) + memcpy(conA, con, sizeof(context)); + conY->name = "Y.raw"; + conU->name = "U.raw"; + conV->name = "V.raw"; + if(con->alpha) + conA->name = "A.raw"; + + con->left_pad = image->window_extra_left; + con->top_pad_remaining = image->window_extra_top; + con->top_pad = image->window_extra_top; + + con->ncomp = conY->ncomp = conU->ncomp = conV->ncomp =1; + if(con->alpha) + conA->ncomp = 1; + start_output_file(con, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conY, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conU, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conV, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + if(con->alpha) + start_output_file(conA, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + + } + + int idx; + int strip_blocks = (image->extended_width)/16; + int dy = 16*strip_blocks; + + if (con->bpi == 8) { + + int xDiv = 16; + int yDiv = 16; + /* Y */ + uint8_t *dp = (uint8_t*)conY->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataY[idx]; + } + + if(isOutputYUV422(image)) + { + dy = 8*strip_blocks; + xDiv = 8; + } + + if(isOutputYUV420(image)) + { + dy = 8*strip_blocks; + xDiv = yDiv = 8; + } + + /* U */ + dp = (uint8_t*)conU->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataU[idx]; + } + /* V */ + dp = (uint8_t*)conV->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataV[idx]; + } + + if(con->alpha) + { + xDiv = yDiv = 16; + dy = 16*strip_blocks; + dp = (uint8_t*)conA->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataA[idx]; + } + } + + } + else if(con->bpi == 16 || con->bpi == 10) { + + int xDiv = 16; + int yDiv = 16; + /* Y */ + uint16_t *dp = (uint16_t*)conY->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataY[idx]; + } + + if(isOutputYUV422(image)) + { + dy = 8*strip_blocks; + xDiv = 8; + } + + if(isOutputYUV420(image)) + { + assert(!"There is no 420 pixel format with bitdepth 16\n"); + dy = 8*strip_blocks; + xDiv = yDiv = 8; + } + + /* U */ + dp = (uint16_t*)conU->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataU[idx]; + } + /* V */ + dp = (uint16_t*)conV->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataV[idx]; + } + + if(con->alpha) + { + xDiv = yDiv = 16; + dy = 16*strip_blocks; + dp = (uint16_t*)conA->buf + xDiv*mx; + for (idx = 0; idx < xDiv*yDiv; idx += 1) { + int dix = (idx/xDiv)*dy + (idx%xDiv); + dp[dix] = dataA[idx]; + } + } + + } + else + { + assert(!"Unsupported bitdepth\n"); + } + + if (mx+1 == strip_blocks) { + + int xDiv = 16; + int yDiv = 16; + int subX = 1; + int subY = 1; + + if(con->bpi == 8) + { + /* Y */ + int left_pad_shift = con->left_pad; + int first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining; + int trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%yDiv : yDiv; + dy = 16*strip_blocks; + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conY->buf + idx*dy + con->left_pad; + write_uint8(conY, dp, conY->wid ); + } + /* U */ + if(isOutputYUV422(image)) + { + dy = 8*strip_blocks; + xDiv = 8; + subX = 2; + left_pad_shift >>= 1; + } + + if(isOutputYUV420(image)) + { + dy = 8*strip_blocks; + xDiv = yDiv = 8; + subX = subY = 2; + left_pad_shift >>= 1; + } + first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining/subY; + trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? ((con->hei + con->top_pad)/subY)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conU->buf + idx*dy + left_pad_shift; + write_uint8(conU, dp, (conU->wid)/subX ); + } + /* V */ + trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? ((con->hei + con->top_pad)/subY)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conV->buf + idx*dy + left_pad_shift; + write_uint8(conV, dp, (conV->wid)/subX ); + } + /* A */ + if(con->alpha) + { + dy = 16*strip_blocks; + xDiv = yDiv = 16; + first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining; + trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conA->buf + idx*dy + con->left_pad; + write_uint8(conA, dp, conA->wid); + } + } + first = (con->top_pad_remaining > 16) ? 16 : con->top_pad_remaining; + con->top_pad_remaining -= first; + } + else if(con->bpi == 16 || con->bpi == 10) + { + /* Y */ + int left_pad_shift = con->left_pad; + int first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining; + int trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%yDiv : yDiv; + dy = 16*strip_blocks; + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conY->buf + idx*dy + con->left_pad; + write_uint16(conY, dp, conY->wid ); + } + /* U */ + if(isOutputYUV422(image)) + { + dy = 8*strip_blocks; + xDiv = 8; + subX = 2; + left_pad_shift >>= 1; + } + + if(isOutputYUV420(image)) + { + dy = 8*strip_blocks; + xDiv = yDiv = 8; + subX = subY = 2; + left_pad_shift >>= 1; + } + first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining/subY; + trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? ((con->hei + con->top_pad)/subY)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conU->buf + idx*dy + left_pad_shift; + write_uint16(conU, dp, (conU->wid)/subX ); + } + /* V */ + first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining/subY; + trans = (my*yDiv + yDiv > (con->hei + con->top_pad)) ? ((con->hei + con->top_pad)/subY)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conV->buf + idx*dy + left_pad_shift; + write_uint16(conV, dp, (conV->wid)/subX ); + } + /* A */ + if(con->alpha) + { + dy = 16*strip_blocks; + xDiv = yDiv = 16; + first = (con->top_pad_remaining > yDiv) ? yDiv : con->top_pad_remaining; + trans = (my*yDiv + yDiv >(con->hei + con->top_pad)) ? (con->hei + con->top_pad)%yDiv : yDiv; + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conA->buf + idx*dy + con->left_pad; + write_uint16(conA, dp, conA->wid); + } + } + first = (con->top_pad_remaining > 16) ? 16 : con->top_pad_remaining; + con->top_pad_remaining -= first; + } + else + assert(!"Unsupported bitdepth\n"); + } + if(my*16 + 16 >= (con->hei + con->top_pad) && mx+1 == strip_blocks) + { + /* End of decode */ + long size = ftell(conY->file); + fseek(conY->file, 0, 0); + long ii; + for(ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conY->file); + fwrite(&val, 1, 1, con->file); + } + size = ftell(conU->file); + fseek(conU->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conU->file); + fwrite(&val, 1, 1, con->file); + } + size = ftell(conV->file); + fseek(conV->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conV->file); + fwrite(&val, 1, 1, con->file); + } + if(con->alpha) + { + size = ftell(conA->file); + fseek(conA->file, 0, 0); + for( ii = 0; ii < size && con->alpha; ii++) + { + uint8_t val; + fread(&val, 1, 1, conA->file); + fwrite(&val, 1, 1, con->file); + } + } + fclose(conY->file); + fclose(conU->file); + fclose(conV->file); + if(con->alpha) + fclose(conA->file); + + free(conY->buf); + free(conU->buf); + free(conV->buf); + if(con->alpha) + free(conA->buf); + + free(conY); + free(conU); + free(conV); + if(con->alpha) + free(conA); + + remove("Y.raw"); + remove("U.raw"); + remove("V.raw"); + if(con->alpha) + remove("A.raw"); + + } +} + +void write_file_CMYK(jxr_image_t image, int mx, int my, int* data) +{ + /* There are 4 or 5 buffers, depending on whether there is an alpha channel or not */ + /* Write each individual component to its own file and then concatenate(not interleave these files together */ + + int *dataC = data; + int *dataM = dataC + 256; + int *dataY = dataM + 256; + int *dataK = dataY + 256; + int *dataA = dataK + 256; + static context *conC = NULL; + static context *conM = NULL; + static context *conY = NULL; + static context *conK = NULL; + static context *conA = NULL; + context *con = (context*) jxr_get_user_data(image); + if (con->file==0) + { + con->alpha = jxr_get_ALPHACHANNEL_FLAG(image); + + conC = (context *)malloc(sizeof(context)); + conM = (context *)malloc(sizeof(context)); + conY = (context *)malloc(sizeof(context)); + conK = (context *)malloc(sizeof(context)); + if(con->alpha) + conA = (context *)malloc(sizeof(context)); + memcpy(conC, con, sizeof(context)); + memcpy(conM, con, sizeof(context)); + memcpy(conY, con, sizeof(context)); + memcpy(conK, con, sizeof(context)); + if(con->alpha) + memcpy(conA, con, sizeof(context)); + conC->name = "C.raw"; + conM->name = "M.raw"; + conY->name = "Y.raw"; + conK->name = "K.raw"; + if(con->alpha) + conA->name = "A.raw"; + + con->left_pad = image->window_extra_left; + con->top_pad_remaining = image->window_extra_top; + con->top_pad = image->window_extra_top; + + con->ncomp = conC->ncomp = conM->ncomp = conY->ncomp = conK->ncomp = 1; + if(con->alpha) + conA->ncomp = 1; + start_output_file(con, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conC, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conM, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conY, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + start_output_file(conK, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + + if(con->alpha) + start_output_file(conA, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + 1 , jxr_get_OUTPUT_BITDEPTH(image),jxr_get_pixel_format(image)); + + } + + int idx; + int strip_blocks = (image->extended_width)/16; + int dy = 16*strip_blocks; + + if (con->bpi == 8) { + + /* C */ + uint8_t *dp = (uint8_t*)conC->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataC[idx]; + } + + /* M */ + dp = (uint8_t*)conM->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataM[idx]; + } + /* Y */ + dp = (uint8_t*)conY->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataY[idx]; + } + /* K */ + dp = (uint8_t*)conK->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataK[idx]; + } + + + if(con->alpha) + { + dp = (uint8_t*)conA->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataA[idx]; + } + } + + } + else if(con->bpi == 16 || con->bpi == 10) { + + /* C */ + uint16_t *dp = (uint16_t*)conC->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataC[idx]; + } + + /* M */ + dp = (uint16_t*)conM->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataM[idx]; + } + /* Y */ + dp = (uint16_t*)conY->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataY[idx]; + } + /* K */ + dp = (uint16_t*)conK->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataK[idx]; + } + + /* A */ + if(con->alpha) + { + dp = (uint16_t*)conA->buf + 16*mx; + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16); + dp[dix] = dataA[idx]; + } + } + } + else + { + assert(!"Unsupported bitdepth\n"); + } + + if (mx+1 == strip_blocks) { + + if(con->bpi == 8) + { + int first = (con->top_pad_remaining > 16) ? 16 : con->top_pad_remaining; + int trans = (my*16 + 16 > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%16 : 16; + + dy = 16*strip_blocks; + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conC->buf + idx*dy + con->left_pad; + write_uint8(conC, dp, conC->wid ); + } + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conM->buf + idx*dy + con->left_pad; + write_uint8(conM, dp, (conM->wid)); + } + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conY->buf + idx*dy + con->left_pad; + write_uint8(conY, dp, (conY->wid)); + } + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conK->buf + idx*dy + con->left_pad; + write_uint8(conK, dp, (conK->wid)); + } + + if(con->alpha) + { + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)conA->buf + idx*dy + con->left_pad; + write_uint8(conA, dp, conA->wid); + } + } + con->top_pad_remaining -= first; + } + else if(con->bpi == 16 || con->bpi == 10) + { + int first = (con->top_pad_remaining > 16) ? 16 : con->top_pad_remaining; + int trans = (my*16 + 16 > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%16 : 16; + dy = 16*strip_blocks; + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conC->buf + idx*dy + con->left_pad; + write_uint16(conC, dp, conC->wid ); + } + + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conM->buf + idx*dy + con->left_pad; + write_uint16(conM, dp, (conM->wid) ); + } + + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conY->buf + idx*dy + con->left_pad; + write_uint16(conY, dp, (conY->wid) ); + } + + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conK->buf + idx*dy + con->left_pad; + write_uint16(conK, dp, (conK->wid) ); + } + + if(con->alpha) + { + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)conA->buf + idx*dy + con->left_pad; + write_uint16(conA, dp, conA->wid); + } + } + con->top_pad_remaining -= first; + } + else + assert(!"Unsupported bitdepth\n"); + } + if(my*16 + 16 >= (con->hei + con->top_pad) && mx+1 == strip_blocks) + { + /* End of decode */ + long size = ftell(conC->file); + long ii; + fseek(conC->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conC->file); + fwrite(&val, 1, 1, con->file); + } + size = ftell(conM->file); + fseek(conM->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conM->file); + fwrite(&val, 1, 1, con->file); + } + size = ftell(conY->file); + fseek(conY->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conY->file); + fwrite(&val, 1, 1, con->file); + } + size = ftell(conK->file); + fseek(conK->file, 0, 0); + for( ii = 0; ii < size; ii++) + { + uint8_t val; + fread(&val, 1, 1, conK->file); + fwrite(&val, 1, 1, con->file); + } + if(con->alpha) + { + size = ftell(conA->file); + fseek(conA->file, 0, 0); + for( ii = 0; ii < size && con->alpha; ii++) + { + uint8_t val; + fread(&val, 1, 1, conA->file); + fwrite(&val, 1, 1, con->file); + } + } + fclose(conC->file); + fclose(conM->file); + fclose(conY->file); + fclose(conK->file); + if(con->alpha) + fclose(conA->file); + + free(conC->buf); + free(conM->buf); + free(conY->buf); + free(conK->buf); + if(con->alpha) + free(conA->buf); + + free(conC); + free(conM); + free(conY); + free(conK); + if(con->alpha) + free(conA); + + remove("C.raw"); + remove("M.raw"); + remove("Y.raw"); + remove("K.raw"); + if(con->alpha) + remove("A.raw"); + } +} + +void write_file(jxr_image_t image, int mx, int my, int*data) +{ + context *con = (context*) jxr_get_user_data(image); + + if((isOutputYUV444(image) || isOutputYUV422(image) || isOutputYUV420(image)) && jxr_get_IMAGE_CHANNELS(image) == 3) + { + /* Use special YCC format only for primary image */ + write_file_YCC(image, mx, my, data); + return; + } + else if(isOutputCMYKDirect(image) && jxr_get_IMAGE_CHANNELS(image) == 4) + { + /* Use special YCC format only for primary image */ + write_file_CMYK(image, mx, my, data); + return; + } + + if (con->file==0) + { + int channels = jxr_get_IMAGE_CHANNELS(image); + if( channels == 3) + set_bgr_flag(con, image); + else + con->isBgr = 0; + + if(jxr_get_pixel_format(image) == JXRC_FMT_32bppRGBE) + { + channels++; + } + + set_pad_bytes(con, image); + + con->left_pad = image->window_extra_left; + con->top_pad_remaining = image->window_extra_top; + con->top_pad = image->window_extra_top; + + con->alpha = jxr_get_ALPHACHANNEL_FLAG(image); + if (con->alpha) /* with alpha channel */ + channels ++; + + start_output_file(con, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + channels, jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + } + + int idx, jdx; + int strip_blocks = (image->extended_width)/16; + int dy = 16*con->ncomp*strip_blocks; + if(con->padBytes !=0) + dy = dy+16*strip_blocks; + if (con->bpi == 1 || con->bpi == 5 || con->bpi == 6 || con->bpi == 8) { + uint8_t *dp = (uint8_t*)con->buf + 16*con->ncomp*mx; + if(con->padBytes != 0) + { + dp = dp + 16*mx; /* Add padding channel offset */ + } + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16)*con->ncomp; + if(con->padBytes) + dix +=(idx%16); + int six = idx*con->ncomp; + int pl; + for (pl = 0 ; pl < con->ncomp ; pl += 1) + dp[dix + pl] = data[six + pl]; + if(con->padBytes != 0) + dp[dix + pl] = 0; /* Padding data after all n channels */ + if(con->isBgr) + switch_r_b(dp+dix, con->bpi); + } + } + else if(con->bpi == 10 || con->bpi == 16){ + uint16_t *dp = (uint16_t*)con->buf + 16*con->ncomp*mx; + if(con->padBytes != 0) + { + dp = dp + 16*mx; /* Add padding channel offset */ + } + + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16)*con->ncomp; + if(con->padBytes) + dix +=(idx%16); + int six = idx*con->ncomp; + int pl; + for (pl = 0 ; pl < con->ncomp ; pl += 1) + dp[dix + pl] = data[six + pl]; + if(con->padBytes != 0) + dp[dix + pl] = 0; /* Padding data after all n channels */ + if(con->isBgr) + switch_r_b(dp + dix, con->bpi); + } + } + else if(con->bpi ==32) { + uint32_t *dp = (uint32_t*)con->buf + 16*con->ncomp*mx; + if(con->padBytes != 0) + { + dp = dp + 16*mx; /* Add padding channel offset */ + } + for (idx = 0; idx < 256; idx += 1) { + int dix = (idx/16)*dy + (idx%16)*con->ncomp; + if(con->padBytes) + dix +=(idx%16); + int six = idx*con->ncomp; + int pl; + for (pl = 0 ; pl < con->ncomp ; pl += 1) + dp[dix + pl] = data[six + pl]; + if(con->padBytes != 0) + dp[dix + pl] = 0; /* Padding data after all n channels */ + if(con->isBgr) + switch_r_b(dp + dix, con->bpi); + } + } + else + { + assert(!"Unsupported bitdepth\n"); + } + + if (mx+1 == strip_blocks) { + int first = (con->top_pad_remaining > 16) ? 16 : con->top_pad_remaining; + con->top_pad_remaining -= first; /* skip the padding rows */ + int trans = (my*16 + 16 > (con->hei + con->top_pad)) ? (con->hei + con->top_pad)%16 : 16; + if(con->bpi == 1) + { + /* ClipAndPackBD1BorW */ + /* Clipping is already handled in scale_and_emit_top, so just pack */ + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)con->buf + idx*dy; + for(jdx = con->left_pad; jdx < (con->wid + con->left_pad); jdx = jdx + 8) + { + uint8_t buff[8]; + uint8_t iResult = 0; + int end = jdx + 8 > con->wid? con->wid:jdx + 8; + memset(buff, 0, 8 * sizeof(uint8_t)); + memcpy(buff, dp+jdx, (end-jdx) * sizeof(uint8_t)); + if (jxr_get_OUTPUT_BITDEPTH(image) == JXR_BD1BLACK1) + { + iResult = (1-buff[7]) + ((1 - buff[6]) << 1) + ((1 - buff[5]) << 2) + + ((1 - buff[4]) << 3) + ((1 - buff[3]) << 4) + ((1 - buff[2]) << 5) + + ((1 - buff[1]) << 6) + ((1 - buff[0]) << 7); + } + else/* jxr_output_bitdepth(image) = = BD1WHITE1 */ + { + iResult = buff[7] + (buff[6] << 1) + (buff[5] << 2) + + (buff[4] << 3) + (buff[3] << 4) + (buff[2] << 5) + + (buff[1] << 6) + (buff[0] << 7); + } + + write_uint8(con, &iResult,1 ); + } + } + } + else if(con->bpi == 5) + { + /* ClipAndPack555 */ + /* Clipping is already handled in scale_and_emit_top, so just pack */ + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)con->buf + idx*dy; + assert(con->ncomp == 3); + for(jdx = con->left_pad*con->ncomp; jdx < (con->wid + con->left_pad)*con->ncomp; jdx = jdx + con->ncomp) + { + uint16_t iResult = 0; + iResult = (uint16_t)dp[jdx] + (((uint16_t)dp[jdx + 1])<<5) + (((uint16_t)dp[jdx + 2])<<10); + write_uint16(con, &iResult,1 ); + } + } + } + else if(con->bpi == 6) + { + /* ClipAndPack565 */ + /* Clipping is already handled in scale_and_emit_top, so just pack */ + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)con->buf + idx*dy; + assert(con->ncomp == 3); + for(jdx = con->left_pad*con->ncomp; jdx < (con->wid + con->left_pad)*con->ncomp; jdx = jdx + con->ncomp) + { + uint16_t iResult = 0; + iResult = (uint16_t)dp[jdx] + (((uint16_t)dp[jdx + 1])<<5) + (((uint16_t)dp[jdx + 2])<<11); + write_uint16(con, &iResult,1 ); + } + } + } + else if (con->bpi==8) + for (idx = first; idx < trans; idx += 1) { + uint8_t *dp = (uint8_t*)con->buf + idx*dy + con->left_pad*con->ncomp; + int padComp = con->ncomp; + if(con->padBytes != 0 ) + padComp ++; + write_uint8(con, dp, con->wid*padComp); } + else if(con->bpi == 10 && con->ncomp == 3) + { + /* ClipAndPack10 */ + /* Clipping is already handled in scale_and_emit_top, so just pack */ + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)con->buf + idx*dy; + for(jdx = con->left_pad*con->ncomp; jdx < (con->wid + con->left_pad)*con->ncomp; jdx = jdx + con->ncomp) + { + uint32_t iResult = 0; + iResult = (uint32_t)dp[jdx] + (((uint32_t)dp[jdx + 1])<<10) + (((uint32_t)dp[jdx + 2])<<20); + write_uint32(con, &iResult,1 ); + } + } + } + else if(con->bpi == 10 && con->ncomp == 1)/*Alpha image decoding for JXR_30bppYCC422Alpha JXR_40bppYCC4444Alpha */ + { + /* ClipAndPack10 */ + /* Clipping is already handled in scale_and_emit_top, so just pack */ + for (idx = 0; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)con->buf + idx*dy; + for(jdx = con->left_pad*con->ncomp; jdx < (con->wid + con->left_pad)*con->ncomp; jdx = jdx + con->ncomp) + { + uint16_t iResult = 0; + iResult = (uint16_t)dp[jdx]; + write_uint16(con, &iResult,1 ); + } + } + } + else if(con->bpi==16) + for (idx = first; idx < trans; idx += 1) { + uint16_t *dp = (uint16_t*)con->buf + idx*dy + con->left_pad*con->ncomp; /* dy already contains offset for padding data */ + int padComp = con->ncomp; + if(con->padBytes != 0 ) + padComp ++; + write_uint16(con, dp, con->wid*padComp ); + } + else if(con->bpi == 32) + for (idx = first; idx < trans; idx += 1) { + uint32_t *dp = (uint32_t*)con->buf + idx*dy + con->left_pad*con->ncomp; + int padComp = con->ncomp; + if(con->padBytes != 0 ) + padComp ++; + write_uint32(con, dp, con->wid*padComp ); + } + else + assert(!"Unsupported bitdepth\n"); + } +} + + +void concatenate_primary_alpha(jxr_image_t image, FILE *fpPrimary, FILE *fpAlpha) +{ + context *con = (context*) jxr_get_user_data(image); + if (con->file==0) + { + set_pad_bytes(con, image); + /* Add 1 to number of channels for alpha */ + con->alpha = 1; + start_output_file(con, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + jxr_get_IMAGE_CHANNELS(image) + 1, jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + } + fseek(fpPrimary, 0, SEEK_END); + long size = ftell(fpPrimary); + fseek(fpPrimary, 0, SEEK_SET); + long i; + for(i = 0; i < size; i++) + { + uint8_t val; + fread(&val, 1, 1, fpPrimary); + fwrite(&val, 1, 1, con->file); + } + fseek(fpAlpha, 0, SEEK_END); + size = ftell(fpAlpha); + fseek(fpAlpha, 0, SEEK_SET); + for(i = 0; i < size; i++) + { + uint8_t val; + fread(&val, 1, 1, fpAlpha); + fwrite(&val, 1, 1, con->file); + } +} + + + +void write_file_combine_primary_alpha(jxr_image_t image, FILE *fpPrimary, FILE *fpAlpha) +{ + context *con = (context*) jxr_get_user_data(image); + int i; + + if(isOutputYUV444(image) || isOutputYUV422(image) || isOutputYUV420(image) || isOutputCMYKDirect(image)) + { + concatenate_primary_alpha(image, fpPrimary, fpAlpha); + return; + } + if (con->file==0) + { + set_pad_bytes(con, image); + /* Add 1 to number of channels for alpha */ + con->alpha = 1; + start_output_file(con, jxr_get_EXTENDED_IMAGE_WIDTH(image), jxr_get_EXTENDED_IMAGE_HEIGHT(image), + jxr_get_IMAGE_WIDTH(image), jxr_get_IMAGE_HEIGHT(image), + jxr_get_IMAGE_CHANNELS(image) + 1, jxr_get_OUTPUT_BITDEPTH(image), jxr_get_pixel_format(image)); + } + int numPixels = jxr_get_IMAGE_WIDTH(image) * jxr_get_IMAGE_HEIGHT(image); + int nPrimaryComp = jxr_get_IMAGE_CHANNELS(image); + if(con->padBytes) + nPrimaryComp ++; + if (con->bpi == 8) { + for (i=0; i<numPixels; i++) { + unsigned char combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + fread(&combine[0],sizeof(char),nPrimaryComp, fpPrimary); + fread(&(combine[nPrimaryComp]),sizeof(char), 1,fpAlpha); + write_uint8(con, combine, nPrimaryComp+1); + } + } + else if(con->bpi == 16) + { + for (i=0; i<numPixels; i++) { + uint16_t combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + fread(&combine[0],sizeof(uint16_t),nPrimaryComp, fpPrimary); + fread(&(combine[nPrimaryComp]),sizeof(uint16_t), 1,fpAlpha); + write_uint16(con, combine, nPrimaryComp+1); + } + } + else if(con->bpi == 32) + { + for (i=0; i<numPixels; i++) { + uint32_t combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + fread(&combine[0],sizeof(uint32_t),nPrimaryComp, fpPrimary); + fread(&(combine[nPrimaryComp]),sizeof(uint32_t), 1,fpAlpha); + write_uint32(con, combine,nPrimaryComp+1); + } + } + else + assert(!"Unsupported bitdepth\n"); +} + + +void split_primary_alpha(jxr_image_t image,void *input_handle, context *con_primary, context *con_alpha, jxr_container_t container) +{ + /* Used for YCCA and CMYKA */ + int wid, hei, ncomp, bpi; + short sf, photometric; + int padBytes; + + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + int numPixels = wid * hei; + int nPrimaryComp = ncomp-1; + context *con = (context *)input_handle; + read_setup(con); + + int i; + + start_output_file(con_primary, wid, hei, wid, hei, con_primary->ncomp, jxr_get_OUTPUT_BITDEPTH(image), jxrc_get_pixel_format(container)); + start_output_file(con_alpha, wid, hei, wid, hei, con_alpha->ncomp, jxr_get_OUTPUT_BITDEPTH(image), jxrc_get_pixel_format(container)); + + if(isOutputYUV444(image) || isOutputYUV422(image) || isOutputYUV420(image) || isOutputCMYKDirect(image)) + { + //16 * (con->ncomp + con->padBytes) * ((con->bpi+7)/8) * ((con->wid+15)&~15); + unsigned bytes = (con->bpi+7)/8; + unsigned size_luma = numPixels * bytes; + unsigned size_chroma = size_luma; + if (isOutputYUV422(image)) + size_chroma >>= 1; + if (isOutputYUV420(image)) + size_chroma >>= 2; + + uint8_t * combine = 0; + combine = (uint8_t*)malloc(size_luma); + assert(combine != 0); + + read_uint8(con, combine, size_luma); + write_uint8(con_primary, combine, size_luma); + + for (i = 1; i < nPrimaryComp; i++) { + read_uint8(con, combine, size_chroma); + write_uint8(con_primary, combine, size_chroma); + } + + read_uint8(con, combine, size_luma); + write_uint8(con_alpha, combine, size_luma); + + free(combine); + } + else + { + for (i=0; i<numPixels; i++) + { + if (con->bpi == 8) { + + unsigned char combine[MAX_CHANNELS + 1];/*+ 1 for padded channel */ + read_uint8(con, &combine[0],nPrimaryComp); + write_uint8(con_primary, combine, nPrimaryComp); + + } + else if(con->bpi == 16) + { + + uint16_t combine[MAX_CHANNELS + 1];/*+ 1 for padded channel */ + read_uint16(con, &combine[0],nPrimaryComp); + write_uint16(con_primary, combine, nPrimaryComp); + + } + else if(con->bpi == 32) + { + + uint32_t combine[MAX_CHANNELS + 1];/*+ 1 for padded channel */ + read_uint32(con, &combine[0],nPrimaryComp); + write_uint32(con_primary, combine, nPrimaryComp); + + } + else + assert(!"Unsupported bitdepth\n"); + } + for (i=0; i<numPixels; i++) + { + if (con->bpi == 8) { + + unsigned char combine[1]; + read_uint8(con, &combine[0],1); + write_uint8(con_alpha, combine, 1); + + } + else if(con->bpi == 16) + { + + uint16_t combine[1]; + read_uint16(con, &combine[0],1); + write_uint16(con_alpha, combine, 1); + + } + else if(con->bpi == 32) + { + + uint32_t combine[1]; + read_uint32(con, &combine[0],1); + write_uint32(con_alpha, combine, 1); + + } + else + assert(!"Unsupported bitdepth\n"); + } + } + close_file(con_primary); + close_file(con_alpha); +} + + +void separate_primary_alpha(jxr_image_t image, void *input_handle, char *path_out, char * path_primary, char *path_alpha, jxr_container_t container) +{ + + context *con; + + int i; + int wid, hei, ncomp, bpi; + short sf, photometric; + int padBytes; + + con = (context *)input_handle; + read_setup(con); + + + context *con_primary = (context *)malloc(sizeof(context)); + assert(con_primary != NULL); + context *con_alpha = (context *)malloc(sizeof(context)); + assert(con_alpha != NULL); + + memcpy(con_primary, con, sizeof(*con)); + memcpy(con_alpha, con, sizeof(*con)); + con_primary->alpha = con_alpha->alpha = 0; + con_primary->buf = con_alpha->buf = 0; + con_primary->ncomp = con->ncomp - 1; + con_alpha->ncomp = 1; + + get_file_parameters(con, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + + const char *p = strrchr(con->name, '.'); + if (p==0) + error("output file name %s needs a suffix to determine its format", con->name); + if (!strcasecmp(p, ".pnm") || !strcasecmp(p, ".pgm") || !strcasecmp(p, ".ppm")) + { + error("Alpha channel not supported by PNM, PGM and PPM"); + } + else if (!strcasecmp(p, ".tif")) + { + strcpy(path_primary, path_out); + strcat(path_primary, "_input_primary.tif"); + strcpy(path_alpha, path_out); + strcat(path_alpha, "_input_alpha.tif"); + + } + else if (!strcasecmp(p, ".raw")) + { + strcpy(path_primary, path_out); + strcat(path_primary, "_input_primary.raw"); + strcpy(path_alpha, path_out); + strcat(path_alpha, "_input_alpha.raw"); + } + else error("unrecognized suffix on output file name %s", con->name); + + con_primary->name = path_primary; + con_alpha->name = path_alpha; + + + if(isOutputYUV444(image) || isOutputYUV422(image) || isOutputYUV420(image) || isOutputCMYKDirect(image)) + { + split_primary_alpha(image, input_handle,con_primary, con_alpha, container); + return; + } + + start_output_file(con_primary, wid, hei, wid, hei, con_primary->ncomp, jxr_get_OUTPUT_BITDEPTH(image), jxrc_get_pixel_format(container)); + start_output_file(con_alpha, wid, hei, wid, hei, con_alpha->ncomp, jxr_get_OUTPUT_BITDEPTH(image), jxrc_get_pixel_format(container)); + + int numPixels = wid * hei; + int nPrimaryComp = ncomp-1; + + if (con->bpi == 8) { + for (i=0; i<numPixels; i++) { + unsigned char combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + read_uint8(con, &combine[0],ncomp); + write_uint8(con_primary, combine, nPrimaryComp); + write_uint8(con_alpha, &(combine[nPrimaryComp]), 1); + + } + } + else if(con->bpi == 16) + { + for (i=0; i<numPixels; i++) { + uint16_t combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + read_uint16(con, &combine[0],ncomp); + write_uint16(con_primary, combine, nPrimaryComp); + write_uint16(con_alpha, &(combine[nPrimaryComp]), 1); + } + } + else if(con->bpi == 32) + { + for (i=0; i<numPixels; i++) { + uint32_t combine[MAX_CHANNELS + 1 + 1];/* +1 for alpha + 1 for padded channel */ + read_uint32(con, &combine[0],ncomp); + write_uint32(con_primary, combine, nPrimaryComp); + write_uint32(con_alpha, &(combine[nPrimaryComp]), 1); + } + } + else + assert(!"Unsupported bitdepth\n"); + close_file(con_primary); + close_file(con_alpha); +} + +/* +* $Log: file.c,v $ +* Revision 1.17 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.16 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.15 2008/03/17 23:34:54 steve +* Support output of CMYK TIFF images. +* +* Revision 1.14 2008/03/06 09:33:47 rick +* Add support for reading multi-strip TIFF files; fix TIFF reader bug. +* +* Revision 1.13 2008/03/05 19:32:02 gus +* *** empty log message *** +* +* Revision 1.12 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.11 2008/03/03 03:16:18 rick +* Re-implement BDx to bpi mapping. +* +* Revision 1.10 2008/03/03 01:57:34 steve +* Fix BDx to bpi mapping. +* +* Revision 1.9 2008/03/03 01:51:40 rick +* Allow output file depths other than 8. +* +* Revision 1.8 2008/02/29 01:03:31 steve +* MSC doesnt have strcasecmp. Use stricmp instead. +* +* Revision 1.7 2008/02/29 00:45:21 steve +* Portability, esp w/ C++ compilers. +* +* Revision 1.6 2008/02/27 06:15:49 rick +* Replace macro ASSERT, which had optional arguments. +* +* Revision 1.5 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.4 2008/02/26 23:44:25 steve +* Handle the special case of compiling via MS C. +* +* Revision 1.3 2008/02/23 08:45:07 rick +* Changed some types to avoid compiler warnings. +* +* Revision 1.2 2008/01/31 23:20:14 rick +* Fix bug in read_file() affecting color input images. +* +* Revision 1.1 2008/01/19 02:30:46 rick +* Re-implement and extend file interface. +* +*/ + diff --git a/jpegxr/file.h b/jpegxr/file.h new file mode 100644 index 000000000..dbed9479e --- /dev/null +++ b/jpegxr/file.h @@ -0,0 +1,72 @@ +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: file.h,v 1.2 2008/02/26 23:52:44 steve Exp $") +#else +#ident "$Id: file.h,v 1.2 2008/02/26 23:52:44 steve Exp $" +#endif + +void *open_input_file(const char *name, const raw_info *raw_info_t, int *alpha_mode, int *padded_format); +void *open_output_file(const char *name); +void get_file_parameters(void *handle, int *wid, int *hei, int *ncomp, int *bpi, short *sf, short *photometric, int *padBytes); +void read_file(jxr_image_t image, int mx, int my, int *data); +void write_file(jxr_image_t image, int mx, int my, int *data); +void write_file_combine_primary_alpha(jxr_image_t image, FILE *fpPrimary, FILE *fpAlpha); +void separate_primary_alpha(jxr_image_t image, void *input_handle, char *path_out, char * path_primary, char *path_alpha, jxr_container_t container); +void close_file(void *handle); +void set_ncomp(void *input_handle, int ncomp); + +/* +* $Log: file.h,v $ +* Revision 1.4 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.3 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.2 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.1 2008/01/19 02:30:46 rick +* Re-implement and extend file interface. +* +*/ + diff --git a/jpegxr/flags.c b/jpegxr/flags.c new file mode 100644 index 000000000..dbdec7630 --- /dev/null +++ b/jpegxr/flags.c @@ -0,0 +1,155 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: flags.c,v 1.5 2008/03/06 02:05:48 steve Exp $") +#else +#ident "$Id: flags.c,v 1.5 2008/03/06 02:05:48 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + +unsigned jxr_get_IMAGE_WIDTH(jxr_image_t image) +{ + return image->width1 + 1; +} + +unsigned jxr_get_IMAGE_HEIGHT(jxr_image_t image) +{ + return image->height1 + 1; +} + +unsigned jxr_get_EXTENDED_IMAGE_WIDTH(jxr_image_t image) +{ + return image->extended_width; +} + +unsigned jxr_get_EXTENDED_IMAGE_HEIGHT(jxr_image_t image) +{ + return image->extended_height; +} + +int jxr_get_TILING_FLAG(jxr_image_t image) +{ + if (TILING_FLAG(image)) + return 1; + else + return 0; +} + +unsigned jxr_get_TILE_COLUMNS(jxr_image_t image) +{ + return image->tile_columns + 1; +} + +unsigned jxr_get_TILE_ROWS(jxr_image_t image) +{ + return image->tile_rows + 1; +} + +int jxr_get_TILE_WIDTH(jxr_image_t image, unsigned column) +{ + if (column > image->tile_columns) { + return 0; + } else if (column == image->tile_columns) { + if (column == 0) + return EXTENDED_WIDTH_BLOCKS(image); + else + return EXTENDED_WIDTH_BLOCKS(image) - image->tile_column_position[column-1]; + } else { + return image->tile_column_width[column]; + } +} + +int jxr_get_TILE_HEIGHT(jxr_image_t image, unsigned row) +{ + if (row > image->tile_rows) { + return 0; + } else if (row == image->tile_rows) { + if (row == 0) + return EXTENDED_HEIGHT_BLOCKS(image); + else + return EXTENDED_HEIGHT_BLOCKS(image) - image->tile_row_position[row-1]; + } else { + return image->tile_row_height[row]; + } +} + +int jxr_get_ALPHACHANNEL_FLAG(jxr_image_t image) +{ + if (ALPHACHANNEL_FLAG(image)) + return 1; + else + return 0; +} + +jxrc_t_pixelFormat jxr_get_pixel_format(jxr_image_t image) +{ + return image->ePixelFormat; +} + +/* +* $Log: flags.c,v $ +* +* Revision 1.7 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.6 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.5 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.4 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.3 2008/02/26 23:28:53 steve +* Remove C99 requirements from the API. +* +* Revision 1.2 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/init.c b/jpegxr/init.c new file mode 100644 index 000000000..6123070a8 --- /dev/null +++ b/jpegxr/init.c @@ -0,0 +1,504 @@ + + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: init.c,v 1.23 2008/03/13 21:23:27 steve Exp $") +#else +#ident "$Id: init.c,v 1.23 2008/03/13 21:23:27 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <assert.h> + +const int _jxr_abslevel_index_delta[7] = { 1, 0, -1, -1, -1, -1, -1 }; + +static void clear_vlc_tables(jxr_image_t image) +{ + int idx; + for (idx = 0 ; idx < AbsLevelInd_COUNT ; idx += 1) { + image->vlc_table[idx].discriminant = 0; + image->vlc_table[idx].discriminant2 = 0; + image->vlc_table[idx].table = 0; + image->vlc_table[idx].deltatable = 0; + image->vlc_table[idx].delta2table = 0; + } +} + +static struct jxr_image* __make_jxr(void) +{ + struct jxr_image*image = (struct jxr_image*) calloc(1, sizeof(struct jxr_image)); + int idx; + image->user_flags = 0; + image->width1 = 0; + image->height1 = 0; + image->extended_width = 0; + image->extended_height = 0; + image->header_flags1 = 0; + image->header_flags2 = 0x80; /* SHORT_HEADER_FLAG=1 */ + image->header_flags_fmt = 0; + image->bands_present = 0; /* Default ALL bands present */ + image->num_channels = 0; + image->tile_index_table = 0; + image->tile_index_table_length = 0; + image->primary = 1; + + clear_vlc_tables(image); + + for (idx = 0 ; idx < MAX_CHANNELS ; idx += 1) { + image->strip[idx].up4 = 0; + image->strip[idx].up3 = 0; + image->strip[idx].up2 = 0; + image->strip[idx].up1 = 0; + image->strip[idx].cur = 0; + } + + image->scaled_flag = 1; + + image->out_fun = 0; + + return image; +} + +static void make_mb_row_buffer(jxr_image_t image, unsigned use_height) +{ + size_t block_count = EXTENDED_WIDTH_BLOCKS(image) * use_height; + int*data, *pred_dclp; + size_t idx; + int format_scale; + int ch; + + image->mb_row_buffer[0] = (struct macroblock_s*) calloc(block_count, sizeof(struct macroblock_s)); + data = (int*) calloc(block_count*256, sizeof(int)); + pred_dclp = (int*) calloc(block_count*7, sizeof(int)); + assert(image->mb_row_buffer[0]); + assert(data); + assert(pred_dclp); + + for (idx = 0 ; idx < block_count ; idx += 1) { + image->mb_row_buffer[0][idx].data = data + 256*idx; + /* 7 (used as mutilpier) = 1 DC + 3 top LP + 3 left LP coefficients used for prediction */ + image->mb_row_buffer[0][idx].pred_dclp = pred_dclp + 7*idx; + } + + format_scale = 256; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + image->mb_row_buffer[ch] = (struct macroblock_s*) calloc(block_count, sizeof(struct macroblock_s)); + data = (int*) calloc(block_count*format_scale, sizeof(int)); + pred_dclp = (int*) calloc(block_count*7, sizeof(int)); + assert(image->mb_row_buffer[ch]); + assert(data); + assert(pred_dclp); + + for (idx = 0 ; idx < block_count ; idx += 1) { + image->mb_row_buffer[ch][idx].data = data + format_scale*idx; + image->mb_row_buffer[ch][idx].pred_dclp = pred_dclp + 7*idx; + } + } +} + +/* +* Allocate the macroblock strip store. Each macroblock points to 256 +* values that are either the 256 pixel values, or the DC, LP and HP +* coefficients. +* +* DC/LP/HP arrangement - +* The first word is the DC. +* The next 15 are the LP coefficients. +* The remaining 240 are HP coefficients. +*/ +void _jxr_make_mbstore(jxr_image_t image, int up4_flag) +{ + int ch; + + assert(image->strip[0].up4 == 0); + assert(image->strip[0].up3 == 0); + assert(image->strip[0].up2 == 0); + assert(image->strip[0].up1 == 0); + assert(image->strip[0].cur == 0); + + assert(image->num_channels > 0); + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + unsigned idx; + if (up4_flag) + image->strip[ch].up4 = (struct macroblock_s*) + calloc(EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + image->strip[ch].up3 = (struct macroblock_s*) + calloc(EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + image->strip[ch].up2 = (struct macroblock_s*) + calloc(EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + image->strip[ch].up1 = (struct macroblock_s*) + calloc(EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + image->strip[ch].cur = (struct macroblock_s*) + calloc(EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + + if (up4_flag) { + image->strip[ch].up4[0].data = (int*)calloc(256 * EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up4[idx].data = image->strip[ch].up4[idx-1].data + 256; + } + image->strip[ch].up3[0].data = (int*)calloc(256 * EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up3[idx].data = image->strip[ch].up3[idx-1].data + 256; + + image->strip[ch].up2[0].data = (int*)calloc(256 * EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up2[idx].data = image->strip[ch].up2[idx-1].data + 256; + + image->strip[ch].up1[0].data = (int*)calloc(256 * EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up1[idx].data = image->strip[ch].up1[idx-1].data + 256; + + image->strip[ch].cur[0].data = (int*)calloc(256 * EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].cur[idx].data = image->strip[ch].cur[idx-1].data + 256; + + if (up4_flag) { + image->strip[ch].up4[0].pred_dclp = (int*)calloc(7*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up4[idx].pred_dclp = image->strip[ch].up4[idx-1].pred_dclp + 7; + } + + image->strip[ch].up3[0].pred_dclp = (int*)calloc(7*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up3[idx].pred_dclp = image->strip[ch].up3[idx-1].pred_dclp + 7; + + image->strip[ch].up2[0].pred_dclp = (int*)calloc(7*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up2[idx].pred_dclp = image->strip[ch].up2[idx-1].pred_dclp + 7; + + image->strip[ch].up1[0].pred_dclp = (int*)calloc(7*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].up1[idx].pred_dclp = image->strip[ch].up1[idx-1].pred_dclp + 7; + + image->strip[ch].cur[0].pred_dclp = (int*)calloc(7*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + for (idx = 1 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->strip[ch].cur[idx].pred_dclp = image->strip[ch].cur[idx-1].pred_dclp + 7; + + if(ch!= 0) + { + if(image->use_clr_fmt == 2 || image->use_clr_fmt == 1) /* 422 or 420 */ + image->strip[ch].upsample_memory_x = (int*)calloc(16, sizeof(int)); + + if(image->use_clr_fmt == 1)/* 420 */ + image->strip[ch].upsample_memory_y = (int*)calloc(8*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + } + + } + + /* If there is tiling (in columns) then allocate a tile buffer + that can hold an entire row of tiles. */ + if (FREQUENCY_MODE_CODESTREAM_FLAG(image)) { /* FREQUENCY MODE */ + + make_mb_row_buffer(image, EXTENDED_HEIGHT_BLOCKS(image)); + + } else { /* SPATIAL */ + if (INDEXTABLE_PRESENT_FLAG(image)) { + /* This means that the tiling flag is used */ + unsigned max_tile_height = 0; + unsigned idx; + int format_scale; + int ch; + for (idx = 0 ; idx < image->tile_rows ; idx += 1) { + if (image->tile_row_height[idx] > max_tile_height) + max_tile_height = image->tile_row_height[idx]; + } + + make_mb_row_buffer(image, max_tile_height); + + /* Save enough context MBs for 4 rows of + macroblocks. */ + + format_scale = 256; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int count = (ch==0)? 256 : format_scale; + image->mb_row_context[ch] = (struct macroblock_s*) + calloc(4*EXTENDED_WIDTH_BLOCKS(image), sizeof(struct macroblock_s)); + image->mb_row_context[ch][0].data = (int*) + calloc(4*EXTENDED_WIDTH_BLOCKS(image)*count, sizeof(int)); + for (idx = 1 ; idx < 4*EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) + image->mb_row_context[ch][idx].data = image->mb_row_context[ch][idx-1].data+count; + } + + } + } + + /* since CBP processing is done at each row, need to save contexts is multiple tile columns */ + image->model_hp_buffer = 0; + image->hp_cbp_model_buffer = 0; + if (image->tile_columns > 1) { + image->model_hp_buffer = (struct model_s*) + calloc(image->tile_columns, sizeof(struct model_s)); + image->hp_cbp_model_buffer = (struct cbp_model_s*) + calloc(image->tile_columns, sizeof(struct cbp_model_s)); + } + + image->cur_my = -1; +} + +jxr_image_t jxr_create_input(void) +{ + struct jxr_image*image = __make_jxr(); + + return image; +} + +jxr_image_t jxr_create_image(int width, int height, unsigned char * windowing) +{ + struct jxr_image*image = __make_jxr(); + + if (width == 0 || height == 0) + return 0; + + image = __make_jxr(); + + if (windowing[0] == 1) { + assert(((width+windowing[2]+windowing[4]) & 0x0f) == 0); + assert(((height+windowing[1]+windowing[3]) & 0x0f) == 0); + } + else { + windowing[1] = windowing[2] = 0; + windowing[3] = (((height + 15) >> 4) << 4) - height; + windowing[4] = (((width + 15) >> 4) << 4) - width; + } + + image->width1 = width-1; + image->height1 = height-1; + image->extended_width = image->width1 + 1 + windowing[2] + windowing[4]; + image->extended_height = image->height1 + 1 + windowing[1] + windowing[3]; + + image->dc_frame_uniform = 1; + image->lp_frame_uniform = 1; + image->lp_use_dc_qp = 0; + image->num_lp_qps = 1; + image->hp_use_lp_qp = 0; + image->hp_frame_uniform = 1; + image->num_hp_qps = 1; + + image->window_extra_top = windowing[1]; + image->window_extra_left = windowing[2]; + image->window_extra_bottom = windowing[3]; + image->window_extra_right = windowing[4]; + + return image; +} + +void jxr_flag_SKIP_HP_DATA(jxr_image_t image, int flag) +{ + if (flag) + image->user_flags |= 0x0001; + else + image->user_flags &= ~0x0001; +} + +void jxr_flag_SKIP_FLEX_DATA(jxr_image_t image, int flag) +{ + if (flag) + image->user_flags |= 0x0002; + else + image->user_flags &= ~0x0002; +} + +void jxr_destroy(jxr_image_t image) +{ + int idx, plane_idx = 1; + if(image == NULL) + return; + + if (ALPHACHANNEL_FLAG(image)) + plane_idx = 2; + + for (; plane_idx > 0; plane_idx --) { + jxr_image_t plane = (plane_idx == 1 ? image : image->alpha); + + for (idx = 0 ; idx < plane->num_channels ; idx += 1) { + if (plane->strip[idx].up4) { + free(plane->strip[idx].up4[0].data); + free(plane->strip[idx].up4); + } + if (plane->strip[idx].up3) { + free(plane->strip[idx].up3[0].data); + free(plane->strip[idx].up3); + } + if (plane->strip[idx].up2) { + free(plane->strip[idx].up2[0].data); + free(plane->strip[idx].up2); + } + if (plane->strip[idx].up1) { + free(plane->strip[idx].up1[0].data); + free(plane->strip[idx].up1); + } + if (plane->strip[idx].cur) { + free(plane->strip[idx].cur[0].data); + free(plane->strip[idx].cur); + } + if(plane->strip[idx].upsample_memory_x) + free(plane->strip[idx].upsample_memory_x); + if(plane->strip[idx].upsample_memory_y) + free(plane->strip[idx].upsample_memory_y); + + } + + for (idx = 0 ; idx < plane->num_channels ; idx += 1) { + if (plane->mb_row_buffer[idx]) { + free(plane->mb_row_buffer[idx][0].data); + free(plane->mb_row_buffer[idx]); + } + + if (plane->mb_row_context[idx]) { + free(plane->mb_row_context[idx][0].data); + free(plane->mb_row_context[idx]); + } + } + + if (plane->model_hp_buffer) { + free(plane->model_hp_buffer); + } + + if (plane->hp_cbp_model_buffer) { + free(plane->hp_cbp_model_buffer); + } + + if(plane_idx == 1){ + if (plane->tile_index_table) + free(plane->tile_index_table); + if (plane->tile_column_width) + free(plane->tile_column_width); + if (plane->tile_row_height) + free(plane->tile_row_height); + } + free(plane); + } +} + +/* +* $Log: init.c,v $ +* Revision 1.25 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.24 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.23 2008/03/13 21:23:27 steve +* Add pipeline step for YUV420. +* +* Revision 1.22 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.21 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.20 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.19 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.18 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.17 2007/11/22 19:02:05 steve +* More fixes of color plane buffer sizes. +* +* Revision 1.16 2007/11/21 23:26:14 steve +* make all strip buffers store MB data. +* +* Revision 1.15 2007/11/21 00:34:30 steve +* Rework spatial mode tile macroblock shuffling. +* +* Revision 1.14 2007/11/15 17:44:13 steve +* Frequency mode color support. +* +* Revision 1.13 2007/11/14 23:56:17 steve +* Fix TILE ordering, using seeks, for FREQUENCY mode. +* +* Revision 1.12 2007/11/12 23:21:54 steve +* Infrastructure for frequency mode ordering. +* +* Revision 1.11 2007/11/08 02:52:32 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.10 2007/11/05 02:01:12 steve +* Add support for mixed row/column tiles. +* +* Revision 1.9 2007/11/01 21:09:40 steve +* Multiple rows of tiles. +* +* Revision 1.8 2007/10/30 21:32:46 steve +* Support for multiple tile columns. +* +* Revision 1.7 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.6 2007/09/04 19:10:46 steve +* Finish level1 overlap filtering. +* +* Revision 1.5 2007/08/15 01:54:11 steve +* Add level2 filter to decoder. +* +* Revision 1.4 2007/08/04 00:15:31 steve +* Allow width/height of 1 pixel. +* +* Revision 1.3 2007/07/21 00:25:48 steve +* snapshot 2007 07 20 +* +* Revision 1.2 2007/06/28 20:03:11 steve +* LP processing seems to be OK now. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/io.c b/jpegxr/io.c new file mode 100644 index 000000000..aaef80f34 --- /dev/null +++ b/jpegxr/io.c @@ -0,0 +1,542 @@ + + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: io.c,v 1.14 2008/03/05 06:58:10 gus Exp $") +#else +#ident "$Id: io.c,v 1.14 2008/03/05 06:58:10 gus Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + +void _jxr_rbitstream_initialize(struct rbitstream*str, FILE*fd) +{ + str->bits_avail = 0; + str->fd = fd; + str->read_count = 0; +} + +size_t _jxr_rbitstream_bitpos(struct rbitstream*str) +{ + return str->read_count*8 - str->bits_avail; +} + +void _jxr_rbitstream_mark(struct rbitstream*str) +{ + assert(str->bits_avail == 0); + str->mark_stream_position = ftell(str->fd); + assert(str->mark_stream_position >= 0); + str->read_count = 0; +} + +void _jxr_rbitstream_seek(struct rbitstream*str, uint64_t off) +{ + int rc; + assert(str->bits_avail == 0); + /* NOTE: Should be using fseek64? */ + rc = fseek(str->fd, str->mark_stream_position + (long)off, SEEK_SET); + str->read_count = (size_t) off; + assert(rc >= 0); +} + +/* +* Cause the bitstream to consume enough bits that the next bit is on +* a byte boundary. This is for getting alignment, which is sometimes +* needed. +*/ +void _jxr_rbitstream_syncbyte(struct rbitstream*str) +{ + str->bits_avail = 0; +} + +/* +* Get the next 8 bits from the input file and adjust the bitstream +* pointers so that the bits can be read out. +*/ +static int get_byte(struct rbitstream*str) +{ + int tmp; + assert(str->bits_avail == 0); + tmp = fgetc(str->fd); + if (tmp == EOF) + return EOF; + + str->byte = tmp; + str->bits_avail = 8; + str->read_count += 1; +#if 0 + DEBUG(" in byte: 0x%02x (bitpos=%zd)\n", + str->byte, str->read_count*8-8); +#endif + return 0; +} + +/* +* The following read integers of various width from the data input +* stream. This handles the bit ordering and packing of the bits. +*/ +int _jxr_rbitstream_uint1(struct rbitstream*str) +{ + if (str->bits_avail == 0) { + get_byte(str); + } + + assert(str->bits_avail > 0); + + str->bits_avail -= 1; + return (str->byte & (1 << str->bits_avail))? 1 : 0; +} + +uint8_t _jxr_rbitstream_uint2(struct rbitstream*str) +{ + uint8_t tmp = 0; + + tmp |= _jxr_rbitstream_uint1(str); + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + return tmp; +} + +uint8_t _jxr_rbitstream_uint3(struct rbitstream*str) +{ + uint8_t tmp = 0; + + tmp |= _jxr_rbitstream_uint1(str); + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + return tmp; +} + +uint8_t _jxr_rbitstream_uint4(struct rbitstream*str) +{ + uint8_t tmp; + int idx; + + if (str->bits_avail == 0) + get_byte(str); + + if (str->bits_avail == 4) { + str->bits_avail = 0; + return str->byte & 0x0f; + } + + tmp = 0; + for (idx = 0 ; idx < 4 ; idx += 1) { + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + } + + return tmp; +} + +uint8_t _jxr_rbitstream_uint6(struct rbitstream*str) +{ + uint8_t tmp; + int idx; + + tmp = _jxr_rbitstream_uint4(str); + for (idx = 4 ; idx < 6 ; idx += 1) { + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + } + + return tmp; +} + +uint8_t _jxr_rbitstream_uint8(struct rbitstream*str) +{ + uint8_t tmp; + int idx; + + if (str->bits_avail == 0) + get_byte(str); + + if (str->bits_avail == 8) { + str->bits_avail = 0; + return str->byte; + } + + tmp = 0; + for (idx = 0 ; idx < 8 ; idx += 1) { + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + } + + return tmp; +} + +uint16_t _jxr_rbitstream_uint12(struct rbitstream*str) +{ + uint16_t tmp = 0; + + tmp = _jxr_rbitstream_uint8(str); + tmp <<= 4; + tmp |= _jxr_rbitstream_uint4(str); + return tmp; +} + +uint16_t _jxr_rbitstream_uint15(struct rbitstream*str) +{ + uint16_t tmp = 0; + + tmp = _jxr_rbitstream_uint8(str); + tmp <<= 4; + tmp |= _jxr_rbitstream_uint4(str); + tmp <<= 3; + tmp |= _jxr_rbitstream_uint3(str); + return tmp; +} + +uint16_t _jxr_rbitstream_uint16(struct rbitstream*str) +{ + uint16_t tmp = 0; + + tmp = _jxr_rbitstream_uint8(str); + tmp <<= 8; + tmp |= _jxr_rbitstream_uint8(str); + return tmp; +} + +uint32_t _jxr_rbitstream_uint32(struct rbitstream*str) +{ + uint32_t tmp = 0; + + tmp = _jxr_rbitstream_uint16(str); + tmp <<= 16; + tmp |= _jxr_rbitstream_uint16(str); + return tmp; +} + +uint32_t _jxr_rbitstream_uintN(struct rbitstream*str, int N) +{ + uint32_t tmp = 0; + assert(N <= 32); + + while (N > 0) { + tmp <<= 1; + tmp |= _jxr_rbitstream_uint1(str); + N -= 1; + } + return tmp; +} + +int _jxr_rbitstream_intE(struct rbitstream*str, int code_size, + const unsigned char*codeb, const signed char*codev) +{ + int bits = 0; + unsigned val = 0; + + while (codeb[val << (code_size-bits)] != bits) { + val <<= 1; + val |= _jxr_rbitstream_uint1(str); + bits += 1; + assert(bits <= code_size); + } + + return codev[val << (code_size-bits)]; +} + +int64_t _jxr_rbitstream_intVLW(struct rbitstream*str) +{ + uint64_t val = _jxr_rbitstream_uint8(str); + if (val < 0xfb) { + uint64_t tmp = _jxr_rbitstream_uint8(str); + val = val*256 + tmp; + + } else if (val == 0xfb) { + val = _jxr_rbitstream_uint32(str); + + } else if (val == 0xfc) { + uint64_t tmp; + val = _jxr_rbitstream_uint32(str); + tmp = _jxr_rbitstream_uint32(str); + val = (val << (uint64_t)32) + tmp; + + } else { + return 0; + } + + return val; +} + +void _jxr_wbitstream_initialize(struct wbitstream*str, FILE*fd) +{ + str->byte = 0; + str->bits_ready = 0; + str->fd = fd; + str->write_count = 0; +} + +size_t _jxr_wbitstream_bitpos(struct wbitstream*str) +{ + return str->write_count*8 + str->bits_ready; +} + +static void put_byte(struct wbitstream*str) +{ + assert(str->bits_ready == 8); + fputc(str->byte, str->fd); + str->byte = 0; + str->bits_ready = 0; + str->write_count += 1; +} + +void _jxr_wbitstream_syncbyte(struct wbitstream*str) +{ + if (str->bits_ready > 0) + str->bits_ready = 8; +} + +void _jxr_wbitstream_flush(struct wbitstream*str) +{ + _jxr_wbitstream_syncbyte(str); + if (str->bits_ready > 0) + put_byte(str); +} + +void _jxr_wbitstream_uint1(struct wbitstream*str, int val) +{ + if (str->bits_ready == 8) + put_byte(str); + + if (val) + str->byte |= 0x80 >> str->bits_ready; + str->bits_ready += 1; +} + +void _jxr_wbitstream_uint2(struct wbitstream*str, uint8_t val) +{ + int idx; + for (idx = 0 ; idx < 2 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x02 >> idx)); + } +} + +void _jxr_wbitstream_uint3(struct wbitstream*str, uint8_t val) +{ + int idx; + for (idx = 0 ; idx < 3 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x04 >> idx)); + } +} + +void _jxr_wbitstream_uint4(struct wbitstream*str, uint8_t val) +{ + int idx; + for (idx = 0 ; idx < 4 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x08 >> idx)); + } +} + +void _jxr_wbitstream_uint6(struct wbitstream*str, uint8_t val) +{ + int idx; + for (idx = 0 ; idx < 6 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x20 >> idx)); + } +} + +void _jxr_wbitstream_uint8(struct wbitstream*str, uint8_t val) +{ + int idx; + + if (str->bits_ready == 8) + put_byte(str); + + if (str->bits_ready == 0) { + str->bits_ready = 8; + str->byte = val; + return; + } + for (idx = 0 ; idx < 8 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x80 >> idx)); + } +} + +void _jxr_wbitstream_uint12(struct wbitstream*str, uint16_t val) +{ + int idx; + for (idx = 0 ; idx < 12 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x800 >> idx)); + } +} + +void _jxr_wbitstream_uint15(struct wbitstream*str, uint16_t val) +{ + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + _jxr_wbitstream_uint1(str, val & (0x4000 >> idx)); + } +} + +void _jxr_wbitstream_uint16(struct wbitstream*str, uint16_t val) +{ + _jxr_wbitstream_uint8(str, val >> 8); + _jxr_wbitstream_uint8(str, val >> 0); +} + +void _jxr_wbitstream_uint32(struct wbitstream*str, uint32_t val) +{ + _jxr_wbitstream_uint8(str, val >> 24); + _jxr_wbitstream_uint8(str, val >> 16); + _jxr_wbitstream_uint8(str, val >> 8); + _jxr_wbitstream_uint8(str, val >> 0); +} + +void _jxr_wbitstream_uintN(struct wbitstream*str, uint32_t val, int N) +{ + assert(N <= 32); + while (N > 0) { + _jxr_wbitstream_uint1(str, 1 & (val >> (N-1))); + N -= 1; + } +} + +void _jxr_wbitstream_intVLW(struct wbitstream*str, uint64_t val) +{ + if (val == 0) { + _jxr_wbitstream_uint8(str, 0xfe); + } else if (val < 0xfb00) { + _jxr_wbitstream_uint16(str, (uint16_t)val); + } else if (val < 0x100000000ULL) { + _jxr_wbitstream_uint8(str, 0xfb); + _jxr_wbitstream_uint32(str, (uint32_t)val); + } else { + _jxr_wbitstream_uint8(str, 0xfc); + _jxr_wbitstream_uint32(str, val >> 32ULL); + _jxr_wbitstream_uint32(str, val >> 0ULL); + } +} + +void _jxr_wbitstream_mark(struct wbitstream*str) +{ + if (str->bits_ready == 8) + _jxr_wbitstream_flush(str); + + assert(str->bits_ready == 0); + /* str->mark_stream_position = ftell(str->fd); */ + str->write_count = 0; +} + +const char* _jxr_vlc_index_name(int vlc) +{ + switch (vlc) { + case AbsLevelIndDCLum: return "AbsLevelIndDCLum"; + case AbsLevelIndDCChr: return "AbsLevelIndDCChr"; + case DecFirstIndLPLum: return "DecFirstIndLPLum"; + case AbsLevelIndLP0: return "AbsLevelIndLP0"; + case AbsLevelIndLP1: return "AbsLevelIndLP1"; + case AbsLevelIndHP0: return "AbsLevelIndHP0"; + case AbsLevelIndHP1: return "AbsLevelIndHP1"; + case DecIndLPLum0: return "DecIndLPLum0"; + case DecIndLPLum1: return "DecIndLPLum1"; + case DecFirstIndLPChr: return "DecFirstIndLPChr"; + case DecIndLPChr0: return "DecIndLPChr0"; + case DecIndLPChr1: return "DecIndLPChr1"; + case DecNumCBP: return "DecNumCBP"; + case DecNumBlkCBP: return "DecNumBlkCBP"; + case DecIndHPLum0: return "DecIndHPLum0"; + case DecIndHPLum1: return "DecIndHPLum1"; + case DecFirstIndHPLum: return "DecFirstIndHPLum"; + case DecFirstIndHPChr: return "DecFirstIndHPChr"; + case DecIndHPChr0: return "DecIndHPChr0"; + case DecIndHPChr1: return "DecIndHPChr1"; + default: return "?????"; + } +} + + +/* +* $Log: io.c,v $ +* Revision 1.16 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.15 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.14 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.13 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.12 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.11 2007/12/07 01:20:34 steve +* Fix adapt not adapting on line ends. +* +* Revision 1.10 2007/12/06 17:53:35 steve +* No longer need bitval dump. +* +* Revision 1.9 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.8 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.7 2007/11/19 18:22:34 steve +* Skip ESCaped FLEXBITS tiles. +* +* Revision 1.6 2007/11/14 23:56:17 steve +* Fix TILE ordering, using seeks, for FREQUENCY mode. +* +* Revision 1.5 2007/11/08 19:38:38 steve +* Get stub DCONLY compression to work. +* +* Revision 1.4 2007/11/08 02:52:32 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.3 2007/08/15 01:54:11 steve +* Add level2 filter to decoder. +* +* Revision 1.2 2007/06/21 17:31:22 steve +* Successfully parse LP components. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/jpegxr.c b/jpegxr/jpegxr.c new file mode 100644 index 000000000..742c0ed56 --- /dev/null +++ b/jpegxr/jpegxr.c @@ -0,0 +1,1754 @@ +/* +** +** $Id: jpegxr.c,v 1.4 2008/05/25 09:40:46 thor Exp $ +** +** This is the main program +** +*/ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: jpegxr.c,v 1.4 2008/05/25 09:40:46 thor Exp $") +#else +#ident "$Id: jpegxr.c,v 1.4 2008/05/25 09:40:46 thor Exp $" +#endif + +# include <stdio.h> +# include <stdlib.h> +# include <string.h> +# include <ctype.h> +# include "jpegxr.h" +# include "file.h" +# include <assert.h> + +/* MSC doesn't include getopt, so if compiling with MSC then get it +from our local copy. Otherwise use the C library version. */ +#ifdef _MSC_VER +# include "getopt.h" +/* MSVC doesn't have strcasecmp. Use _stricmp instead */ +# define strcasecmp _stricmp +#else +# include <unistd.h> +#endif + +char*path_out = 0; +char*path_debug = 0; +char*quant_uniform = 0; + +char*flags[128]; +int nflags = 0; + +static jxr_bands_present_t bands_present = JXR_BP_ALL; +static int trim_flexbits = 0; +static int overlap_filter = 1; +static jxr_color_fmt_t internal_color_fmt = JXR_YUV444; +static int disable_tile_overlap = 0; +static int frequency_mode_flag = 0; +static int profile_idc = 111; +static int level_idc = 255; +static int long_word_flag_setting = 1; +static int alpha_mode = 2; +static int padded_format = 0; +static unsigned char window_params[5] = {0,0,0,0,0}; +static jxrc_t_pixelFormat pxl_fmt; + +/* Set this flag if the encoder should try to use the USE_DC_QP and +USE_LP_QP flags when it can. */ +static int use_dc_qp_flag = 0; + +# define MAX_CHANNELS 16 +static unsigned char quant_per_channel[MAX_CHANNELS]; +static unsigned quant_per_channel_count = 0; + +# define MAX_TILES 4096 +static unsigned tile_rows = 1; +static unsigned tile_columns = 1; +static unsigned tile_width_in_MB[MAX_TILES * 2] = {0}; +static unsigned tile_height_in_MB[MAX_TILES * 2] = {0}; + +static unsigned char shift_bits = 0; +static unsigned char len_mantissa = 10; +static char exp_bias = 4; + +static raw_info raw_info_t; + +static int main_compress(const char*path); +static int main_decompress(const char*path); + +/* This function parses a qp input file and returns an array of +jxr_tile_qp with the results. The parser needs to know the tile +dimensions of the image in order to get the right number of +tiles. */ +extern int qp_parse_file(FILE*fd, jxr_image_t image); +/* Path to the input quant file. */ +static const char*quant_path = 0; + +int main(int argc, char*argv[]) +{ + int compress_flag = 0; + int flag; + int derive_flag = 0; + char*cp_temp; + int idx; + + /* initialize raw input */ + raw_info_t.is_raw = 0; + raw_info_t.raw_width = 0; + raw_info_t.raw_height = 0; + raw_info_t.raw_format = 3; + raw_info_t.raw_bpc = 8; + + while ((flag = getopt(argc, argv, "b:cphmwdra:D:f:F:l:o:U:C:R:P:L:q:Q:X:W:H:M:B:s:")) != -1) { + switch (flag) { + case 'b': /* Bands present */ + if (strcasecmp(optarg,"ALL") == 0) + bands_present = JXR_BP_ALL; + else if (strcasecmp(optarg,"NOFLEXBITS") == 0) + bands_present = JXR_BP_NOFLEXBITS; + else if (strcasecmp(optarg,"NOHIGHPASS") == 0) + bands_present = JXR_BP_NOHIGHPASS; + else if (strcasecmp(optarg,"DCONLY") == 0) + bands_present = JXR_BP_DCONLY; + else { + fprintf(stderr, "Invalid bands flag: %s\n", optarg); + fprintf(stderr, "Should be one of: ALL, NOFLEXBITS, NOHIGHPASS, DCONLY\n"); + return 1; + } + break; + + case 'c': + compress_flag = 1; + break; + + case 'd': + derive_flag = 1; + break; + + case 'D': + path_debug = optarg; + break; + + case 'p': + padded_format = 1; + break; + + case 'f': + if (strcmp(optarg, "USE_DC_QP") == 0) { + use_dc_qp_flag = 1; + } else if (strcmp(optarg,"YUV444") == 0) { + internal_color_fmt = JXR_YUV444; + } else if (strcmp(optarg,"YUV422") == 0) { + internal_color_fmt = JXR_YUV422; + } else if (strcmp(optarg,"YUV420") == 0) { + internal_color_fmt = JXR_YUV420; + } else { + } + break; + + case 'F': + trim_flexbits = strtoul(optarg, 0, 10); + if (trim_flexbits > 15) { + trim_flexbits = 15; + } + break; + + case 'h': + disable_tile_overlap = 1; + break; + + case 'm': + frequency_mode_flag = 1; + break; + + case 'w': + long_word_flag_setting = 0; + break; + + case 'l': + overlap_filter = strtoul(optarg, 0, 10); + if (overlap_filter >= 3) { + fprintf(stderr, "Invalid overlap filter flag. Got %d\n", overlap_filter); + return 1; + } + break; + + case 'X': + flags[nflags] = optarg; + nflags += 1; + break; + + case 'o': + path_out = optarg; + break; + + case 's': + cp_temp = optarg; + window_params[0] = 1; + unsigned read_value; + for (idx = 0 ; idx < 4 ; idx += 1) { + read_value = (unsigned) strtoul(cp_temp, &cp_temp, 10); + assert(read_value >= 0 && read_value < 64); + window_params[idx + 1] = (unsigned char) read_value; + if (*cp_temp == ':') + cp_temp += 1; + } + break; + + case 'U': + cp_temp = optarg; + tile_rows = (unsigned) strtoul(cp_temp, &cp_temp, 10); + if (tile_rows > MAX_TILES) + tile_rows = MAX_TILES; + if (*cp_temp == ':') { + cp_temp += 1; + tile_columns = (unsigned) strtoul(cp_temp, &cp_temp, 10); + if (tile_columns > MAX_TILES) + tile_columns = MAX_TILES; + } + else { + tile_columns = tile_rows; + } + + break; + + case 'a': + alpha_mode = strtoul(optarg, 0, 10); + if(alpha_mode <0 || alpha_mode > 2) + assert(0); + break; + + case 'C': + cp_temp = optarg; + for (tile_columns = 0 ; tile_columns < MAX_TILES ; tile_columns++) { + tile_width_in_MB[tile_columns] = (unsigned) strtoul(cp_temp, &cp_temp, 10); + if (*cp_temp == ':') + cp_temp += 1; + else + break; + } + tile_columns++; + break; + + case 'R': + cp_temp = optarg; + for (tile_rows = 0 ; tile_rows < MAX_TILES ; tile_rows++) { + tile_height_in_MB[tile_rows] = (unsigned) strtoul(cp_temp, &cp_temp, 10); + if (*cp_temp == ':') + cp_temp += 1; + else + break; + } + tile_rows++; + break; + + + case 'q': { /* Uniform quantization */ + quant_uniform = optarg; + quant_per_channel_count = 0; + int last_q = 0; + cp_temp = optarg; + for (idx = 0 ; idx < MAX_CHANNELS ; idx += 1) { + if (*cp_temp == 0) { + quant_per_channel[idx] = quant_per_channel[last_q]; + continue; + } + last_q = idx; + quant_per_channel_count += 1; + quant_per_channel[idx] = (unsigned char) strtoul(cp_temp, &cp_temp, 10); + if (*cp_temp == ':') + cp_temp += 1; + } + break; + } + + case 'Q': + quant_path = optarg; + break; + + case 'P': + profile_idc = strtoul(optarg, 0, 10); + if (profile_idc > 255) { + profile_idc = 255; + } + if (profile_idc < 0) { + profile_idc = 0; + } + break; + + case 'L': + level_idc = strtoul(optarg, 0, 10); + if (level_idc > 255) { + level_idc = 255; + } + if (level_idc < 0) { + level_idc = 0; + } + break; + + case 'r': + raw_info_t.is_raw = 1; + break; + + case 'W': + raw_info_t.raw_width = (unsigned int)atoi(optarg); + break; + + case 'H': + raw_info_t.raw_height = (unsigned int)atoi(optarg); + break; + + case 'M': + raw_info_t.raw_format = (unsigned char)atoi(optarg); + if ((raw_info_t.raw_format < 3) || (raw_info_t.raw_format > 34)) { + fprintf(stderr, "Invalid raw format.\n"); + return -1; + } + break; + + case 'B': + raw_info_t.raw_bpc = (unsigned char)atoi(optarg); + if ((8 != raw_info_t.raw_bpc) && (10 != raw_info_t.raw_bpc) && (16 != raw_info_t.raw_bpc)) { + fprintf(stderr, "Invalid bit/channel.\n"); + return -1; + } + break; + + case '?': + fprintf(stderr, "Abort from bad flag.\n"); + return -1; + } + } + + if (optind >= argc) { + fprintf(stderr,"Usage: %s <flags> <input_file.jxr>\n" + " DECODER FLAGS:\n" + " [-o <path>] [-w] [-P 44|55|66|111] [-L 4|8|16|32|64|128|255]\n" + "\n" + "\t-o: selects output file name (.raw/.tif/.pnm)\n" + "\t (PNM output can be used only for 24bpp RGB and 8bpp gray Output)\n" + "\t (TIF output can be used for all formats except the following:\n" + "\t N channels, BGR, RGBE, YCC, CMYKDirect & Premultiplied RGB)\n" + "\t (RAW output can be used for all formats)\n" + "\t-w: tests whether LONG_WORD_FLAG needs to be equal to TRUE\n" + "\t (will still decode the image)\n" + "\t-P: selects the maximum accepted profile value\n" + "\t (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced)\n" + "\t-L: selects the maximum accepted level value\n" + "\t (4|8|16|32|64|128)\n" + "\n" + " ENCODER FLAGS: (Temporary (.tmp) files may be used in encoding)\n" + " -c [-o <path>] [-b ALL|NOFLEXBITS|NOHIGHPASS|DCONLY] [-a 0|1|2] [-p]\n" + " [-f YUV444|YUV422|YUV420] [-F bits] [-h] [-m] [-l 0|1|2]\n" + " [-q q1[:q2[:q3]]] [-Q <path>] [-d] [-w] [-U rows:columns]\n" + " [-C width1[:width2>[:width3...]]] [-R height1[:height2[:height3...]]]\n" + " [-P 44|55|66|111] [-L 4|8|16|32|64|128|255] [-s top|left|bottom|right]\n" + " [-r -W width -H height -M 3|4|...|18 [-B 8|16]]\n" + "\n" + "\t-c: selects encoding instead of decoding\n" + "\t this flag is necessary for encoding\n" + "\t-o: selects the output file name (.jxr)\n" + "\t-b: selects the bands to encode\n" + "\t (ALL<Default>|NOFLEXBITS|NOHIGHPASS|DCONLY)\n" + "\t-a: selects encoder alpha mode\n" + "\t (0: no alpha|1:interleaved alpha|2:separate alpha) \n" + "\t Default: For tif input files, based on the information in the\n" + "\t PhotometricInterpretation and SamplesPerPixel tags in the container,\n" + "\t the encoder chooses an input pixel format. If the number\n" + "\t of components is 4 and photometric is 2, RGBA input is inferred and \n" + "\t the encoder assumes the presence of an alpha channel while encoding.\n" + "\t If the number of components is 5 and photometric is 5, CMYKA input is\n" + "\t inferred. In both these cases, the encoder infers a pixel format with\n" + "\t an alpha channel. In such cases, the default alpha encoder mode is 2.\n" + "\t For raw input files, when the -M parameter specified by the user is\n" + "\t 9, 10, 11, 12 13, 14, 23, 24, 25, 26 or 28,\n" + "\t the default alpha encoder mode is 2\n" + "\t In all other cases, the default alpha encoder mode is 0.\n" + "\t-p: selects an input pixel format with a padding channel\n" + "\t With tif input, when the encoder infers that the input file has an\n" + "\t alpha channel (see explanation for -a), this flag causes the encoder\n" + "\t to treat the alpha channel as a padding channel instead\n" + "\t-f: selects the internal color format\n" + "\t (YUV444<Default>|YUV422|YUV420)\n" + "\t-F: selects the number of flexbits to trim\n" + "\t (0<default> - 15)\n" + "\t-h: selects hard tile boundaries\n" + "\t (soft tile boundaries by default)\n" + "\t-m: encode in frequency order codestream\n" + "\t (spatial order by default)\n" + "\t-l: selects the overlapped block filtering\n" + "\t (0:off|1:HP only<Default>|2:all)\n" + "\n" + "\t-q: sets the quantization values separately, or one per band\n" + "\t (0<default, lossless> - 255)\n" + "\t-Q: specifies a file containing detailed quantization information\n" + "\t See sample.qp\n" + "\t-d: selects quantization for U/V channels derived from Y channel\n" + "\n" + "\t-U: selects uniform tile sizes\n" + "\t-C: selects the number of tile columns and the width of each\n" + "\t-R: selects the number of tile rows and the height of each\n" + "\n" + "\t-w: sets LONG_WORD_FLAG equal to FALSE\n" + "\t-P: selects the profile value\n" + "\t (44:Sub-Baseline|55:Baseline|66:Main|111:Advanced)\n" + "\t-L: selects the level value\n" + "\t (4|8|16|32|64|128)\n" + "\t-s: sets the top, left, bottom, and right margins\n" + "\n" + "\t-r: selects encoding with RAW images\n" + "\t must also specify -W, -H and -M, optional -B\n" + "\t-W: RAW image width when encoding with RAW images\n" + "\t-H: RAW image height when encoding with RAW images\n" + "\t-M: RAW image format when encoding with RAW images\n" + "\t 3: 3-channel\n" + "\t 4: 4-channel\n" + "\t 5: 5-channel\n" + "\t 6: 6-channel\n" + "\t 7: 7-channel\n" + "\t 8: 8-channel\n" + "\t 9: 3-channel Alpha\n" + "\t 10: 4-channel Alpha\n" + "\t 11: 5-channel Alpha\n" + "\t 12: 6-channel Alpha\n" + "\t 13: 7-channel Alpha\n" + "\t 14: 8-channel Alpha\n" + "\t 15: 32bppRGBE\n" + "\t 16: 16bppBGR555\n" + "\t 17: 16bppBGR565\n" + "\t 18: 32bppBGR101010\n" + "\t 19: YCC420\n" + "\t 20: YCC422\n" + "\t 21: YCC444\n" + "\t 22: YCC444 Fixed Point\n" + "\t 23: YCC420 Alpha\n" + "\t 24: YCC422 Alpha\n" + "\t 25: YCC444 Alpha\n" + "\t 26: YCC444 Fixed Point Alpha\n" + "\t 27: CMYKDIRECT\n" + "\t 28: CMYKDIRECT Alpha\n" + "\t 29: 24bppBGR\n" + "\t 30: 32bppBGR\n" + "\t 31: 32bppBGRA\n" + "\t 32: 32bppPBGRA\n" + "\t 33: 64bppPRGBA\n" + "\t 34: 128bppPRGBAFloat\n" + "\t-B: RAW image bit/channel when encoding with RAW images\n" + "\t 8: 8-bit/channel (default)\n" + "\t 10: 10-bit/channel\n" + "\t 16: 16-bit/channel\n" + "\n", + argv[0]); + return 1; + } + + /* + ** start mod thor: Derived quantization as in the DPK + */ + if (derive_flag) { + int idx = quant_per_channel[0]; + int idxuv = idx; + switch (internal_color_fmt) { + case JXR_YUV444: + if (idx < 16) { + idxuv = idx * 2; + } else if (idx <= 48) { + idxuv = idx + 18; + } else { + idxuv = idx + 18 + 2; + } + quant_per_channel_count = 3; + break; + case JXR_YUV422: + if (idx < 16) { + idxuv = idx + ((idx + 1) >> 1); + } else if (idx <= 48) { + idxuv = idx + 8; + } else { + idxuv = idx + 8 + 2; + } + quant_per_channel_count = 3; + break; + case JXR_YUV420: + if (idx < 16) { + idxuv = idx + ((idx + 2) >> 2); + } else if (idx <= 48) { + idxuv = idx + 4; + } else { + idxuv = idx + 4 + 2; + } + quant_per_channel_count = 3; + break; + default: + idxuv = idx; + break; + } + for(idx = 1;idx < MAX_CHANNELS;idx++) { + quant_per_channel[idx] = idxuv; + } + } + /* + ** End mod thor + */ + + if(disable_tile_overlap) + assert(compress_flag); + + if (frequency_mode_flag) + assert(compress_flag); + + if (compress_flag) + return main_compress(argv[optind]); + else + return main_decompress(argv[optind]); +} + +int setup_image_params(jxr_image_t *ptr_image, void *input_handle, int alpha_mode, int alpha_plane) +{ + int rc = 0; + + int wid, hei, ncomp, bpi; + short sf, photometric; + int padBytes; + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + + wid -= (window_params[2] + ((window_params[4] >> 4) << 4)); + assert(wid > 0); + hei -= (window_params[1] + ((window_params[3] >> 4) << 4)); + assert(hei > 0); + + /* Create a stub image. */ + jxr_image_t image = jxr_create_image(wid, hei, window_params); + *ptr_image = image; + + if (!raw_info_t.is_raw) { + /* Guess a color format from the number of components. */ + if(!alpha_plane) + { + switch (ncomp + padBytes) { + case 1: + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + break; + case 3: + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + break; + case 4: + if (photometric == 5){ + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUVK, 4); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_CMYK); + } + else if (photometric == 2){ /* RGB_NULL */ + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + } + break; + case 5: + if (photometric == 5){ /* CMYKA */ + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUVK, 4); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_CMYK); + } + break; + default: + jxr_set_INTERNAL_CLR_FMT(image, JXR_NCOMPONENT, ncomp); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_NCOMPONENT); + break; + } + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + + switch (bpi) { + case 1: + if (photometric) /*white is 1 */ + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD1WHITE1); + else + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD1BLACK1); + break; + case 8: + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + break; + case 16: + if (sf == 1) { + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + jxr_set_SHIFT_BITS(image, shift_bits); + } + else if (sf == 2) { + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16S); + jxr_set_SHIFT_BITS(image, shift_bits); + } + else if (sf == 3) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16F); + break; + case 32: + if (sf == 2) { + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD32S); + jxr_set_SHIFT_BITS(image, shift_bits); + } + else if (sf == 3) { + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD32F); + jxr_set_FLOAT(image, len_mantissa, exp_bias); + } + break; + default: + assert(0); + break; + } + } + else { /* raw */ + if ((raw_info_t.raw_format >= 3) && (raw_info_t.raw_format <= 14)) { /* N-channel and N-channel Alpha*/ + if(!alpha_plane) + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_NCOMPONENT); + else + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + if (raw_info_t.raw_format <= 8) + jxr_set_INTERNAL_CLR_FMT(image, JXR_NCOMPONENT, ncomp); /* N-channel */ + else + { + if(!alpha_plane) + jxr_set_INTERNAL_CLR_FMT(image, JXR_NCOMPONENT, ncomp - 1); /* N-channel Alpha */ + else + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); /* N-channel Alpha */ + } + if (8 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + else + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + else if (raw_info_t.raw_format == 15) { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUV444, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGBE); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else if (raw_info_t.raw_format == 16) { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD5); + } + else if (raw_info_t.raw_format == 17) { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD565); + } + else if (raw_info_t.raw_format == 18) { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD10); + } + else if (raw_info_t.raw_format == 19 || raw_info_t.raw_format == 23) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUV420, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YUV420); + } + else { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else if (raw_info_t.raw_format == 20 || raw_info_t.raw_format == 24) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUV422, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YUV422); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + if (8 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + else if (10 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD10); + else + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + else if (raw_info_t.raw_format == 21 || raw_info_t.raw_format == 25) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YUV444); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + if (8 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + else if (10 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD10); + else + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + else if (raw_info_t.raw_format == 22 || raw_info_t.raw_format == 26) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUV444, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YUV444); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16S); + } + else if (raw_info_t.raw_format == 27 || raw_info_t.raw_format == 28) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YUVK, 4); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_CMYKDIRECT); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + } + if (8 == raw_info_t.raw_bpc) + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + else + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + else if (raw_info_t.raw_format == 29) { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else if (raw_info_t.raw_format == 30) { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else if (raw_info_t.raw_format == 31) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + } + else if (raw_info_t.raw_format == 32) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD8); + } + } + else if (raw_info_t.raw_format == 33) + { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD16); + } + } + else if (raw_info_t.raw_format == 34) { + if(!alpha_plane) + { + jxr_set_INTERNAL_CLR_FMT(image, internal_color_fmt, 3); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_RGB); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD32F); + jxr_set_FLOAT(image, len_mantissa, exp_bias); + } + else + { + jxr_set_INTERNAL_CLR_FMT(image, JXR_YONLY, 1); + jxr_set_OUTPUT_CLR_FMT(image, JXR_OCF_YONLY); + jxr_set_OUTPUT_BITDEPTH(image, JXR_BD32F); + jxr_set_FLOAT(image, len_mantissa, exp_bias); + } + + } + + if(alpha_mode == 2 && !alpha_plane) + { + set_ncomp(input_handle, ncomp - 1); + } + else if(alpha_mode == 2 && alpha_plane) + { + set_ncomp(input_handle, 1); + } + } + + + + jxr_set_BANDS_PRESENT(image, bands_present); + jxr_set_TRIM_FLEXBITS(image, trim_flexbits); + jxr_set_OVERLAP_FILTER(image, overlap_filter); + jxr_set_DISABLE_TILE_OVERLAP(image, disable_tile_overlap); + jxr_set_FREQUENCY_MODE_CODESTREAM_FLAG(image, frequency_mode_flag); + jxr_set_PROFILE_IDC(image, profile_idc); + jxr_set_LEVEL_IDC(image, level_idc); + jxr_set_LONG_WORD_FLAG(image, long_word_flag_setting); + jxr_set_ALPHA_IMAGE_PLANE_FLAG(image, alpha_mode == 1 ? 1 : 0); + + jxr_set_NUM_VER_TILES_MINUS1(image, tile_columns); + jxr_set_TILE_WIDTH_IN_MB(image, tile_width_in_MB); + jxr_set_NUM_HOR_TILES_MINUS1(image, tile_rows); + jxr_set_TILE_HEIGHT_IN_MB(image, tile_height_in_MB); + jxr_set_pixel_format(image, pxl_fmt); + + if (quant_uniform) { + if (quant_per_channel_count == 1) { + jxr_set_QP_UNIFORM(image, quant_per_channel[0]); + } else if (ncomp >= 3 && quant_per_channel_count == 2) { + jxr_set_QP_SEPARATE(image, quant_per_channel); + } else { + int idx; + for (idx = ncomp ; idx < (int) quant_per_channel_count ; idx += 1) + quant_per_channel[idx] = quant_per_channel[ncomp-1]; + + jxr_set_QP_INDEPENDENT(image, quant_per_channel); + } + } else if (quant_path) { + FILE*quant_fd = fopen(quant_path, "r"); + if (quant_fd == 0) { + perror(quant_path); + return 1; + } + int rc = qp_parse_file(quant_fd, image); + if (rc < 0) return 1; + + } else { + jxr_set_QP_LOSSLESS(image); + } + + rc = jxr_test_PROFILE_IDC(image, 0); + if (rc < 0) { + return 1; + } + + rc = jxr_test_LEVEL_IDC(image, 0); + if (rc < 0) { + return 1; + } + return 0; +} + + +int setup_container_params(jxr_container_t container, void *input_handle) +{ + int wid, hei, ncomp, bpi; + short sf, photometric; + int padBytes; + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + int alpha_present = 0; + if (!raw_info_t.is_raw) { + switch (ncomp + padBytes) { + case 1: + if (bpi == 1) { + pxl_fmt = JXRC_FMT_BlackWhite; + } + else if (bpi == 8) { + pxl_fmt = JXRC_FMT_8bppGray; + } + else if (bpi == 16) { + if(sf == 1) + pxl_fmt = JXRC_FMT_16bppGray; + else if(sf == 2) + pxl_fmt = JXRC_FMT_16bppGrayFixedPoint; + else if(sf == 3) + pxl_fmt = JXRC_FMT_16bppGrayHalf; + } + else if (bpi == 32) { + if(sf == 2) + pxl_fmt = JXRC_FMT_32bppGrayFixedPoint; + else if(sf == 3) + pxl_fmt = JXRC_FMT_32bppGrayFloat; + } + break; + case 3: /* Assume RGB */ + if (bpi == 8) + pxl_fmt = (JXRC_FMT_24bppRGB); + else if (bpi == 16) { + if(sf == 1) + pxl_fmt = JXRC_FMT_48bppRGB; + else if(sf == 2) + pxl_fmt = JXRC_FMT_48bppRGBFixedPoint; + else if(sf == 3) + pxl_fmt = JXRC_FMT_48bppRGBHalf; + } + else if (bpi == 32) { + if(sf == 2) + pxl_fmt = JXRC_FMT_96bppRGBFixedPoint; + /* no 96bppRGBFloat */ + } + break; + case 4: /* CMYK or RGBA or RGB_Null*/ + if (bpi == 8) { + if (photometric == 5) + pxl_fmt = JXRC_FMT_32bppCMYK; + } + else if (bpi == 16) { + if (photometric == 5) + pxl_fmt = JXRC_FMT_64bppCMYK; + else if (photometric == 2) { + if (sf == 1) + { + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppRGBA; /* no 64bppRGB */ + } + else if (sf == 2) { + if (ncomp == 3) + pxl_fmt = JXRC_FMT_64bppRGBFixedPoint; + else if (ncomp == 4) + { + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppRGBAFixedPoint; + } + } + else if (sf == 3) { + if (ncomp == 3) + pxl_fmt = JXRC_FMT_64bppRGBHalf; + else if (ncomp == 4) + { + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppRGBAHalf; + } + } + } + } + else if (bpi == 32) { + if (photometric == 2) { + if (sf == 2) { + if (ncomp == 3) + pxl_fmt = JXRC_FMT_128bppRGBFixedPoint; + if (ncomp == 4) + { + alpha_present = 1; + pxl_fmt = JXRC_FMT_128bppRGBAFixedPoint; + } + } + else if(sf == 3) { + if (ncomp == 3) + pxl_fmt = JXRC_FMT_128bppRGBFloat; + else if (ncomp == 4) + { + alpha_present = 1; + pxl_fmt = JXRC_FMT_128bppRGBAFloat; + } + } + } + /* add 128bppRGBAFloat here */ + } + break; + case 5: /* CMYKA */ + if (bpi == 8) { + if (photometric == 5) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_40bppCMYKAlpha; + } + } + else if (bpi == 16) { + if (photometric == 5) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_80bppCMYKAlpha; + } + } + break; + default: + assert(0); + break; + } + } + else { /* raw */ + if ((raw_info_t.raw_format >= 3) && (raw_info_t.raw_format <= 14)) { /* N-channel */ + if (8 == raw_info_t.raw_bpc) { + switch (raw_info_t.raw_format) { + case 3: + pxl_fmt = JXRC_FMT_24bpp3Channels; + break; + case 4: + pxl_fmt = JXRC_FMT_32bpp4Channels; + break; + case 5: + pxl_fmt = JXRC_FMT_40bpp5Channels; + break; + case 6: + pxl_fmt = JXRC_FMT_48bpp6Channels; + break; + case 7: + pxl_fmt = JXRC_FMT_56bpp7Channels; + break; + case 8: + pxl_fmt = JXRC_FMT_64bpp8Channels; + break; + case 9: + alpha_present = 1; + pxl_fmt = JXRC_FMT_32bpp3ChannelsAlpha; + break; + case 10: + alpha_present = 1; + pxl_fmt = JXRC_FMT_40bpp4ChannelsAlpha; + break; + case 11: + alpha_present = 1; + pxl_fmt = JXRC_FMT_48bpp5ChannelsAlpha; + break; + case 12: + alpha_present = 1; + pxl_fmt = JXRC_FMT_56bpp6ChannelsAlpha; + break; + case 13: + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bpp7ChannelsAlpha; + break; + case 14: + alpha_present = 1; + pxl_fmt = JXRC_FMT_72bpp8ChannelsAlpha; + break; + default: + assert(0); + break; + + } + } + else { /* 16bpc */ + switch (raw_info_t.raw_format) { + case 3: + pxl_fmt = JXRC_FMT_48bpp3Channels; + break; + case 4: + pxl_fmt = JXRC_FMT_64bpp4Channels; + break; + case 5: + pxl_fmt = JXRC_FMT_80bpp5Channels; + break; + case 6: + pxl_fmt = JXRC_FMT_96bpp6Channels; + break; + case 7: + pxl_fmt = JXRC_FMT_112bpp7Channels; + break; + case 8: + pxl_fmt = JXRC_FMT_128bpp8Channels; + break; + case 9: + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bpp3ChannelsAlpha; + break; + case 10: + alpha_present = 1; + pxl_fmt = JXRC_FMT_80bpp4ChannelsAlpha; + break; + case 11: + alpha_present = 1; + pxl_fmt = JXRC_FMT_96bpp5ChannelsAlpha; + break; + case 12: + alpha_present = 1; + pxl_fmt = JXRC_FMT_112bpp6ChannelsAlpha; + break; + case 13: + alpha_present = 1; + pxl_fmt = JXRC_FMT_128bpp7ChannelsAlpha; + break; + case 14: + alpha_present = 1; + pxl_fmt = JXRC_FMT_144bpp8ChannelsAlpha; + break; + default: + assert(0); + break; + } + } + } + else if (raw_info_t.raw_format == 15) { /* RGBE */ + pxl_fmt = JXRC_FMT_32bppRGBE; + } + else if (raw_info_t.raw_format == 16) { + pxl_fmt = JXRC_FMT_16bppBGR555; + } + else if (raw_info_t.raw_format == 17) { + pxl_fmt = JXRC_FMT_16bppBGR565; + } + else if (raw_info_t.raw_format == 18) { + pxl_fmt = JXRC_FMT_32bppBGR101010; + } + else if ((raw_info_t.raw_format >= 19) && (raw_info_t.raw_format <= 26)) { /* YCC */ + if (8 == raw_info_t.raw_bpc) { + switch (raw_info_t.raw_format) { + case 19: + pxl_fmt = JXRC_FMT_12bppYCC420; + break; + case 20: + pxl_fmt = JXRC_FMT_16bppYCC422; + break; + case 21: + pxl_fmt = JXRC_FMT_24bppYCC444; + break; + case 23: + alpha_present = 1; + pxl_fmt = JXRC_FMT_20bppYCC420Alpha; + break; + case 24: + alpha_present = 1; + pxl_fmt = JXRC_FMT_24bppYCC422Alpha; + break; + case 25: + alpha_present = 1; + pxl_fmt = JXRC_FMT_32bppYCC444Alpha; + break; + default: + assert(0); + break; + } + } + else if (10 == raw_info_t.raw_bpc) { + switch (raw_info_t.raw_format) { + case 20: + pxl_fmt = JXRC_FMT_20bppYCC422; + break; + case 21: + pxl_fmt = JXRC_FMT_30bppYCC444; + break; + case 24: + alpha_present = 1; + pxl_fmt = JXRC_FMT_30bppYCC422Alpha; + break; + case 25: + alpha_present = 1; + pxl_fmt = JXRC_FMT_40bppYCC444Alpha; + break; + default: + assert(0); + break; + } + } + else if (16 == raw_info_t.raw_bpc) { /* 16bpc */ + switch (raw_info_t.raw_format) { + case 20: + pxl_fmt = JXRC_FMT_32bppYCC422; + break; + case 21: + pxl_fmt = JXRC_FMT_48bppYCC444; + break; + case 22: + pxl_fmt = JXRC_FMT_48bppYCC444FixedPoint; + break; + case 24: + alpha_present = 1; + pxl_fmt = JXRC_FMT_48bppYCC422Alpha; + break; + case 25: + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppYCC444Alpha; + break; + case 26: + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppYCC444AlphaFixedPoint; + break; + default: + assert(0); + break; + } + } + else + assert(0); + } + else if ((raw_info_t.raw_format >= 27) && (raw_info_t.raw_format <= 28)) { /* CMYKDIRECT */ + if (8 == raw_info_t.raw_bpc) { + switch (raw_info_t.raw_format) { + case 27: + pxl_fmt = JXRC_FMT_32bppCMYKDIRECT; + break; + case 28: + alpha_present = 1; + pxl_fmt = JXRC_FMT_40bppCMYKDIRECTAlpha; + break; + default: + assert(0); + break; + } + } + else if (16 == raw_info_t.raw_bpc) { /* 16bpc */ + switch (raw_info_t.raw_format) { + case 27: + pxl_fmt = JXRC_FMT_64bppCMYKDIRECT; + break; + case 28: + alpha_present = 1; + pxl_fmt = JXRC_FMT_80bppCMYKDIRECTAlpha; + break; + default: + assert(0); + break; + } + } + else + assert(0); + } + else if (raw_info_t.raw_format == 29) { + pxl_fmt = JXRC_FMT_24bppBGR; + } + else if (raw_info_t.raw_format == 30) { + pxl_fmt = JXRC_FMT_32bppBGR; + } + else if (raw_info_t.raw_format == 31) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_32bppBGRA; + } + else if (raw_info_t.raw_format == 32) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_32bppPBGRA; + } + else if (raw_info_t.raw_format == 33) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_64bppPRGBA; + } + else if (raw_info_t.raw_format == 34) { + alpha_present = 1; + pxl_fmt = JXRC_FMT_128bppPRGBAFloat; + } + else + assert(0); + } + + jxrc_set_pixel_format(container, pxl_fmt); + + if(alpha_present) + { + if(alpha_mode == 0) /* No -a option was used at command line, so by default, turn on Separate alpha */ + { + alpha_mode = 2; /* Separate alpha */ + fprintf(stderr, " Setting alpha_mode to 2\n"); + } + else + { + fprintf(stderr, " Using alpha_mode = %d\n ", alpha_mode); + } + + } + else /* Current output format has no alpha information, so turn off alpha_mode */ + { + if(alpha_mode != 0) + { + alpha_mode = 0; + fprintf(stderr, " Setting alpha_mode to 0\n"); + } + } + + jxrc_set_image_shape(container, wid, hei); + jxrc_set_image_band_presence(container, (unsigned) bands_present); /* another call will need to be added for separate alpha */ + return 0; + + +} + +static int main_compress(const char*path) +{ + int rc = 0; + jxr_image_t image = NULL; + void *input_handle = NULL; + jxr_container_t container = NULL; + + if (path_out == 0) + path_out = "out.jxr"; + + FILE*fd = fopen(path_out, "wb"); + if (fd == 0) { + perror(path_out); + rc = -1; + goto exit; + } + + input_handle = open_input_file(path, &raw_info_t, &alpha_mode, &padded_format); + char path_primary[2048]; + char path_alpha[2048]; + int wid, hei, ncomp, bpi; + short sf, photometric; + int padBytes; + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + + + /* Create the file container and bind the FD to it. */ + container = jxr_create_container(); + jxrc_start_file(container, fd); + + /* Start the next ifd entry and load it with information about + the image to be processed. */ + rc = jxrc_begin_ifd_entry(container); + if(rc != 0) + goto exit; + rc = setup_container_params(container, input_handle); + if(rc != 0) + goto exit; + + /* Create a stub image. */ + if(alpha_mode == 2) + rc = setup_image_params(&image, input_handle, 0, 0); /* Set up parameters for a regular image, fix later after separating primary and alpha */ + else + rc = setup_image_params(&image, input_handle, alpha_mode, 0); + + if(rc != 0) + goto exit; + + if(alpha_mode == 2) + { + /* Open handle to dump primary in tif format */ + separate_primary_alpha(image, input_handle, path_out, path_primary, path_alpha, container);//jxrc_image_pixelformat(container, 0)); + close_file(input_handle); + input_handle = NULL; + input_handle = open_input_file(path_primary, &raw_info_t, &alpha_mode, &padded_format); + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + rc = setup_image_params(&image, input_handle, alpha_mode, 0); + if(rc != 0) + goto exit; + jxrc_set_separate_alpha_image_plane(container, 1); + } + else + { + jxrc_set_separate_alpha_image_plane(container, 0); + } + + jxr_set_pixel_format(image, jxrc_get_pixel_format(container)); + + /* Close out the current IFD and start with the actual image + data to be written. */ + jxrc_begin_image_data(container); + + jxr_set_block_input(image, read_file); + jxr_set_user_data(image, input_handle); + + /* Write image to the destination file. */ + rc = jxr_write_image_bitstream(image, fd); + if (rc != 0) { + goto exit; + } + + /* Finalize IFDs for image. */ + jxrc_write_container_post(container); + + close_file(input_handle); + input_handle = NULL; + jxr_destroy(image); + image = NULL; + + if(alpha_mode == 2) + { + input_handle = open_input_file(path_alpha, &raw_info_t, &alpha_mode, &padded_format); + get_file_parameters(input_handle, &wid, &hei, &ncomp, &bpi, &sf, &photometric, &padBytes); + + rc = setup_image_params(&image, input_handle, alpha_mode, 1); + jxr_set_pixel_format(image, jxrc_get_pixel_format(container)); + if(rc != 0) + { + goto exit; + } + + jxr_set_block_input(image, read_file); + jxr_set_user_data(image, input_handle); + + /* Write image to the destination file. */ + rc = jxr_write_image_bitstream(image, fd); + if (rc != 0) { + goto exit; + } + /* Finalize IFDs for alpha plane. */ + jxrc_write_container_post_alpha(container); + remove(path_alpha); + remove(path_primary); + } + + + +exit: + close_file(input_handle); + jxr_destroy(image); + if(fd) + fclose(fd); + jxr_destroy_container(container); + return rc; +} + +static int decompress_image(FILE *fd, jxr_container_t container, void *output_handle, jxr_image_t *pImage, unsigned char alpha) +{ + int rc, idx; + *pImage = jxr_create_input(); + jxr_set_block_output(*pImage, write_file); + jxr_set_pixel_format(*pImage, jxrc_image_pixelformat(container, 0)); + jxr_set_user_data(*pImage, output_handle); + jxr_set_PROFILE_IDC(*pImage, profile_idc); + jxr_set_LEVEL_IDC(*pImage, level_idc); + jxr_set_container_parameters(*pImage, + jxrc_image_pixelformat(container, 0), + jxrc_image_width(container, 0), jxrc_image_height(container, 0), + jxrc_alpha_offset(container, 0), + jxrc_image_band_presence(container,0), jxrc_alpha_band_presence(container,0), alpha); + + for (idx = 0 ; idx < nflags ; idx += 1) { + if (strcmp(flags[idx],"SKIP_HP_DATA") == 0) { + jxr_flag_SKIP_HP_DATA(*pImage, 1); + continue; + } + if (strcmp(flags[idx],"SKIP_FLEX_DATA") == 0) { + jxr_flag_SKIP_FLEX_DATA(*pImage, 1); + continue; + } + } + + /* Process as an image bitstream. */ + rc = jxr_read_image_bitstream(*pImage, fd); + if (rc < 0) { + switch (rc) { + case JXR_EC_BADMAGIC: + fprintf(stderr, "No valid magic number. Not an JPEG XR container or bitstream.\n"); + break; + default: + fprintf(stderr, " Error %d reading image bitstream\n", rc); + break; + } + } + else + rc = jxr_test_LONG_WORD_FLAG(*pImage, long_word_flag_setting); + return rc; + +} +#define SAFE_FREE(h) {if(h)free(h); h = NULL;} +#define SAFE_CLOSE(h) {if(h)close_file(h); h = NULL;} +#define SAFE_JXR_DESTROY(h) {if(h) jxr_destroy(h); h = NULL;} + +static int main_decompress(const char*path_in) +{ + int rc; + int codedImages = 1; + unsigned int alphaCodedImagePresent = 0; + void *output_handle_primary = NULL; + void *output_handle_alpha = NULL; + char path_out_primary[2048]; + char path_out_alpha[2048]; + unsigned long off; + jxr_image_t imageAlpha=NULL, image=NULL; + if (path_out == 0) + path_out = "out.raw"; + + FILE*fd = fopen(path_in, "rb"); + if (fd == 0) { + perror(path_in); + return -1; + } + + void *output_handle = open_output_file(path_out); + + jxr_container_t ifile = jxr_create_container(); + rc = jxr_read_image_container(ifile, fd); + if (rc >= 0) { + assert(rc >= 0); +# if defined(DETAILED_DEBUG) + printf("Detected jxr image container\n"); + printf("XXXX Bytes of contained image: %ld\n", jxrc_image_bytecount(ifile, 0)); +#endif + off = jxrc_image_offset(ifile, 0); +#if defined(DETAILED_DEBUG) + printf("XXXX Offset of contained image: %ld\n", off); +#endif + rc = fseek(fd, off, SEEK_SET); + assert(rc >= 0); + if(jxrc_alpha_offset(ifile, 0)) + { + alphaCodedImagePresent = 1; +# if defined(DETAILED_DEBUG) + printf("XXXX Bytes of alpha image: %ld\n", jxrc_alpha_bytecount(ifile, 0)); + printf("XXXX Offset of contained image: %ld\n", jxrc_alpha_offset(ifile, 0)); +#endif + } + } else { +#if defined(DETAILED_DEBUG) + printf("No container found, assuming unwrapped bistream with no alpha coded image\n"); +#endif + rc = fseek(fd, 0, SEEK_SET); + assert(rc >= 0); + } + + /* read optional IFD tags to make certain of conformance */ + char * document_name = 0, * image_description = 0, * equipment_make = 0, * equipment_model = 0, * page_name = 0; + char * software_name_version = 0, * date_time = 0, * artist_name = 0, * host_computer = 0, * copyright_notice = 0; + unsigned char profile, level; + unsigned short page_number[2] = {0, 0}, color_space; + unsigned long spatial_xfrm, image_type; + float width_res, height_res; + unsigned char image_band_present, alpha_band_present, buf[4]; + + rc = jxrc_document_name(ifile, 0, &document_name); + rc = jxrc_image_description(ifile, 0, &image_description); + rc = jxrc_equipment_make(ifile, 0, &equipment_make); + rc = jxrc_equipment_model(ifile, 0, &equipment_model); + rc = jxrc_page_name(ifile, 0, &page_name); + rc = jxrc_page_number(ifile, 0, page_number); + rc = jxrc_software_name_version(ifile, 0, &software_name_version); + rc = jxrc_date_time(ifile, 0, &date_time); + rc = jxrc_artist_name(ifile, 0, &artist_name); + rc = jxrc_host_computer(ifile, 0, &host_computer); + rc = jxrc_copyright_notice(ifile, 0, ©right_notice); + color_space = jxrc_color_space(ifile, 0); + spatial_xfrm = jxrc_spatial_xfrm_primary(ifile, 0); + image_type = jxrc_image_type(ifile, 0); + rc = jxrc_ptm_color_info(ifile, 0, buf); + rc = jxrc_profile_level_container(ifile, 0, &profile, &level); + if (rc < 0) { + profile = 111; + level = 255; + } + width_res = jxrc_width_resolution(ifile, 0); + height_res = jxrc_height_resolution(ifile, 0); + image_band_present = jxrc_image_band_presence(ifile, 0); + alpha_band_present = jxrc_alpha_band_presence(ifile, 0); + rc = jxrc_padding_data(ifile, 0); + + + if(alphaCodedImagePresent) + { + /* Open handle to dump decoded primary in raw format */ + strcpy(path_out_primary, path_out); + strcat(path_out_primary, "_primary.raw"); + output_handle_primary = open_output_file(path_out_primary); + } + else + { + output_handle_primary = open_output_file(path_out); + } + /*Decode image */ + rc = decompress_image(fd, ifile, output_handle_primary, &image, 0); + SAFE_CLOSE(output_handle_primary); + if(rc < 0) + goto exit; + + if(!alphaCodedImagePresent) + goto exit; + + /* Open handle to dump decoded alpha in raw format*/ + strcpy(path_out_alpha, path_out); + strcat(path_out_alpha, "_alpha.raw"); + output_handle_alpha = open_output_file(path_out_alpha); + + /*Seek to alpha offset */ + off = jxrc_alpha_offset(ifile, 0); + rc = fseek(fd, off, SEEK_SET); + assert(rc >= 0); + /* Decode alpha */ + rc = decompress_image(fd, ifile, output_handle_alpha, &imageAlpha, 1); + SAFE_CLOSE(output_handle_alpha); + if(rc < 0) + goto exit; + + /* For YCC and CMYKDirect formats, concatenate alpha and primary images */ + /* For other output pixel formats, interleave alphad and primary images */ + { + output_handle = open_output_file(path_out); + FILE *fpPrimary = fopen(path_out_primary,"rb"); + assert(fpPrimary); + FILE *fpAlpha = fopen(path_out_alpha,"rb"); + assert(fpAlpha); + jxr_set_user_data(image, output_handle); + write_file_combine_primary_alpha(image, fpPrimary, fpAlpha); + fclose(fpPrimary); + fclose(fpAlpha); + remove(path_out_primary); + remove(path_out_alpha); + SAFE_CLOSE(output_handle); + } + +exit: + SAFE_FREE(document_name); + SAFE_FREE(image_description); + SAFE_FREE(equipment_make); + SAFE_FREE(equipment_model); + SAFE_FREE(page_name); + SAFE_FREE(software_name_version); + SAFE_FREE(date_time); + SAFE_FREE(artist_name); + SAFE_FREE(host_computer); + SAFE_FREE(copyright_notice); + SAFE_JXR_DESTROY(image); + SAFE_JXR_DESTROY(imageAlpha); + fclose(fd); + return 0; +} + +/* +* $Log: jpegxr.c,v $ +* Revision 1.39 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.38 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.37 2008/05/25 09:40:46 thor +* Added a -d command line option to enable derived quantization. +* +* Revision 1.36 2008/05/13 13:47:11 thor +* Some experiments with a smarter selection for the quantization size, +* does not yet compile. +* +* Revision 1.35 2008-05-09 19:57:48 thor +* Reformatted for unix LF. +* +* Revision 1.34 2008-04-15 14:28:12 thor +* Start of the repository for the jpegxr reference software. +* +* Revision 1.33 2008/03/21 18:05:53 steve +* Proper CMYK formatting on input. +* +* Revision 1.32 2008/03/18 18:36:56 steve +* Support compress of CMYK images. +* +* Revision 1.31 2008/03/11 22:12:49 steve +* Encode YUV422 through DC. +* +* Revision 1.30 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.29 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.28 2008/03/05 04:04:30 steve +* Clarify constraints on USE_DC_QP in image plane header. +* +* Revision 1.27 2008/03/05 01:27:15 steve +* QP_UNIFORM may use USE_DC_LP optionally. +* +* Revision 1.26 2008/03/04 23:01:28 steve +* Cleanup QP API in preparation for distributed QP +* +* Revision 1.25 2008/03/02 19:56:27 steve +* Infrastructure to read write BD16 files. +* +* Revision 1.24 2008/03/01 02:46:09 steve +* Add support for JXR container. +* +* Revision 1.23 2008/02/29 01:03:31 steve +* MSC doesnt have strcasecmp. Use stricmp instead. +* +* Revision 1.22 2008/02/29 00:57:59 steve +* VisualStudio files +* +* Revision 1.21 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.20 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.19 2008/01/19 02:30:46 rick +* Re-implement and extend file interface. +* +* Revision 1.18 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.17 2008/01/06 01:29:28 steve +* Add support for TRIM_FLEXBITS in compression. +* +* Revision 1.16 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.15 2007/12/06 00:24:25 steve +* Zero fill strip buffer, so that right pad is zeros. +* +* Revision 1.14 2007/12/04 22:06:10 steve +* Infrastructure for encoding LP. +* +* Revision 1.13 2007/11/30 01:57:00 steve +* Handle comments in PNM files. +* +* Revision 1.12 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.11 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.10 2007/11/08 02:52:32 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.9 2007/11/07 18:11:02 steve +* Useful error message for bad magic numbers. +* +* Revision 1.8 2007/10/22 23:08:55 steve +* Protect prints with DETAILED_DEBUG. +* +* Revision 1.7 2007/09/18 17:02:49 steve +* Slight PNM header format change. +* +* Revision 1.6 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.5 2007/08/03 22:49:10 steve +* Do not write out the line padding. +* +* Revision 1.4 2007/07/30 23:09:57 steve +* Interleave FLEXBITS within HP block. +* +* Revision 1.3 2007/07/21 00:25:48 steve +* snapshot 2007 07 20 +* +* Revision 1.2 2007/06/07 18:53:06 steve +* Parse HP coeffs that are all 0. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/jpegxr.h b/jpegxr/jpegxr.h new file mode 100644 index 000000000..a474f87b2 --- /dev/null +++ b/jpegxr/jpegxr.h @@ -0,0 +1,794 @@ + +# ifndef __jpegxr_h +# define __jpegxr_h + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: jpegxr.h,v 1.26 2008/03/18 18:36:56 steve Exp $") +#else +#ident "$Id: jpegxr.h,v 1.26 2008/03/18 18:36:56 steve Exp $" +#endif + +# include <stdio.h> + +#ifdef _MSC_VER +# ifdef JXR_DLL_EXPORTS +# define JXR_EXTERN extern "C" __declspec(dllexport) +# else +# define JXR_EXTERN extern "C" __declspec(dllimport) +# endif +#else +# ifdef _cplusplus +# define JXR_EXTERN extern "C" +# else +# define JXR_EXTERN extern +# endif +#endif + +/* JPEG XR CONTAINER */ + +/* +* The container type represents an optional container that may +* contain 1 or more JPEG XR images. Create the jxr_create_container +* function and free them with jxr_destroy_container. The functions +* below can be used to extract the image from the container. +*/ +typedef struct jxr_container *jxr_container_t; + +JXR_EXTERN jxr_container_t jxr_create_container(void); +JXR_EXTERN void jxr_destroy_container(jxr_container_t c); + +#define NUM_GUIDS 79 +extern unsigned char jxr_guids[NUM_GUIDS][16]; + +typedef enum JXRC_GUID_e{ + JXRC_FMT_24bppRGB = 0, + JXRC_FMT_24bppBGR, + JXRC_FMT_32bppBGR, + JXRC_FMT_48bppRGB, + JXRC_FMT_48bppRGBFixedPoint, + JXRC_FMT_48bppRGBHalf, + JXRC_FMT_96bppRGBFixedPoint, + JXRC_FMT_64bppRGBFixedPoint, + JXRC_FMT_64bppRGBHalf, + JXRC_FMT_128bppRGBFixedPoint, + JXRC_FMT_128bppRGBFloat, + JXRC_FMT_32bppBGRA, + JXRC_FMT_64bppRGBA, + JXRC_FMT_64bppRGBAFixedPoint, + JXRC_FMT_64bppRGBAHalf, + JXRC_FMT_128bppRGBAFixedPoint, + JXRC_FMT_128bppRGBAFloat, + JXRC_FMT_32bppPBGRA, + JXRC_FMT_64bppPRGBA, + JXRC_FMT_128bppPRGBAFloat, + JXRC_FMT_32bppCMYK, + JXRC_FMT_40bppCMYKAlpha, + JXRC_FMT_64bppCMYK, + JXRC_FMT_80bppCMYKAlpha, + JXRC_FMT_24bpp3Channels, + JXRC_FMT_32bpp4Channels, + JXRC_FMT_40bpp5Channels, + JXRC_FMT_48bpp6Channels, + JXRC_FMT_56bpp7Channels, + JXRC_FMT_64bpp8Channels, + JXRC_FMT_32bpp3ChannelsAlpha, + JXRC_FMT_40bpp4ChannelsAlpha, + JXRC_FMT_48bpp5ChannelsAlpha, + JXRC_FMT_56bpp6ChannelsAlpha, + JXRC_FMT_64bpp7ChannelsAlpha, + JXRC_FMT_72bpp8ChannelsAlpha, + JXRC_FMT_48bpp3Channels, + JXRC_FMT_64bpp4Channels, + JXRC_FMT_80bpp5Channels, + JXRC_FMT_96bpp6Channels, + JXRC_FMT_112bpp7Channels, + JXRC_FMT_128bpp8Channels, + JXRC_FMT_64bpp3ChannelsAlpha, + JXRC_FMT_80bpp4ChannelsAlpha, + JXRC_FMT_96bpp5ChannelsAlpha, + JXRC_FMT_112bpp6ChannelsAlpha, + JXRC_FMT_128bpp7ChannelsAlpha, + JXRC_FMT_144bpp8ChannelsAlpha, + JXRC_FMT_8bppGray, + JXRC_FMT_16bppGray, + JXRC_FMT_16bppGrayFixedPoint, + JXRC_FMT_16bppGrayHalf, + JXRC_FMT_32bppGrayFixedPoint, + JXRC_FMT_32bppGrayFloat, + JXRC_FMT_BlackWhite, + JXRC_FMT_16bppBGR555, + JXRC_FMT_16bppBGR565, + JXRC_FMT_32bppBGR101010, + JXRC_FMT_32bppRGBE, + JXRC_FMT_32bppCMYKDIRECT, + JXRC_FMT_64bppCMYKDIRECT, + JXRC_FMT_40bppCMYKDIRECTAlpha, + JXRC_FMT_80bppCMYKDIRECTAlpha, + JXRC_FMT_12bppYCC420, + JXRC_FMT_16bppYCC422, + JXRC_FMT_20bppYCC422, + JXRC_FMT_32bppYCC422, + JXRC_FMT_24bppYCC444, + JXRC_FMT_30bppYCC444, + JXRC_FMT_48bppYCC444, + JXRC_FMT_48bppYCC444FixedPoint, + JXRC_FMT_20bppYCC420Alpha, + JXRC_FMT_24bppYCC422Alpha, + JXRC_FMT_30bppYCC422Alpha, + JXRC_FMT_48bppYCC422Alpha, + JXRC_FMT_32bppYCC444Alpha, + JXRC_FMT_40bppYCC444Alpha, + JXRC_FMT_64bppYCC444Alpha, + JXRC_FMT_64bppYCC444AlphaFixedPoint, +}jxrc_t_pixelFormat; + + +#define UNDEF_GUID (NUM_GUIDS + 1) +/* +* Given a clean container handle, read the specified file (open for +* read) to get all the characteristics of the container. This just +* opens and parses the container, it does *not* decompress the +* image, or even necessarily read the image data. That is left for +* the jxr_read_image_bitstream below. Instead, this function just +* collects all the data in the container tags and makes it available +* via the jxrc_* functions below. +* +* JXR_EC_BADMAGIC +* The magic number is wrong, implying that it is not an JPEG XR +* container. Perhaps it is a bitstream? +*/ +JXR_EXTERN int jxr_read_image_container(jxr_container_t c, FILE*fd); + +/* +* jxr_c_image_count returns the number of images in this +* container. The images are then numbers starting from 0, with 0 +* intended to be the default view. +*/ +JXR_EXTERN int jxrc_image_count(jxr_container_t c); + +/* File position for image in container. */ +JXR_EXTERN unsigned long jxrc_image_offset(jxr_container_t c, int image); +/* Byte count for image in container. */ +JXR_EXTERN unsigned long jxrc_image_bytecount(jxr_container_t c, int image); +/* File position for alpha image plane in container. */ +JXR_EXTERN unsigned long jxrc_alpha_offset(jxr_container_t c, int image); +/* Byte count for alpha image in container. */ +JXR_EXTERN unsigned long jxrc_alpha_bytecount(jxr_container_t c, int image); +/* Pixel format for image in container */ +JXR_EXTERN jxrc_t_pixelFormat jxrc_image_pixelformat(jxr_container_t c, int imagenum); +/* Image width in container*/ +JXR_EXTERN unsigned long jxrc_image_width(jxr_container_t container, int image); +/* Profile/Level in the container */ +JXR_EXTERN int jxrc_profile_level_container(jxr_container_t container, int image, unsigned char * profile, unsigned char * level); +/* Image height in container*/ +JXR_EXTERN unsigned long jxrc_image_height(jxr_container_t container, int image); +/* Spatial transfrom primary in container*/ +JXR_EXTERN unsigned long jxrc_spatial_xfrm_primary(jxr_container_t container, int image); +/* Width resolution in container */ +JXR_EXTERN float jxrc_width_resolution(jxr_container_t container, int image); +/* Height resolution in container */ +JXR_EXTERN float jxrc_height_resolution(jxr_container_t container, int image); +/* Image band presence in container */ +JXR_EXTERN unsigned char jxrc_image_band_presence(jxr_container_t container, int image); +/* Alpha band presence in container */ +JXR_EXTERN unsigned char jxrc_alpha_band_presence(jxr_container_t container, int image); +/* Image type in container */ +JXR_EXTERN unsigned long jxrc_image_type(jxr_container_t container, int image); +/* PTM Color Info in container */ +JXR_EXTERN int jxrc_ptm_color_info(jxr_container_t container, int image, unsigned char * buf); +/* Color space info in container */ +JXR_EXTERN unsigned short jxrc_color_space(jxr_container_t container, int image); +/* UTF8 strings in container */ +JXR_EXTERN int jxrc_document_name(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_image_description(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_equipment_make(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_equipment_model(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_page_name(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_software_name_version(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_date_time(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_artist_name(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_host_computer(jxr_container_t container, int image, char ** string); +JXR_EXTERN int jxrc_copyright_notice(jxr_container_t container, int image, char ** string); +/* page number in container */ +JXR_EXTERN int jxrc_page_number(jxr_container_t container, int image, unsigned short * value); +/* padding data in container */ +JXR_EXTERN int jxrc_padding_data(jxr_container_t container, int image); + +/* +* When writing an image file, start with a call to +* jxrc_start_file. This binds the FILE pointer to the container and +* gets the file pointers started. +* +* Then use the jxrc_begin_ifd_entry() function to create the next ifd +* entry. This makes the next IFD ready for its settings. Load the +* settings to reflect the image using the jxrc_set_* functions. +* +* When ready to start writing the image, use the jxr_begin_image_data +* to close the ifd and start writing the image data. At this point +* the caller can write the bit stream data itself. +* +* The jxrc_write_container_post, finalizes the +* IFD value for IMAGE_BYTE_COUNT and IMAGE_OFFSET and leaves the pointer ready for the end of the image. +* +* The jxrc_write_container_post_alpha, finalizes the +* IFD value for ALPHA_BYTE_COUNT and ALPHA_OFFSET and leaves the pointer ready for the end of the image. +* +*/ + +JXR_EXTERN int jxrc_start_file(jxr_container_t c, FILE*fd); + +JXR_EXTERN int jxrc_begin_ifd_entry(jxr_container_t c); +JXR_EXTERN int jxrc_set_pixel_format(jxr_container_t c, jxrc_t_pixelFormat fmt); +JXR_EXTERN jxrc_t_pixelFormat jxrc_get_pixel_format(jxr_container_t c); +JXR_EXTERN int jxrc_set_image_shape(jxr_container_t c, unsigned wid, unsigned hei); +JXR_EXTERN int jxrc_set_image_band_presence(jxr_container_t cp, unsigned bands); +JXR_EXTERN int jxrc_set_separate_alpha_image_plane(jxr_container_t cp, unsigned int alpha_present); + +JXR_EXTERN int jxrc_begin_image_data(jxr_container_t c); +JXR_EXTERN int jxrc_write_container_post(jxr_container_t c); +JXR_EXTERN int jxrc_write_container_post_alpha(jxr_container_t c); + +/* JPEG XR BITSTREAM */ + +/* +* The jxr_image_t is an opaque image type that represents an JPEG-XR +* bitstream image. It holds the state for various of the following +* operations. +* +* For reading (decompress), the general process goes like this: +* +* - Create an jxr_image_t object with the jxr_create_input() function, +* +* - Attach a callback function to receive blocks of image data with +* the jxr_set_block_output() function, then +* +* - Run the decompress with the jxr_read_image_bitstream() function. +* +* - Destroy the jxr_image_T object with the jxr_destroy() function. +* +* The jxr_read_image_bitstream() function calls the user block +* function periodically with data for a macroblock (16x16 pixels) of +* the image. The callback function dispatches the data, for example +* by formatting it into an image buffer or writing it to an output +* file or rendering it to the screen. +*/ +typedef struct jxr_image *jxr_image_t; + +/* +* Create (destroy) an JPEG XR image cookie. +* +* jxr_create_image - +* Create an jxr_image_t handle that will be used for writing an +* image out. +* +* jxr_create_input - +* Create an jxr_image_t handle that can be used to read an image. +* +* jxr_destroy - +* Destroy an jxr_image_t object. +*/ +JXR_EXTERN jxr_image_t jxr_create_image(int width, int height, unsigned char * windowing); +JXR_EXTERN jxr_image_t jxr_create_input(void); +JXR_EXTERN void jxr_destroy(jxr_image_t image); + +/* +* Some user-controlled flags. +*/ +JXR_EXTERN void jxr_flag_SKIP_HP_DATA(jxr_image_t image, int flag); +JXR_EXTERN void jxr_flag_SKIP_FLEX_DATA(jxr_image_t image, int flag); + +/* +* Applications may attach a single pointer to the jxr_image_t handle, +* and retrieve it anytime, including within callbacks. The user data +* is intended to be used by the callbacks to get information about +* the context of the image process. +*/ +JXR_EXTERN void jxr_set_user_data(jxr_image_t image, void*data); +JXR_EXTERN void*jxr_get_user_data(jxr_image_t image); + +/* +* Functions for getting/setting various flags of the image. These +* either reflect the image that has been read, or controls how to +* write the image out. +* +* IMAGE_WIDTH/IMAGE_HEIGHT +* Dimensions of the image. +* +* IMAGE_CHANNELS +* Number of channels in the image (not including alpha). For +* example, 1==GRAY, 3==RGB. +* +* TILING_FLAG +* TRUE if tiles are present in the image. +* +* FREQUENCY_MODE_CODESTREAM_FLAG +* 0 == Spatial mode +* 1 == Frequency mode +* +* TILE_WIDTH/TILE_HEIGHT +* Dimensions of the tile rows/columns if present in the image, or +* 0 otherwise. The widths/heights of all the columns/rows will +* always be a multiple of 16 (the size of a macroblock). +* +* WINDOWING_FLAG +* TRUE if there are windowin parameters in the image. +* +* ALPHACHANNEL_FLAG +* TRUE if there is an alpha channel present. +* +* NOTE about setting flags: In many cases, the order that you set +* things matters as internal configuration is devined from previous +* values. So the order that jxr_set_* functions are listed in this +* file is the order they should be applied to a file that is being +* built up for output. +*/ +JXR_EXTERN unsigned jxr_get_IMAGE_WIDTH(jxr_image_t image); +JXR_EXTERN unsigned jxr_get_IMAGE_HEIGHT(jxr_image_t image); +JXR_EXTERN unsigned jxr_get_EXTENDED_IMAGE_WIDTH(jxr_image_t image); +JXR_EXTERN unsigned jxr_get_EXTENDED_IMAGE_HEIGHT(jxr_image_t image); +JXR_EXTERN int jxr_get_IMAGE_CHANNELS(jxr_image_t image); +JXR_EXTERN int jxr_get_TILING_FLAG(jxr_image_t image); +JXR_EXTERN int jxr_get_FREQUENCY_MODE_CODESTREAM_FLAG(jxr_image_t image); +JXR_EXTERN unsigned jxr_get_TILE_COLUMNS(jxr_image_t image); +JXR_EXTERN unsigned jxr_get_TILE_ROWS(jxr_image_t image); +JXR_EXTERN int jxr_get_TILE_WIDTH(jxr_image_t image, unsigned column); +JXR_EXTERN int jxr_get_TILE_HEIGHT(jxr_image_t image, unsigned row); + +JXR_EXTERN int jxr_get_ALPHACHANNEL_FLAG(jxr_image_t image); +JXR_EXTERN jxrc_t_pixelFormat jxr_get_pixel_format(jxr_image_t image); + +/* +* This is the "Internal" color format of the image. It is the color +* mode that is used to encode the image data. These are the only +* formats that JPEG XR supports directly. This is not the same as +* the EXTERNAL color format, which is the format that the user +* presents/receives the data in. The available external formats are a +* larger set. +*/ +typedef enum jxr_color_fmt_e{ + JXR_YONLY = 0, + JXR_YUV420 = 1, + JXR_YUV422 = 2, + JXR_YUV444 = 3, + JXR_YUVK = 4, + JXR_fmt_reserved5 = 5, + JXR_NCOMPONENT = 6, + JXR_fmt_reserved7 = 7 +}jxr_color_fmt_t; + +JXR_EXTERN void jxr_set_INTERNAL_CLR_FMT(jxr_image_t image, jxr_color_fmt_t fmt, int channels); + +/* +* This is the "output" color format of the image. +*/ +typedef enum jxr_output_clr_fmt_e{ + JXR_OCF_YONLY = 0, + JXR_OCF_YUV420 = 1, + JXR_OCF_YUV422 = 2, + JXR_OCF_YUV444 = 3, + JXR_OCF_CMYK = 4, + JXR_OCF_CMYKDIRECT = 5, + JXR_OCF_NCOMPONENT = 6, + JXR_OCF_RGB = 7, + JXR_OCF_RGBE = 8, + JXR_OCF_fmt_reserved9 = 9, + JXR_OCF_fmt_reserved10 = 10, + JXR_OCF_fmt_reserved11 = 11, + JXR_OCF_fmt_reserved12 = 12, + JXR_OCF_fmt_reserved13 = 13, + JXR_OCF_fmt_reserved14 = 14, + JXR_OCF_fmt_reserved15 = 15 +}jxr_output_clr_fmt_t; + +JXR_EXTERN void jxr_set_OUTPUT_CLR_FMT(jxr_image_t image, jxr_output_clr_fmt_t fmt); +JXR_EXTERN jxr_output_clr_fmt_t jxr_get_OUTPUT_CLR_FMT(jxr_image_t image); + + +/* +* This is the bit depth to use. +*/ +typedef enum jxr_bitdepth_e{ + JXR_BD1WHITE1 = 0, + JXR_BD8 = 1, + JXR_BD16 = 2, + JXR_BD16S = 3, + JXR_BD16F = 4, + JXR_BDRESERVED = 5, + JXR_BD32S = 6, + JXR_BD32F = 7, + JXR_BD5 = 8, + JXR_BD10 = 9, + JXR_BD565 = 10, + JXR_BD1BLACK1 = 15 +}jxr_bitdepth_t; + +JXR_EXTERN jxr_bitdepth_t jxr_get_OUTPUT_BITDEPTH(jxr_image_t image); +JXR_EXTERN void jxr_set_OUTPUT_BITDEPTH(jxr_image_t image, jxr_bitdepth_t bd); +JXR_EXTERN void jxr_set_SHIFT_BITS(jxr_image_t image, unsigned char shift_bits); +JXR_EXTERN void jxr_set_FLOAT(jxr_image_t image, unsigned char len_mantissa, char exp_bias); + +/* +* This sets the frequency bands that are to be included in the +* image. The more bands are included, the higher the fidelity of the +* compression, but also the larger the image result. +* +* If FLEXBITS are included, the TRIM_FLEXBITS value can be used to +* reduce the amount of FLEXBIT data included. If 0 (the default) then +* all the flexbit data is included, if trim==1, then 1 bit of flexbit +* data is trimmed, and so on. TRIM_FLECBITS must be 0 <= TRIM_FLEXBITS <= 15. +*/ +typedef enum jxr_bands_present_e{ + JXR_BP_ALL = 0, + JXR_BP_NOFLEXBITS = 1, + JXR_BP_NOHIGHPASS = 2, + JXR_BP_DCONLY = 3, + JXR_BP_ISOLATED = 4 +}jxr_bands_present_t; + +JXR_EXTERN void jxr_set_BANDS_PRESENT(jxr_image_t image, jxr_bands_present_t bp); +JXR_EXTERN void jxr_set_TRIM_FLEXBITS(jxr_image_t image, int trim); +/* Filtering +* Control overlap filtering with this function. +* +* - 0 +* No overlap filtering. (The default) +* +* - 1 +* Filter only the first stage, right before the first lifting pass. +* +* - 2 +* Filter first and second stage. +* +* - 3 +* Reserved +* +* All other values for flag are out of range. +*/ +JXR_EXTERN void jxr_set_OVERLAP_FILTER(jxr_image_t image, int flag); + +/* HardTiles +* Controls overlap filtering on tile boundaries +* +* - 0 +* Corresonds to soft tiles. Overlap Filtering is appiled across tile boundaries. (The default) +* +* -1 +* Corresonds to hard tiles. Overlap Filtering is not appiled across tile boundaries. (The default) +* Instead, tile boundaries and corners are treated like image boundaries and image corners +* +* All other values are out of range +*/ +JXR_EXTERN void jxr_set_DISABLE_TILE_OVERLAP(jxr_image_t image, int flag); +JXR_EXTERN void jxr_set_FREQUENCY_MODE_CODESTREAM_FLAG(jxr_image_t image, int flag); +JXR_EXTERN void jxr_set_INDEX_TABLE_PRESENT_FLAG(jxr_image_t image, int flag); +JXR_EXTERN void jxr_set_ALPHA_IMAGE_PLANE_FLAG(jxr_image_t image, int flag); +JXR_EXTERN void jxr_set_PROFILE_IDC(jxr_image_t image, int profile_idc); +JXR_EXTERN void jxr_set_LEVEL_IDC(jxr_image_t image, int level_idc); +JXR_EXTERN void jxr_set_LONG_WORD_FLAG(jxr_image_t image, int flag); +JXR_EXTERN int jxr_test_PROFILE_IDC(jxr_image_t image, int flag); +JXR_EXTERN int jxr_test_LEVEL_IDC(jxr_image_t image, int flag); + +JXR_EXTERN void jxr_set_NUM_VER_TILES_MINUS1(jxr_image_t image, unsigned num); +JXR_EXTERN void jxr_set_TILE_WIDTH_IN_MB(jxr_image_t image, unsigned* list); +JXR_EXTERN void jxr_set_NUM_HOR_TILES_MINUS1(jxr_image_t image, unsigned num); +JXR_EXTERN void jxr_set_TILE_HEIGHT_IN_MB(jxr_image_t image, unsigned* list); +JXR_EXTERN void jxr_set_TILING_FLAG(jxr_image_t image, int flag); +JXR_EXTERN void jxr_set_container_parameters(jxr_image_t image, jxrc_t_pixelFormat pixel_format, unsigned wid, unsigned hei, unsigned separate, unsigned char image_presence, unsigned char alpha_presence, unsigned char alpha); + +/* +* It is a consequence of the JXR format that an image can have no +* more then 16 channels. This is because the channels count field is +* only 4 bits wide. This is also true of NUM_LP_QPS and +* NUM_HP_QPS. These constants can thus be used to size so tables. +*/ + +# define MAX_CHANNELS 16 +# define MAX_LP_QPS 16 +# define MAX_HP_QPS 16 + +/* Quantization +* These are functions to set up the quantization to be used for +* encoding. Only one of these can be used for a given image. The +* control over the QP values depends on which function you use. +* +* - set_QP_LOSSLESS() +* Configure the QP values for lossless compression. This will also +* set up the SCALED_FLAG appropriately. Note that this is not really +* lossless unless all the bands are present. +* +* NOTE 1: DC/LP/HP_IMAGEPLANE_UNIFORM is set to true because the +* quantization value is uniform identity. +* +* NOTE 2: Grayscale images will be configured with channel mode +* UNIFORM. +* +* NOTE 3: Although lossless can be achieved with channel modes of +* UNIFORM, SEPARATE and INDEPENDENT, this function will set +* the channel mode to SEPARATE for color images. +* +* - set_QP_UNIFORM() +* All the bands/channels are set with the same QP value. If the +* use_dc_only flag it false, then the DC/LP/HP values are identical, +* but encoded distinctly. +* +* NOTE 1: DC/LP/HP_IMAGEPLANE_UNIFORM is set to true so that the QP +* are kept in the plane header. +* +* - set_QP_SEPARATE +* All the bands are set with the same QP value, depending on the +* component. The Y component gets the first quant value, and the +* remaining channels get the other quant value. +* +* NOTE 1: DC/LP/HP_IMAGEPLANE_UNIFORM is set to true so that the QP +* are kept in the plane header. +* +* NOTE 2: This should NOT be applied to grayscale images. Images +* with 1 channel must have channel mode UNIFORM. +* +* - set_QP_INDEPENDENT +* All the bands are set with the same QP value, but each channel gets +* its own QP value. +* +* NOTE 1: DC/LP/HP_IMAGEPLANE_UNIFORM is set to true so that the QP +* are kept in the plane header. +* +* NOTE 2: For single channel images (i.e. grayscale) this actually +* sets the channel mode to UNIFORM. Only the UNIFORM +* channel mode is valid for grayscale. +* +* - set_QP_DISTRIBUTED +* This is the most complex form. Every tile/channel can have its own +* QP set, and that QP set is mapped onto each +* tile/channel/macroblock. The argument to the set_QP_DISTRIBUTED +* function is an array of jxr_time_qp objects, one object per tile in +* the complete image. +* +* NOTE 1: The tile configuration must be set before this function is +* called. If no tile configuration is set, then there is +* exactly 1 tile. +* NOTE 2: set_QP_DISTRIBUTED causes DC/LP/HP_IMAGEPLANE_UNIFORM to be +* false so that the QP values are moved to tile headers. +*/ + +JXR_EXTERN void jxr_set_QP_LOSSLESS(jxr_image_t image); +JXR_EXTERN void jxr_set_QP_UNIFORM(jxr_image_t image, unsigned char quant); +JXR_EXTERN void jxr_set_QP_SEPARATE(jxr_image_t image, unsigned char*quant_y_uv); +JXR_EXTERN void jxr_set_QP_INDEPENDENT(jxr_image_t image, unsigned char*quant_per_channel); + + +struct jxr_tile_channel_qp{ + /* These are all the QP values available for the tile. A + tile/channel can have only 1 unique DC QP value, and up to + 16 (each) LP and HP QP values. */ + unsigned char dc_qp; + unsigned char num_lp, num_hp; /* Number for LP/HP QP values. */ + unsigned char lp_qp[16]; + unsigned char hp_qp[16]; +}; + +typedef enum jxr_component_mode_e{ + JXR_CM_UNIFORM = 0, + JXR_CM_SEPARATE = 1, + JXR_CM_INDEPENDENT = 2, + JXR_CM_Reserved = 3 +}jxr_component_mode_t; + +struct jxr_tile_qp{ + /* For every channel, have an jxr_tile_qp for all the tiles in + the image. Each jxr_tile_channel_qp represents the QP + values for a tile/channel. There are (up to) 16 channels, + and each channel points to an array of jxr_tile_qp + objects, depending on the component_mode. If the mode is + UNIFORM, then there is only one channel of data that is + shared for all components, etc. */ + jxr_component_mode_t component_mode; + struct jxr_tile_channel_qp channel[16]; + /* Map the LP/HP QP values to the macroblocks. There are as + many bytes in each array as there are macroblocks in the + tile, and the value at each byte is the index into the + table above. This is how the QP values are mapped to + macroblocks. */ + unsigned char*lp_map; + unsigned char*hp_map; + /* Per tile Quantization parameters for up to 16 channels. This is required when quantization step sizes vary across tiles */ + unsigned char dc_quant_ch[MAX_CHANNELS]; + unsigned char lp_quant_ch[MAX_CHANNELS][MAX_LP_QPS]; + unsigned char hp_quant_ch[MAX_CHANNELS][MAX_HP_QPS]; +}; + +typedef struct raw_info { + unsigned int is_raw; + unsigned int raw_width; + unsigned int raw_height; + unsigned char raw_format; + unsigned char raw_bpc; +} raw_info; + +JXR_EXTERN void jxr_set_QP_DISTRIBUTED(jxr_image_t image, struct jxr_tile_qp*qp); + + +/* +* Callbacks +* +* jxr_set_block_output - +* During read of a compressed bitstream, the block_output function +* is used to report that a 16x16 macroblock is complete. The +* application is called back via a function of type block_fun_t to +* receive and dispense with the data. +*/ +typedef void (*block_fun_t)(jxr_image_t image, int mx, int my, int*data); + +JXR_EXTERN void jxr_set_block_input (jxr_image_t image, block_fun_t fun); +JXR_EXTERN void jxr_set_block_output(jxr_image_t image, block_fun_t fun); + +JXR_EXTERN void jxr_set_pixel_format(jxr_image_t image, jxrc_t_pixelFormat pixelFormat); +/* +* After the jxr_image_t object is all set up, the +* jxr_read_image_bitstream function is called to read the bitstream +* and decompress it. This function assumes that the fd is open for +* read and set to the beginning of the bitstream (where the magic +* number starts). +* +* JXR_EC_BADMAGIC +* The magic number is wrong, implying that it is not an JPEG XR +* bitstream. +*/ +JXR_EXTERN int jxr_read_image_bitstream(jxr_image_t image, FILE*fd); + +/* +* After decoder is run, test desired LONG_WORD_FLAG against +* calculations done in decoder +*/ +JXR_EXTERN int jxr_test_LONG_WORD_FLAG(jxr_image_t image, int flag); + +/* +* Given an image cookie that represents an image, and an fd opened +* for write, write the entire JPEG XR bit stream. +*/ +JXR_EXTERN int jxr_write_image_bitstream(jxr_image_t image, FILE*fd); + + +/* +* jxr error codes. Many of the above functions return a positive +* (>=0) value or a negative error code. The error codes are: +*/ + +# define JXR_EC_OK (0) /* No error */ +# define JXR_EC_ERROR (-1) /* Unspecified error */ +# define JXR_EC_BADMAGIC (-2) /* Stream lacks proper magic number. */ +# define JXR_EC_FEATURE_NOT_IMPLEMENTED (-3) +# define JXR_EC_IO (-4) /* Error reading/writing data */ +# define JXR_EC_BADFORMAT (-5) /* Bad file format */ + + +#undef JXR_EXTERN + +/* +* $Log: jpegxr.h,v $ +* Revision 1.28 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.27 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.26 2008/03/18 18:36:56 steve +* Support compress of CMYK images. +* +* Revision 1.25 2008/03/18 15:50:08 steve +* Gray images must be UNIFORM +* +* Revision 1.24 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.23 2008/03/05 04:04:30 steve +* Clarify constraints on USE_DC_QP in image plane header. +* +* Revision 1.22 2008/03/05 01:27:15 steve +* QP_UNIFORM may use USE_DC_LP optionally. +* +* Revision 1.21 2008/03/05 00:31:17 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.20 2008/03/04 23:01:28 steve +* Cleanup QP API in preparation for distributed QP +* +* Revision 1.19 2008/03/02 19:56:27 steve +* Infrastructure to read write BD16 files. +* +* Revision 1.18 2008/03/01 02:46:09 steve +* Add support for JXR container. +* +* Revision 1.17 2008/02/29 01:29:57 steve +* Mark more extern functions for MSC. +* +* Revision 1.16 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.15 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.14 2008/02/26 23:28:53 steve +* Remove C99 requirements from the API. +* +* Revision 1.13 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.12 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.11 2008/01/06 01:29:28 steve +* Add support for TRIM_FLEXBITS in compression. +* +* Revision 1.10 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.9 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.8 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.7 2007/11/08 02:52:32 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.6 2007/11/07 18:11:45 steve +* Missing error code. +* +* Revision 1.5 2007/11/06 22:32:34 steve +* Documentation for the jpegxr library use. +* +* Revision 1.4 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.3 2007/07/30 23:09:57 steve +* Interleave FLEXBITS within HP block. +* +* Revision 1.2 2007/07/21 00:25:48 steve +* snapshot 2007 07 20 +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + +#endif diff --git a/jpegxr/jpegxr_pixelformat.c b/jpegxr/jpegxr_pixelformat.c new file mode 100644 index 000000000..b68d28be8 --- /dev/null +++ b/jpegxr/jpegxr_pixelformat.c @@ -0,0 +1,156 @@ +/* +** +** $Id: jpegxr_priv.c,v 1.0 2009-02-23 13:47:11 Radhika Exp $ +** +** +*/ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: jpegxr_priv.c,v 1.0 2009-02-23 13:47:11 Radhika Exp $") +#else +#ident "$Id: jpegxr_priv.c,v 1.0 2009-02-23 13:47:11 Radhika Exp $" +#endif +#include "jxr_priv.h" +#include <string.h> +/* +* This file contains functions for pixel format parsing +*/ +unsigned char jxr_guids[NUM_GUIDS][16]= +{ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0D},/* JXR_24bppRGB = 0, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0C},/* JXR_24bppBGR, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0E},/* JXR_32bppBGR, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x15},/* JXR_48bppRGB, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x12},/* JXR_48bppRGBFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x3B},/* JXR_48bppRGBHalf, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x18},/* JXR_96bppRGBFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x40},/* JXR_64bppRGBFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x42},/* JXR_64bppRGBHalf, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x41},/* JXR_128bppRGBFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1B},/* JXR_128bppRGBFloat, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0F},/* JXR_32bppBGRA, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x16},/* JXR_64bppRGBA, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1D},/* JXR_64bppRGBAFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x3A},/* JXR_64bppRGBAHalf, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1E},/* JXR_128bppRGBAFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x19},/* JXR_128bppRGBAFloat, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x10},/* JXR_32bppPBGRA, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x17},/* JXR_64bppPRGBA, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1A},/* JXR_128bppPRGBAFloat, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1C},/* JXR_32bppCMYK, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2C},/* JXR_40bppCMYKAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x1F},/* JXR_64bppCMYK, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2D},/* JXR_80bppCMYKAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x20},/* JXR_24bpp3Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x21},/* JXR_32bpp4Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x22},/* JXR_40bpp5Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x23},/* JXR_48bpp6Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x24},/* JXR_56bpp7Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x25},/* JXR_64bpp8Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2E},/* JXR_32bpp3ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2F},/* JXR_40bpp4ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x30},/* JXR_48bpp5ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x31},/* JXR_56bpp6ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x32},/* JXR_64bpp7ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x33},/* JXR_72bpp8ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x26},/* JXR_48bpp3Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x27},/* JXR_64bpp4Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x28},/* JXR_80bpp5Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x29},/* JXR_96bpp6Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2A},/* JXR_112bpp7Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x2B},/* JXR_128bpp8Channels, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x34},/* JXR_64bpp3ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x35},/* JXR_80bpp4ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x36},/* JXR_96bpp5ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x37},/* JXR_112bpp6ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x38},/* JXR_128bpp7ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x39},/* JXR_144bpp8ChannelsAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x08},/* JXR_8bppGray, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0B},/* JXR_16bppGray, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x13},/* JXR_16bppGrayFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x3E},/* JXR_16bppGrayHalf, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x3F},/* JXR_32bppGrayFixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x11},/* JXR_32bppGrayFloat, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x05},/* JXR_BlackWhite, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x09},/* JXR_16bppBGR555, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x0A},/* JXR_16bppBGR565, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x14},/* JXR_32bppBGR101010, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x3D},/* JXR_32bppRGBE, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x54},/* JXR_32bppCMYKDIRECT, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x55},/* JXR_64bppCMYKDIRECT, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x56},/* JXR_40bppCMYKDIRECTAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x43},/* JXR_80bppCMYKDIRECTAlpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x44},/* JXR_12bppYCC420, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x45},/* JXR_16bppYCC422, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x46},/* JXR_20bppYCC422, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x47},/* JXR_32bppYCC422, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x48},/* JXR_24bppYCC444, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x49},/* JXR_30bppYCC444, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4A},/* JXR_48bppYCC444, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4B},/* JXR_48bppYCC444FixedPoint, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4C},/* JXR_20bppYCC420Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4D},/* JXR_24bppYCC422Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4E},/* JXR_30bppYCC422Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x4F},/* JXR_48bppYCC422Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x50},/* JXR_32bppYCC444Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x51},/* JXR_40bppYCC444Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x52},/* JXR_64bppYCC444Alpha, */ + {0x24, 0xC3, 0xDD, 0x6F, 03, 0x4E, 0xFE, 0x4B, 0xB1, 0x85, 0x3D, 0x77, 0x76, 0x8D, 0xC9, 0x53} /* JXR_64bppYCC444AlphaFixedPoint, */ +}; + +unsigned int isEqualGUID(unsigned char guid1[16], unsigned char guid2[16]) +{ + return memcmp(guid1,guid2,16) == 0; +} + + +/* +* $Log: jpegxr_pixelformat.c,v $ +* Revision 1.2 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.1 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +*/ + diff --git a/jpegxr/jxr_priv.h b/jpegxr/jxr_priv.h new file mode 100644 index 000000000..a46134746 --- /dev/null +++ b/jpegxr/jxr_priv.h @@ -0,0 +1,821 @@ +#ifndef __jxr_priv_H +#define __jxr_priv_H +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: jxr_priv.h,v 1.3 2008-05-13 13:47:11 thor Exp $") +#else +#ident "$Id: jxr_priv.h,v 1.3 2008-05-13 13:47:11 thor Exp $" +#endif + +# include "jpegxr.h" + +#ifndef _MSC_VER +# include <stdint.h> +#else +/* MSVC (as of 2008) does not support C99 or the stdint.h header +file. So include a private little header file here that does the +minimal typedefs that we need. */ +# include "stdint_minimal.h" +#endif + +/* define this to check if range of values exceeds signed 16-bit */ +#define VERIFY_16BIT + +#ifdef VERIFY_16BIT +#define CHECK1(flag, a) if(((a) < -0x8000) || ((a) >= 0x8000)) flag = 1 +#else +#define CHECK1(flag, a) do { } while(0) +#endif + +#define CHECK2(flag, a, b) CHECK1(flag, a); CHECK1(flag, b) +#define CHECK3(flag, a, b, c) CHECK2(flag, a, b); CHECK1(flag, c) +#define CHECK4(flag, a, b, c, d) CHECK3(flag, a, b, c); CHECK1(flag, d) +#define CHECK5(flag, a, b, c, d, e) CHECK4(flag, a, b, c, d); CHECK1(flag, e) +#define CHECK6(flag, a, b, c, d, e, f) CHECK5(flag, a, b, c, d, e); CHECK1(flag, f) + +struct macroblock_s{ + int*data; + /* This is used to temporarily hold Predicted values. */ + int*pred_dclp; + /* */ + unsigned lp_quant : 8; + unsigned hp_quant : 8; + int mbhp_pred_mode : 3; + int have_qnt : 1;/* THOR: If set, the quant values are valid */ + /* Stash HP CBP values for the macroblock. */ + int hp_cbp, hp_diff_cbp; + /* model_bits for current HP. HP uses this to pass model_bits + to FLEXBITS parsing. */ + unsigned hp_model_bits[2]; +}; + +struct adaptive_vlc_s{ + int discriminant; + int discriminant2; + int table; + int deltatable; + int delta2table; +}; + +struct cbp_model_s{ + int state[2]; + int count0[2]; + int count1[2]; +}; + +typedef enum abs_level_vlc_index_e{ + AbsLevelIndDCLum, + AbsLevelIndDCChr, + DecFirstIndLPLum, + AbsLevelIndLP0, + AbsLevelIndLP1, + AbsLevelIndHP0, + AbsLevelIndHP1, + DecIndLPLum0, + DecIndLPLum1, + DecFirstIndLPChr, + DecIndLPChr0, + DecIndLPChr1, + DecNumCBP, + DecNumBlkCBP, + DecIndHPLum0, + DecIndHPLum1, + DecFirstIndHPLum, + DecFirstIndHPChr, + DecIndHPChr0, + DecIndHPChr1, + AbsLevelInd_COUNT +}abs_level_vlc_index_t; + +struct model_s{ + int bits[2]; + int state[2]; +}; + +struct jxr_image{ + int user_flags; + + /* These store are the width/height minus 1 (so that 4Gwidth + is OK but 0 width is not.) This, by the way, is how the + width/height is stored in the HPPhoto stream too. */ + uint32_t width1; + uint32_t height1; + uint32_t extended_width; + uint32_t extended_height; + + uint8_t header_flags1; + uint8_t header_flags2; + /* Color format of the source image data */ + uint8_t header_flags_fmt; + jxr_output_clr_fmt_t output_clr_fmt; + /* Color format to use internally. */ + /* 0=YONLY, 1=YUV420, 2=YUV422, 3=YUV444, 4=CMYK, 5=CMYKDIRECT, 6=NCOMPONENT */ + uint8_t use_clr_fmt; + + /* pixel format */ + jxrc_t_pixelFormat ePixelFormat; + + /* If TRIM_FLEXBITS_FLAG, then this is the bits to trim. */ + unsigned trim_flexbits : 4; + + /* 0==ALL, 1==NOFLEXBITS, 2==NOHIGHPASS, 3==DCONLY, 4==ISOLATED */ + uint8_t bands_present; + uint8_t bands_present_of_primary; /* stores value of primary image plane to apply restriction on value of alpha image plane */ + + uint8_t chroma_centering_x; + uint8_t chroma_centering_y; + + uint8_t num_channels; + + /* Disable overlap flag, true for hard tiles, false for soft tiles*/ + unsigned disableTileOverlapFlag; + + unsigned tile_rows; + unsigned tile_columns; + unsigned*tile_row_height; + unsigned*tile_column_width; + /* This is the position in image macroblocks. */ + unsigned*tile_column_position; + unsigned*tile_row_position; + /* The numbers collected by INDEX_TABLE */ + int64_t*tile_index_table; + int64_t tile_index_table_length; + + uint16_t window_extra_top; + uint16_t window_extra_left; + uint16_t window_extra_bottom; + uint16_t window_extra_right; + + /* Information from the plane header. */ + + unsigned scaled_flag : 1; + unsigned dc_frame_uniform : 1; + unsigned lp_use_dc_qp : 1; + unsigned lp_frame_uniform : 1; + unsigned hp_use_lp_qp : 1; + unsigned hp_frame_uniform : 1; + + unsigned char shift_bits; + unsigned char len_mantissa; + char exp_bias; + + /* Per-tile information (changes as tiles are processed) */ + unsigned num_lp_qps; + unsigned num_hp_qps; + + /* State variables used by encoder/decoder. */ + int cur_my; /* Address of strip_cur */ + struct{ + struct macroblock_s*up4; + struct macroblock_s*up3; + struct macroblock_s*up2; + struct macroblock_s*up1; + struct macroblock_s*cur; + int *upsample_memory_y; /* Number of elements is dependent on number of MBs in each MB row */ + int *upsample_memory_x; /* Always contains 16 elements */ + }strip[MAX_CHANNELS]; + + /* SPATIAL: Hold previous strips of current tile */ + /* FREQUENCY: mbs for the entire image. */ + struct macroblock_s*mb_row_buffer[MAX_CHANNELS]; + /* Hold final 4 strips of previous tile */ + struct macroblock_s*mb_row_context[MAX_CHANNELS]; + + struct adaptive_vlc_s vlc_table[AbsLevelInd_COUNT]; + int count_max_CBPLP; + int count_zero_CBPLP; + + struct cbp_model_s hp_cbp_model; + + unsigned lopass_scanorder[15]; + unsigned lopass_scantotals[15]; + + unsigned hipass_hor_scanorder[15]; + unsigned hipass_hor_scantotals[15]; + unsigned hipass_ver_scanorder[15]; + unsigned hipass_ver_scantotals[15]; + + jxr_component_mode_t dc_component_mode, lp_component_mode, hp_component_mode; + + /* Quantization parameters for up to 16 channels. */ + unsigned char dc_quant_ch[MAX_CHANNELS]; + unsigned char lp_quant_ch[MAX_CHANNELS][MAX_LP_QPS]; + unsigned char hp_quant_ch[MAX_CHANNELS][MAX_HP_QPS]; +# define HP_QUANT_Y hp_quant_ch[0] + + /* Per-tile quantization data (used during encode) */ + struct jxr_tile_qp*tile_quant; +# define GET_TILE_QUANT(image,tx,ty) ((image)->tile_quant + (ty)*((image)->tile_rows+1) + (tx)) + + struct model_s model_dc, model_lp, model_hp; + + struct model_s*model_hp_buffer; + struct cbp_model_s*hp_cbp_model_buffer; + + block_fun_t out_fun; + block_fun_t inp_fun; + void*user_data; + + struct jxr_image * alpha; /* interleaved alpha image plane */ + int primary; /* primary channel or alpha channel */ + + uint8_t profile_idc; + uint8_t level_idc; + + uint8_t lwf_test; /* flag to track whether long_word_flag needs to be TRUE */ + + /* store container values */ + uint32_t container_width; + uint32_t container_height; + uint8_t container_nc; + uint8_t container_alpha; + uint8_t container_separate_alpha; + jxr_bitdepth_t container_bpc; + jxr_output_clr_fmt_t container_color; + uint8_t container_image_band_presence; + uint8_t container_alpha_band_presence; + uint8_t container_current_separate_alpha; +}; + +extern unsigned char _jxr_select_lp_index(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern unsigned char _jxr_select_hp_index(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my); + +/* User flags for controlling encode/decode */ +# define SKIP_HP_DATA(image) ((image)->user_flags & 0x0001) +# define SKIP_FLEX_DATA(image) ((image)->user_flags & 0x0002) + +/* Get the width of the image in macroblocks. Round up. */ +# define WIDTH_BLOCKS(image) (((image)->width1 + 16) >> 4) +# define HEIGHT_BLOCKS(image) (((image)->height1 + 16) >> 4) + +# define EXTENDED_WIDTH_BLOCKS(image) (((image)->extended_width) >> 4) +# define EXTENDED_HEIGHT_BLOCKS(image) (((image)->extended_height) >> 4) + +/* TRUE if tiling is supported in this image. */ +# define TILING_FLAG(image) ((image)->header_flags1 & 0x80) +/* TRUE if the bitstream format is frequency mode (FREQUENCY_MODE_CODESTREAM_FLAG is true), FALSE for spatial mode */ +# define FREQUENCY_MODE_CODESTREAM_FLAG(image) ((image)->header_flags1 & 0x40) +/* TRUE if the INDEXTABLE_PRESENT_FLAG is set for the image. */ +# define INDEXTABLE_PRESENT_FLAG(image) ((image)->header_flags1 & 0x04) +/* OVERLAP value: 0, 1, 2 or 3 */ +# define OVERLAP_INFO(image) ((image)->header_flags1 & 0x03) +/* LONG_WORD_FLAG */ +# define LONG_WORD_FLAG(image) ((image)->header_flags2 & 0x40) + +/* TRUE if the SHORT_HEADER flag is set. */ +# define SHORT_HEADER_FLAG(image) ((image)->header_flags2 & 0x80) +/* TRUE if windowing is allowed, 0 otherwise. */ +# define WINDOWING_FLAG(image) ((image)->header_flags2 & 0x20) +# define TRIM_FLEXBITS_FLAG(image) ((image)->header_flags2 & 0x10) +# define ALPHACHANNEL_FLAG(image) ((image)->header_flags2 & 0x01) + +# define SOURCE_CLR_FMT(image) (((image)->header_flags_fmt >> 4) & 0x0f) + +/* SOURCE_BITDEPTH (aka OUTPUT_BITDEPTH) can be: +* 0 BD1WHITE1 +* 1 BD8 +* 2 BD16 +* 3 BD16S +* 4 BD16F +* 5 RESERVED +* 6 BD32S +* 7 BD32F +* 8 BD5 +* 9 BD10 +* 10 BD565 +* 11 RESERVED +* 12 RESERVED +* 13 RESERVED +* 14 RESERVED +* 15 BD1BLACK1 +*/ +# define SOURCE_BITDEPTH(image) (((image)->header_flags_fmt >> 0) & 0x0f) + +/* +* Given the tile index and macroblock index within the tile, return +* the l-value macroblock structure. +*/ +# define MACROBLK_CUR(image,c,tx,mx) ((image)->strip[c].cur[(image)->tile_column_position[tx]+mx]) +# define MACROBLK_UP1(image,c,tx,mx) ((image)->strip[c].up1[(image)->tile_column_position[tx]+mx]) +# define MACROBLK_UP2(image,c,tx,mx) ((image)->strip[c].up2[(image)->tile_column_position[tx]+mx]) +# define MACROBLK_UP3(image,c,tx,mx) ((image)->strip[c].up3[(image)->tile_column_position[tx]+mx]) +# define MACROBLK_UP4(image,c,tx,mx) ((image)->strip[c].up4[(image)->tile_column_position[tx]+mx]) + +/* Return the l-value of the DC coefficient in the macroblock. */ +# define MACROBLK_UP2_DC(image, c, tx, mx) (MACROBLK_UP2(image,c,tx,mx).data[0]) +# define MACROBLK_UP_DC(image, c, tx, mx) (MACROBLK_UP1(image,c,tx,mx).data[0]) +# define MACROBLK_CUR_DC(image, c, tx, mx) (MACROBLK_CUR(image,c,tx,mx).data[0]) +/* Return the l-value of the LP coefficient in the macroblock. +The k value can range from 0-14. (There are 15 LP coefficients.) */ +# define MACROBLK_CUR_LP(image,c,tx,mx,k) (MACROBLK_CUR(image,c,tx,mx).data[1+k]) +# define MACROBLK_UP_LP(image,c,tx,mx,k) (MACROBLK_UP1(image,c,tx,mx).data[1+k]) +# define MACROBLK_UP2_LP(image,c,tx,mx,k) (MACROBLK_UP2(image,c,tx,mx).data[1+k]) + +# define MACROBLK_CUR_LP_QUANT(image,c,tx,mx) (MACROBLK_CUR(image,c,tx,mx).lp_quant) +# define MACROBLK_UP1_LP_QUANT(image,c,tx,mx) (MACROBLK_UP1(image,c,tx,mx).lp_quant) +# define MACROBLK_UP2_LP_QUANT(image,c,tx,mx) (MACROBLK_UP2(image,c,tx,mx).lp_quant) + +/* Return the l-value of the HP coefficient in the macroblk. +The blk value is 0-15 and identifies the block within the macroblk. +The k value is 0-14 and addresses the coefficient within the blk. */ +# define MACROBLK_CUR_HP(image,c,tx,mx,blk,k) (MACROBLK_CUR(image,c,tx,mx).data[16+15*(blk)+(k)]) +# define MACROBLK_UP1_HP(image,c,tx,mx,blk,k) (MACROBLK_UP1(image,c,tx,mx).data[16+15*(blk)+(k)]) +# define MACROBLK_UP2_HP(image,c,tx,mx,blk,k) (MACROBLK_UP2(image,c,tx,mx).data[16+15*(blk)+(k)]) + +# define MACROBLK_CUR_HP_QUANT(image,c,tx,mx) (MACROBLK_CUR(image,c,tx,mx).hp_quant) +# define MACROBLK_UP1_HP_QUANT(image,c,tx,mx) (MACROBLK_UP1(image,c,tx,mx).hp_quant) +# define MACROBLK_UP2_HP_QUANT(image,c,tx,mx) (MACROBLK_UP2(image,c,tx,mx).hp_quant) + +/* Return the l-value of the HP CBP value. */ +# define MACROBLK_CUR_HPCBP(image,c,tx,mx) (MACROBLK_CUR(image,c,tx,mx).hp_cbp) +# define MACROBLK_UP1_HPCBP(image,c,tx,mx) (MACROBLK_UP1(image,c,tx,mx).hp_cbp) + +extern void _jxr_make_mbstore(jxr_image_t image, int include_up4); +extern void _jxr_fill_strip(jxr_image_t image); +extern void _jxr_rflush_mb_strip(jxr_image_t image, int tx, int ty, int my); +extern void _jxr_wflush_mb_strip(jxr_image_t image, int tx, int ty, int my, int read_new); + +/* Common strip handling functions. */ +extern void _jxr_clear_strip_cur(jxr_image_t image); +extern void _jxr_r_rotate_mb_strip(jxr_image_t image); + +/* Wrap up an image collected in frequency mode. */ +extern void _jxr_frequency_mode_render(jxr_image_t image); + +/* Application interface functions */ +extern void _jxr_send_mb_to_output(jxr_image_t image, int mx, int my, int*data); + +/* I/O functions. */ + +struct rbitstream{ + unsigned char byte; + int bits_avail; + FILE*fd; + size_t read_count; + + long mark_stream_position; +}; + +/* Get the current *bit* position, for diagnostic use. */ +extern void _jxr_rbitstream_initialize(struct rbitstream*str, FILE*fd); +extern size_t _jxr_rbitstream_bitpos(struct rbitstream*str); + +extern void _jxr_rbitstream_syncbyte(struct rbitstream*str); +extern int _jxr_rbitstream_uint1(struct rbitstream*str); +extern uint8_t _jxr_rbitstream_uint2(struct rbitstream*str); +extern uint8_t _jxr_rbitstream_uint3(struct rbitstream*str); +extern uint8_t _jxr_rbitstream_uint4(struct rbitstream*str); +extern uint8_t _jxr_rbitstream_uint6(struct rbitstream*str); +extern uint8_t _jxr_rbitstream_uint8(struct rbitstream*str); +extern uint16_t _jxr_rbitstream_uint12(struct rbitstream*str); +extern uint16_t _jxr_rbitstream_uint15(struct rbitstream*str); +extern uint16_t _jxr_rbitstream_uint16(struct rbitstream*str); +extern uint32_t _jxr_rbitstream_uint32(struct rbitstream*str); +extern uint32_t _jxr_rbitstream_uintN(struct rbitstream*str, int N); +/* Return <0 if there is an escape code. */ +extern int64_t _jxr_rbitstream_intVLW(struct rbitstream*str); + +extern int _jxr_rbitstream_intE(struct rbitstream*str, int code_size, + const unsigned char*codeb, + const signed char*codev); +extern const char* _jxr_vlc_index_name(int vlc); + +/* +* These functions provided limited random access into the file +* stream. The mark() function causes a given point to be marked as +* "zero", then the seek() function can go to a *byte* position +* relative the zeo mark. These functions can only be called when the +* stream is on a byte boundary. +*/ +extern void _jxr_rbitstream_mark(struct rbitstream*str); +extern void _jxr_rbitstream_seek(struct rbitstream*str, uint64_t off); + +struct wbitstream{ + unsigned char byte; + int bits_ready; + FILE*fd; + size_t write_count; +}; + +extern void _jxr_wbitstream_initialize(struct wbitstream*str, FILE*fd); +extern size_t _jxr_wbitstream_bitpos(struct wbitstream*str); +extern void _jxr_wbitstream_syncbyte(struct wbitstream*str); +extern void _jxr_wbitstream_uint1(struct wbitstream*str, int val); +extern void _jxr_wbitstream_uint2(struct wbitstream*str, uint8_t val); +extern void _jxr_wbitstream_uint3(struct wbitstream*str, uint8_t val); +extern void _jxr_wbitstream_uint4(struct wbitstream*str, uint8_t val); +extern void _jxr_wbitstream_uint6(struct wbitstream*str, uint8_t val); +extern void _jxr_wbitstream_uint8(struct wbitstream*str, uint8_t val); +extern void _jxr_wbitstream_uint12(struct wbitstream*str, uint16_t val); +extern void _jxr_wbitstream_uint15(struct wbitstream*str, uint16_t val); +extern void _jxr_wbitstream_uint16(struct wbitstream*str, uint16_t val); +extern void _jxr_wbitstream_uint32(struct wbitstream*str, uint32_t val); +extern void _jxr_wbitstream_uintN(struct wbitstream*str, uint32_t val, int N); +extern void _jxr_wbitstream_intVLW(struct wbitstream*str, uint64_t val); +extern void _jxr_wbitstream_flush(struct wbitstream*str); + +extern void _jxr_wbitstream_mark(struct wbitstream*str); +extern void _jxr_wbitstream_seek(struct wbitstream*str, uint64_t off); + +extern void _jxr_w_TILE_SPATIAL(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty); +extern void _jxr_w_TILE_DC(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty); +extern void _jxr_w_TILE_LP(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty); +extern void _jxr_w_TILE_HP_FLEX(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty); +extern void _jxr_w_TILE_HEADER_DC(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); +extern void _jxr_w_TILE_HEADER_LOWPASS(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); +extern void _jxr_w_TILE_HEADER_HIGHPASS(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); +extern void _jxr_w_MB_DC(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern void _jxr_w_MB_LP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern int _jxr_w_MB_HP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, struct wbitstream*strFB); +extern void _jxr_w_MB_CBP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern void _jxr_w_DC_QP(jxr_image_t image, struct wbitstream*str); +extern void _jxr_w_LP_QP(jxr_image_t image, struct wbitstream*str); +extern void _jxr_w_HP_QP(jxr_image_t image, struct wbitstream*str); +extern void _jxr_w_ENCODE_QP_INDEX(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty, unsigned mx, unsigned my, + unsigned num_qps, unsigned qp_index); + + +extern int _jxr_r_TILE_SPATIAL(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty); +extern int _jxr_r_TILE_DC(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty); +extern int _jxr_r_TILE_LP(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty); +extern int _jxr_r_TILE_HP(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty); +extern int _jxr_r_TILE_FLEXBITS(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty); +extern int _jxr_r_TILE_FLEXBITS_ESCAPE(jxr_image_t image, + unsigned tx, unsigned ty); +extern void _jxr_r_TILE_HEADER_DC(jxr_image_t image, struct rbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); +extern void _jxr_r_TILE_HEADER_LOWPASS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); +extern void _jxr_r_TILE_HEADER_HIGHPASS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, unsigned tx, unsigned ty); + +extern void _jxr_r_MB_DC(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern void _jxr_r_MB_LP(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern int _jxr_r_MB_HP(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern int _jxr_r_MB_CBP(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +int _jxr_r_MB_FLEXBITS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); + +extern int _jxr_r_DC_QP(jxr_image_t image, struct rbitstream*str); +extern int _jxr_r_LP_QP(jxr_image_t image, struct rbitstream*str); + +extern unsigned _jxr_DECODE_QP_INDEX(struct rbitstream*str, + unsigned index_count); +extern int r_DECODE_BLOCK(jxr_image_t image, struct rbitstream*str, + int chroma_flag, int coeff[16], int band, int location); + +/* algorithm functions */ +/* +* In these functions, the mx and my are the position of the MB +* within a tile (i.e. mx=my=0 is the top left MB in the TILE not +* necessarily the image). The mx and my are given it units of MB. The +* pixel position is mx*16, my*16. +*/ + +extern int _jxr_quant_map(jxr_image_t image, int x, int shift); +extern int _jxr_InitContext(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my); +extern int _jxr_ResetContext(jxr_image_t image, unsigned tx, unsigned mx); +extern int _jxr_ResetTotals(jxr_image_t image, unsigned mx); +extern int _jxr_vlc_select(int band, int chroma_flag); +extern void _jxr_InitVLCTable(jxr_image_t image, int vlc_select); +extern void _jxr_AdaptVLCTable(jxr_image_t image, int vlc_select); +extern void _jxr_AdaptLP(jxr_image_t image); +extern void _jxr_AdaptHP(jxr_image_t image); +extern void _jxr_InitializeModelMB(struct model_s*model, int band); +extern void _jxr_UpdateModelMB(jxr_image_t image, int lap_mean[2], +struct model_s*model, int band); + +extern void _jxr_InitializeCountCBPLP(jxr_image_t image); +extern void _jxr_UpdateCountCBPLP(jxr_image_t image, int cbplp, int max); + +extern void _jxr_InitLPVLC(jxr_image_t image); +extern void _jxr_InitCBPVLC(jxr_image_t image); +extern void _jxr_InitHPVLC(jxr_image_t image); + +extern void _jxr_InitializeCBPModel(jxr_image_t image); +extern void _jxr_w_PredCBP444(jxr_image_t image, + int ch, unsigned tx, + unsigned mx, int my); +extern void _jxr_w_PredCBP422(jxr_image_t image, + int ch, unsigned tx, + unsigned mx, int my); +extern void _jxr_w_PredCBP420(jxr_image_t image, + int ch, unsigned tx, + unsigned mx, int my); +extern int _jxr_PredCBP444(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, unsigned mx, unsigned my); +extern int _jxr_PredCBP422(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, unsigned mx, unsigned my); +extern int _jxr_PredCBP420(jxr_image_t image, int*diff_cbp, + int channel, unsigned tx, unsigned mx, unsigned my); +extern void _jxr_UpdateCBPModel(jxr_image_t image); + +extern void _jxr_InitializeAdaptiveScanLP(jxr_image_t image); +extern void _jxr_ResetTotalsAdaptiveScanLP(jxr_image_t image); + +extern void _jxr_InitializeAdaptiveScanHP(jxr_image_t image); +extern void _jxr_ResetTotalsAdaptiveScanHP(jxr_image_t image); + +extern void _jxr_complete_cur_dclp(jxr_image_t image, int tx, int mx, int my); +extern void _jxr_propagate_hp_predictions(jxr_image_t image, + int ch, unsigned tx, unsigned mx, + int mbhp_pred_mode); + +extern void _jxr_4OverlapFilter(int*a, int*b, int*c, int*d); +extern void _jxr_4x4OverlapFilter(int*a, int*b, int*c, int*d, + int*e, int*f, int*g, int*h, + int*i, int*j, int*k, int*l, + int*m, int*n, int*o, int*p); +extern void _jxr_2OverlapFilter(int*a, int*b); + +extern void _jxr_2x2OverlapFilter(int*a, int*b, int*c, int*d); + +extern void _jxr_4PreFilter(int*a, int*b, int*c, int*d); +extern void _jxr_4x4PreFilter(int*a, int*b, int*c, int*d, + int*e, int*f, int*g, int*h, + int*i, int*j, int*k, int*l, + int*m, int*n, int*o, int*p); + +extern void _jxr_2PreFilter(int*a, int*b); + +extern void _jxr_2x2PreFilter(int*a, int*b, int*c, int*d); + +extern const int _jxr_abslevel_index_delta[7]; + +/* +* All the blocks of HP data (16 blocks, 15 coefficients per block) in +* a macroblock are stored together. The data is written into the +* stream in this order: +* +* 0 1 4 5 +* 2 3 6 7 +* 8 9 12 13 +* 10 11 14 15 +*/ +extern const int _jxr_hp_scan_map[16]; + +extern uint8_t _jxr_read_lwf_test_flag(); +extern void _jxr_4x4IPCT(int*coeff); +extern void _jxr_2x2IPCT(int*coeff); +extern void _jxr_2ptT(int*a, int*b); +extern void _jxr_2ptFwdT(int*a, int*b); +extern void _jxr_InvPermute2pt(int*a, int*b); +extern void _jxr_4x4PCT(int*coeff); +extern void _jxr_2x2PCT(int*coeff); + + +extern int _jxr_floor_div2(int x); +extern int _jxr_ceil_div2(int x); + +# define SWAP(x,y) do { int tmp = (x); (x) = (y); (y) = tmp; } while(0) + + +/* *** +* Container types +* ***/ + +struct ifd_table{ + uint16_t tag; + uint16_t type; + uint32_t cnt; + + union{ + uint8_t v_byte[4]; + uint16_t v_short[2]; + uint32_t v_long; + int8_t v_sbyte[4]; + int16_t v_sshort[2]; + int32_t v_slong; + float v_float; + + uint8_t *p_byte; + uint16_t *p_short; + uint32_t *p_long; + uint64_t *p_rational; + int8_t *p_sbyte; + int16_t *p_sshort; + int32_t *p_slong; + int64_t *p_srational; + float *p_float; + double *p_double; + }value_; +}; + +/* +* This is the container itself. It contains pointers to the tables. +*/ +struct jxr_container{ + /* Number of images in the container. */ + int image_count; + + /* IFDs for all the images. */ + unsigned*table_cnt; + struct ifd_table**table; + + /* Members for managing output. */ + + FILE*fd; /* File to write to. */ + uint32_t file_mark; + uint32_t next_ifd_mark; + uint32_t image_count_mark; + uint32_t image_offset_mark; + uint32_t alpha_count_mark; + uint32_t alpha_offset_mark; + uint32_t alpha_begin_mark; /* Required to calculate bytes used up by the alpha plane */ + + uint8_t image_band, alpha_band; /* for bands present */ + uint32_t wid, hei; + unsigned char pixel_format[16]; + + uint8_t separate_alpha_image_plane; +}; + +extern int jxr_read_image_pixelformat(jxr_container_t c); + +extern unsigned int isEqualGUID(unsigned char guid1[16], unsigned char guid2[16]); + +#if defined(DETAILED_DEBUG) +# define DEBUG(...) fprintf(stdout, __VA_ARGS__) +#else +# define DEBUG(...) do { } while(0) +#endif + +extern const char*_jxr_vld_index_name(int vlc); + +/* +* $Log: jxr_priv.h,v $ +* Revision 1.67 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.66 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.65 2008-05-13 13:47:11 thor +* Some experiments with a smarter selection for the quantization size, +* does not yet compile. +* +* Revision 1.64 2008-05-09 19:57:48 thor +* Reformatted for unix LF. +* +* Revision 1.63 2008-04-15 14:28:12 thor +* Start of the repository for the jpegxr reference software. +* +* Revision 1.62 2008/03/20 22:38:53 steve +* Use MB HPQP instead of first HPQP in decode. +* +* Revision 1.61 2008/03/14 00:54:08 steve +* Add second prefilter for YUV422 and YUV420 encode. +* +* Revision 1.60 2008/03/13 21:23:27 steve +* Add pipeline step for YUV420. +* +* Revision 1.59 2008/03/13 17:49:31 steve +* Fix problem with YUV422 CBP prediction for UV planes +* +* Add support for YUV420 encoding. +* +* Revision 1.58 2008/03/11 22:12:48 steve +* Encode YUV422 through DC. +* +* Revision 1.57 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.56 2008/03/05 00:31:17 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.55 2008/03/02 18:35:27 steve +* Add support for BD16 +* +* Revision 1.54 2008/03/01 02:46:08 steve +* Add support for JXR container. +* +* Revision 1.53 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.52 2008/02/26 23:44:25 steve +* Handle the special case of compiling via MS C. +* +* Revision 1.51 2008/02/01 22:49:52 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.50 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.49 2008/01/06 01:29:28 steve +* Add support for TRIM_FLEXBITS in compression. +* +* Revision 1.48 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.47 2008/01/01 01:07:26 steve +* Add missing HP prediction. +* +* Revision 1.46 2007/12/30 00:16:00 steve +* Add encoding of HP values. +* +* Revision 1.45 2007/12/14 17:10:39 steve +* HP CBP Prediction +* +* Revision 1.44 2007/12/13 18:01:09 steve +* Stubs for HP encoding. +* +* Revision 1.43 2007/12/07 01:20:34 steve +* Fix adapt not adapting on line ends. +* +* Revision 1.42 2007/12/06 23:12:41 steve +* Stubs for LP encode operations. +* +* Revision 1.41 2007/12/04 22:06:10 steve +* Infrastructure for encoding LP. +* +* Revision 1.40 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.39 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.38 2007/11/21 23:26:14 steve +* make all strip buffers store MB data. +*/ +#endif diff --git a/jpegxr/my_getopt-1.5/LICENSE b/jpegxr/my_getopt-1.5/LICENSE new file mode 100644 index 000000000..2224aba0c --- /dev/null +++ b/jpegxr/my_getopt-1.5/LICENSE @@ -0,0 +1,22 @@ +my_getopt - a command-line argument parser +Copyright 1997-2001, Benjamin Sittler + +Permission is hereby granted, free of charge, to any person +obtaining a copy of this software and associated documentation +files (the "Software"), to deal in the Software without +restriction, including without limitation the rights to use, copy, +modify, merge, publish, distribute, sublicense, and/or sell copies +of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be +included in all copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +DEALINGS IN THE SOFTWARE. diff --git a/jpegxr/my_getopt-1.5/getopt.h b/jpegxr/my_getopt-1.5/getopt.h new file mode 100644 index 000000000..06b8c9d17 --- /dev/null +++ b/jpegxr/my_getopt-1.5/getopt.h @@ -0,0 +1,56 @@ +/* +* getopt.h - cpp wrapper for my_getopt to make it look like getopt. +* Copyright 1997, 2000, 2001, 2002, Benjamin Sittler +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MY_WRAPPER_GETOPT_H_INCLUDED +#define MY_WRAPPER_GETOPT_H_INCLUDED + +#ifdef __cplusplus +extern "C"{ +#endif + +#include "my_getopt.h" + +#undef getopt +#define getopt my_getopt +#undef getopt_long +#define getopt_long my_getopt_long +#undef getopt_long_only +#define getopt_long_only my_getopt_long_only +#undef _getopt_internal +#define _getopt_internal _my_getopt_internal +#undef opterr +#define opterr my_opterr +#undef optind +#define optind my_optind +#undef optopt +#define optopt my_optopt +#undef optarg +#define optarg my_optarg + +#ifdef __cplusplus +} +#endif + +#endif /* MY_WRAPPER_GETOPT_H_INCLUDED */ diff --git a/jpegxr/my_getopt-1.5/my_getopt.c b/jpegxr/my_getopt-1.5/my_getopt.c new file mode 100644 index 000000000..edc4a3465 --- /dev/null +++ b/jpegxr/my_getopt-1.5/my_getopt.c @@ -0,0 +1,281 @@ +/* +* my_getopt.c - my re-implementation of getopt. +* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#include <sys/types.h> +#include <stdlib.h> +#include <stdio.h> +#include <string.h> +#include "my_getopt.h" + +int my_optind=1, my_opterr=1, my_optopt=0; +char *my_optarg=0; + +/* reset argument parser to start-up values */ +int my_getopt_reset(void) +{ + my_optind = 1; + my_opterr = 1; + my_optopt = 0; + my_optarg = 0; + return 0; +} + +/* this is the plain old UNIX getopt, with GNU-style extensions. */ +/* if you're porting some piece of UNIX software, this is all you need. */ +/* this supports GNU-style permution and optional arguments */ + +int my_getopt(int argc, char * argv[], const char *opts) +{ + static int charind=0; + const char *s; + char mode, colon_mode; + int off = 0, opt = -1; + + if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; + else { + if((colon_mode = *opts) == ':') off ++; + if(((mode = opts[off]) == '+') || (mode == '-')) { + off++; + if((colon_mode != ':') && ((colon_mode = opts[off]) == ':')) + off ++; + } + } + my_optarg = 0; + if(charind) { + my_optopt = argv[my_optind][charind]; + for(s=opts+off; *s; s++) if(my_optopt == *s) { + charind++; + if((*(++s) == ':') || ((my_optopt == 'W') && (*s == ';'))) { + if(argv[my_optind][charind]) { + my_optarg = &(argv[my_optind++][charind]); + charind = 0; + } else if(*(++s) != ':') { + charind = 0; + if(++my_optind >= argc) { + if(my_opterr) fprintf(stderr, + "%s: option requires an argument -- %c\n", + argv[0], my_optopt); + opt = (colon_mode == ':') ? ':' : '?'; + goto my_getopt_ok; + } + my_optarg = argv[my_optind++]; + } + } + opt = my_optopt; + goto my_getopt_ok; + } + if(my_opterr) fprintf(stderr, + "%s: illegal option -- %c\n", + argv[0], my_optopt); + opt = '?'; + if(argv[my_optind][++charind] == '\0') { + my_optind++; + charind = 0; + } +my_getopt_ok: + if(charind && ! argv[my_optind][charind]) { + my_optind++; + charind = 0; + } + } else if((my_optind >= argc) || + ((argv[my_optind][0] == '-') && + (argv[my_optind][1] == '-') && + (argv[my_optind][2] == '\0'))) { + my_optind++; + opt = -1; + } else if((argv[my_optind][0] != '-') || + (argv[my_optind][1] == '\0')) { + char *tmp; + int i, j, k; + + if(mode == '+') opt = -1; + else if(mode == '-') { + my_optarg = argv[my_optind++]; + charind = 0; + opt = 1; + } else { + for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') && + (argv[i][1] != '\0')) { + my_optind=i; + opt=my_getopt(argc, argv, opts); + while(i > j) { + tmp=argv[--i]; + for(k=i; k+1<my_optind; k++) argv[k]=argv[k+1]; + argv[--my_optind]=tmp; + } + break; + } + if(i == argc) opt = -1; + } + } else { + charind++; + opt = my_getopt(argc, argv, opts); + } + if (my_optind > argc) my_optind = argc; + return opt; +} + +/* this is the extended getopt_long{,_only}, with some GNU-like +* extensions. Implements _getopt_internal in case any programs +* expecting GNU libc getopt call it. +*/ + +int _my_getopt_internal(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind, + int long_only) +{ + char mode, colon_mode = *shortopts; + int shortoff = 0, opt = -1; + + if(getenv("POSIXLY_CORRECT")) colon_mode = mode = '+'; + else { + if((colon_mode = *shortopts) == ':') shortoff ++; + if(((mode = shortopts[shortoff]) == '+') || (mode == '-')) { + shortoff++; + if((colon_mode != ':') && ((colon_mode = shortopts[shortoff]) == ':')) + shortoff ++; + } + } + my_optarg = 0; + if((my_optind >= argc) || + ((argv[my_optind][0] == '-') && + (argv[my_optind][1] == '-') && + (argv[my_optind][2] == '\0'))) { + my_optind++; + opt = -1; + } else if((argv[my_optind][0] != '-') || + (argv[my_optind][1] == '\0')) { + char *tmp; + int i, j, k; + + opt = -1; + if(mode == '+') return -1; + else if(mode == '-') { + my_optarg = argv[my_optind++]; + return 1; + } + for(i=j=my_optind; i<argc; i++) if((argv[i][0] == '-') && + (argv[i][1] != '\0')) { + my_optind=i; + opt=_my_getopt_internal(argc, argv, shortopts, + longopts, longind, + long_only); + while(i > j) { + tmp=argv[--i]; + for(k=i; k+1<my_optind; k++) + argv[k]=argv[k+1]; + argv[--my_optind]=tmp; + } + break; + } + } else if((!long_only) && (argv[my_optind][1] != '-')) + opt = my_getopt(argc, argv, shortopts); + else { + int charind, offset; + int found = 0, ind, hits = 0; + + if(((my_optopt = argv[my_optind][1]) != '-') && ! argv[my_optind][2]) { + int c; + + ind = shortoff; + while((c = shortopts[ind++])) { + if(((shortopts[ind] == ':') || + ((c == 'W') && (shortopts[ind] == ';'))) && + (shortopts[++ind] == ':')) + ind ++; + if(my_optopt == c) return my_getopt(argc, argv, shortopts); + } + } + offset = 2 - (argv[my_optind][1] != '-'); + for(charind = offset; + (argv[my_optind][charind] != '\0') && + (argv[my_optind][charind] != '='); + charind++); + for(ind = 0; longopts[ind].name && !hits; ind++) + if((strlen(longopts[ind].name) == (size_t) (charind - offset)) && + (strncmp(longopts[ind].name, + argv[my_optind] + offset, charind - offset) == 0)) + found = ind, hits++; + if(!hits) for(ind = 0; longopts[ind].name; ind++) + if(strncmp(longopts[ind].name, + argv[my_optind] + offset, charind - offset) == 0) + found = ind, hits++; + if(hits == 1) { + opt = 0; + + if(argv[my_optind][charind] == '=') { + if(longopts[found].has_arg == 0) { + opt = '?'; + if(my_opterr) fprintf(stderr, + "%s: option `--%s' doesn't allow an argument\n", + argv[0], longopts[found].name); + } else { + my_optarg = argv[my_optind] + ++charind; + charind = 0; + } + } else if(longopts[found].has_arg == 1) { + if(++my_optind >= argc) { + opt = (colon_mode == ':') ? ':' : '?'; + if(my_opterr) fprintf(stderr, + "%s: option `--%s' requires an argument\n", + argv[0], longopts[found].name); + } else my_optarg = argv[my_optind]; + } + if(!opt) { + if (longind) *longind = found; + if(!longopts[found].flag) opt = longopts[found].val; + else *(longopts[found].flag) = longopts[found].val; + } + my_optind++; + } else if(!hits) { + if(offset == 1) opt = my_getopt(argc, argv, shortopts); + else { + opt = '?'; + if(my_opterr) fprintf(stderr, + "%s: unrecognized option `%s'\n", + argv[0], argv[my_optind++]); + } + } else { + opt = '?'; + if(my_opterr) fprintf(stderr, + "%s: option `%s' is ambiguous\n", + argv[0], argv[my_optind++]); + } + } + if (my_optind > argc) my_optind = argc; + return opt; +} + +int my_getopt_long(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind) +{ + return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 0); +} + +int my_getopt_long_only(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind) +{ + return _my_getopt_internal(argc, argv, shortopts, longopts, longind, 1); +} diff --git a/jpegxr/my_getopt-1.5/my_getopt.h b/jpegxr/my_getopt-1.5/my_getopt.h new file mode 100644 index 000000000..1d9523d4f --- /dev/null +++ b/jpegxr/my_getopt-1.5/my_getopt.h @@ -0,0 +1,72 @@ +/* +* my_getopt.h - interface to my re-implementation of getopt. +* Copyright 1997, 2000, 2001, 2002, 2006, Benjamin Sittler +* +* Permission is hereby granted, free of charge, to any person +* obtaining a copy of this software and associated documentation +* files (the "Software"), to deal in the Software without +* restriction, including without limitation the rights to use, copy, +* modify, merge, publish, distribute, sublicense, and/or sell copies +* of the Software, and to permit persons to whom the Software is +* furnished to do so, subject to the following conditions: +* +* The above copyright notice and this permission notice shall be +* included in all copies or substantial portions of the Software. +* +* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, +* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF +* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND +* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT +* HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, +* WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +* DEALINGS IN THE SOFTWARE. +*/ + +#ifndef MY_GETOPT_H_INCLUDED +#define MY_GETOPT_H_INCLUDED + +#ifdef __cplusplus +extern "C"{ +#endif + + /* reset argument parser to start-up values */ + extern int my_getopt_reset(void); + + /* UNIX-style short-argument parser */ + extern int my_getopt(int argc, char * argv[], const char *opts); + + extern int my_optind, my_opterr, my_optopt; + extern char *my_optarg; + + struct option{ + const char *name; + int has_arg; + int *flag; + int val; + }; + + /* human-readable values for has_arg */ +#undef no_argument +#define no_argument 0 +#undef required_argument +#define required_argument 1 +#undef optional_argument +#define optional_argument 2 + + /* GNU-style long-argument parsers */ + extern int my_getopt_long(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind); + + extern int my_getopt_long_only(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind); + + extern int _my_getopt_internal(int argc, char * argv[], const char *shortopts, + const struct option *longopts, int *longind, + int long_only); + +#ifdef __cplusplus +} +#endif + +#endif /* MY_GETOPT_H_INCLUDED */ diff --git a/jpegxr/qp.tab.c b/jpegxr/qp.tab.c new file mode 100644 index 000000000..e87208635 --- /dev/null +++ b/jpegxr/qp.tab.c @@ -0,0 +1,1909 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton implementation for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + +/* C LALR(1) parser skeleton written by Richard Stallman, by + simplifying the original so-called "semantic" parser. */ + +/* All symbols defined below should begin with yy or YY, to avoid + infringing on user name space. This should be done even for local + variables, as they might otherwise be expanded by user macros. + There are some unavoidable exceptions within include files to + define necessary library symbols; they are noted "INFRINGES ON + USER NAME SPACE" below. */ + +/* Identify Bison output. */ +#define YYBISON 1 + +/* Bison version. */ +#define YYBISON_VERSION "2.4.1" + +/* Skeleton name. */ +#define YYSKELETON_NAME "yacc.c" + +/* Pure parsers. */ +#define YYPURE 0 + +/* Push parsers. */ +#define YYPUSH 0 + +/* Pull parsers. */ +#define YYPULL 1 + +/* Using locations. */ +#define YYLSP_NEEDED 0 + +/* Substitute the variable and function names. */ +#define yyparse qp_parse +#define yylex qp_lex +#define yyerror qp_error +#define yylval qp_lval +#define yychar qp_char +#define yydebug qp_debug +#define yynerrs qp_nerrs + + +/* Copy the first part of user declarations. */ + +/* Line 189 of yacc.c */ +#line 2 "qp_parse.y" + + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: qp_parse.y,v 1.8 2008/03/20 18:10:29 steve Exp $") +#else +#ident "$Id: qp_parse.y,v 1.8 2008/03/20 18:10:29 steve Exp $" +#endif + +# include "jpegxr.h" +# include <stdlib.h> +# include <assert.h> +# define YYINCLUDED_STDLIB_H + + extern int qp_lex(void); + static void yyerror(const char*txt); + + static int errors = 0; + + /* Parse state variables. */ + + /* The image we are getting QP values for */ + static jxr_image_t cur_image; + /* Some characteristics of that image. */ + static unsigned tile_columns; + static unsigned tile_rows; + + /* The array of all the tiles to be calculated. */ + static struct jxr_tile_qp* tile_qp = 0; + + /* Tile currently in progress. */ + static unsigned cur_tilex = 0; + static unsigned cur_tiley = 0; + static struct jxr_tile_qp*cur_tile = 0; + + static unsigned mb_in_tile = 0; + + static unsigned cur_channel = 0; + + + +/* Line 189 of yacc.c */ +#line 162 "qp.tab.c" + +/* Enabling traces. */ +#ifndef YYDEBUG +# define YYDEBUG 0 +#endif + +/* Enabling verbose error messages. */ +#ifdef YYERROR_VERBOSE +# undef YYERROR_VERBOSE +# define YYERROR_VERBOSE 1 +#else +# define YYERROR_VERBOSE 0 +#endif + +/* Enabling the token table. */ +#ifndef YYTOKEN_TABLE +# define YYTOKEN_TABLE 0 +#endif + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + K_DC = 258, + K_CHANNEL = 259, + K_HP = 260, + K_INDEPENDENT = 261, + K_LP = 262, + K_SEPARATE = 263, + K_TILE = 264, + K_UNIFORM = 265, + NUMBER = 266 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 214 of yacc.c */ +#line 82 "qp_parse.y" + + unsigned number; + + struct { + unsigned char*data; + unsigned count; + } map_list; + + struct sixteen_nums { + unsigned char num; + unsigned char qp[16]; + } qp_set; + + + +/* Line 214 of yacc.c */ +#line 225 "qp.tab.c" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + + +/* Copy the second part of user declarations. */ + + +/* Line 264 of yacc.c */ +#line 237 "qp.tab.c" + +#ifdef short +# undef short +#endif + +#ifdef YYTYPE_UINT8 +typedef YYTYPE_UINT8 yytype_uint8; +#else +typedef unsigned char yytype_uint8; +#endif + +#ifdef YYTYPE_INT8 +typedef YYTYPE_INT8 yytype_int8; +#elif (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +typedef signed char yytype_int8; +#else +typedef short int yytype_int8; +#endif + +#ifdef YYTYPE_UINT16 +typedef YYTYPE_UINT16 yytype_uint16; +#else +typedef unsigned short int yytype_uint16; +#endif + +#ifdef YYTYPE_INT16 +typedef YYTYPE_INT16 yytype_int16; +#else +typedef short int yytype_int16; +#endif + +#ifndef YYSIZE_T +# ifdef __SIZE_TYPE__ +# define YYSIZE_T __SIZE_TYPE__ +# elif defined size_t +# define YYSIZE_T size_t +# elif ! defined YYSIZE_T && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stddef.h> /* INFRINGES ON USER NAME SPACE */ +# define YYSIZE_T size_t +# else +# define YYSIZE_T unsigned int +# endif +#endif + +#define YYSIZE_MAXIMUM ((YYSIZE_T) -1) + +#ifndef YY_ +# if YYENABLE_NLS +# if ENABLE_NLS +# include <libintl.h> /* INFRINGES ON USER NAME SPACE */ +# define YY_(msgid) dgettext ("bison-runtime", msgid) +# endif +# endif +# ifndef YY_ +# define YY_(msgid) msgid +# endif +#endif + +/* Suppress unused-variable warnings by "using" E. */ +#if ! defined lint || defined __GNUC__ +# define YYUSE(e) ((void) (e)) +#else +# define YYUSE(e) /* empty */ +#endif + +/* Identity function, used to suppress warnings about constant conditions. */ +#ifndef lint +# define YYID(n) (n) +#else +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static int +YYID (int yyi) +#else +static int +YYID (yyi) + int yyi; +#endif +{ + return yyi; +} +#endif + +#if ! defined yyoverflow || YYERROR_VERBOSE + +/* The parser invokes alloca or malloc; define the necessary symbols. */ + +# ifdef YYSTACK_USE_ALLOCA +# if YYSTACK_USE_ALLOCA +# ifdef __GNUC__ +# define YYSTACK_ALLOC __builtin_alloca +# elif defined __BUILTIN_VA_ARG_INCR +# include <alloca.h> /* INFRINGES ON USER NAME SPACE */ +# elif defined _AIX +# define YYSTACK_ALLOC __alloca +# elif defined _MSC_VER +# include <malloc.h> /* INFRINGES ON USER NAME SPACE */ +# define alloca _alloca +# else +# define YYSTACK_ALLOC alloca +# if ! defined _ALLOCA_H && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# endif +# endif +# endif + +# ifdef YYSTACK_ALLOC + /* Pacify GCC's `empty if-body' warning. */ +# define YYSTACK_FREE(Ptr) do { /* empty */; } while (YYID (0)) +# ifndef YYSTACK_ALLOC_MAXIMUM + /* The OS might guarantee only one guard page at the bottom of the stack, + and a page size can be as small as 4096 bytes. So we cannot safely + invoke alloca (N) if N exceeds 4096. Use a slightly smaller number + to allow for a few compiler-allocated temporary stack slots. */ +# define YYSTACK_ALLOC_MAXIMUM 4032 /* reasonable circa 2006 */ +# endif +# else +# define YYSTACK_ALLOC YYMALLOC +# define YYSTACK_FREE YYFREE +# ifndef YYSTACK_ALLOC_MAXIMUM +# define YYSTACK_ALLOC_MAXIMUM YYSIZE_MAXIMUM +# endif +# if (defined __cplusplus && ! defined _STDLIB_H \ + && ! ((defined YYMALLOC || defined malloc) \ + && (defined YYFREE || defined free))) +# include <stdlib.h> /* INFRINGES ON USER NAME SPACE */ +# ifndef _STDLIB_H +# define _STDLIB_H 1 +# endif +# endif +# ifndef YYMALLOC +# define YYMALLOC malloc +# if ! defined malloc && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void *malloc (YYSIZE_T); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# ifndef YYFREE +# define YYFREE free +# if ! defined free && ! defined _STDLIB_H && (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +void free (void *); /* INFRINGES ON USER NAME SPACE */ +# endif +# endif +# endif +#endif /* ! defined yyoverflow || YYERROR_VERBOSE */ + + +#if (! defined yyoverflow \ + && (! defined __cplusplus \ + || (defined YYSTYPE_IS_TRIVIAL && YYSTYPE_IS_TRIVIAL))) + +/* A type that is properly aligned for any stack member. */ +union yyalloc +{ + yytype_int16 yyss_alloc; + YYSTYPE yyvs_alloc; +}; + +/* The size of the maximum gap between one aligned stack and the next. */ +# define YYSTACK_GAP_MAXIMUM (sizeof (union yyalloc) - 1) + +/* The size of an array large to enough to hold all stacks, each with + N elements. */ +# define YYSTACK_BYTES(N) \ + ((N) * (sizeof (yytype_int16) + sizeof (YYSTYPE)) \ + + YYSTACK_GAP_MAXIMUM) + +/* Copy COUNT objects from FROM to TO. The source and destination do + not overlap. */ +# ifndef YYCOPY +# if defined __GNUC__ && 1 < __GNUC__ +# define YYCOPY(To, From, Count) \ + __builtin_memcpy (To, From, (Count) * sizeof (*(From))) +# else +# define YYCOPY(To, From, Count) \ + do \ + { \ + YYSIZE_T yyi; \ + for (yyi = 0; yyi < (Count); yyi++) \ + (To)[yyi] = (From)[yyi]; \ + } \ + while (YYID (0)) +# endif +# endif + +/* Relocate STACK from its old location to the new one. The + local variables YYSIZE and YYSTACKSIZE give the old and new number of + elements in the stack, and YYPTR gives the new location of the + stack. Advance YYPTR to a properly aligned location for the next + stack. */ +# define YYSTACK_RELOCATE(Stack_alloc, Stack) \ + do \ + { \ + YYSIZE_T yynewbytes; \ + YYCOPY (&yyptr->Stack_alloc, Stack, yysize); \ + Stack = &yyptr->Stack_alloc; \ + yynewbytes = yystacksize * sizeof (*Stack) + YYSTACK_GAP_MAXIMUM; \ + yyptr += yynewbytes / sizeof (*yyptr); \ + } \ + while (YYID (0)) + +#endif + +/* YYFINAL -- State number of the termination state. */ +#define YYFINAL 6 +/* YYLAST -- Last index in YYTABLE. */ +#define YYLAST 51 + +/* YYNTOKENS -- Number of terminals. */ +#define YYNTOKENS 19 +/* YYNNTS -- Number of nonterminals. */ +#define YYNNTS 14 +/* YYNRULES -- Number of rules. */ +#define YYNRULES 26 +/* YYNRULES -- Number of states. */ +#define YYNSTATES 56 + +/* YYTRANSLATE(YYLEX) -- Bison symbol number corresponding to YYLEX. */ +#define YYUNDEFTOK 2 +#define YYMAXUTOK 266 + +#define YYTRANSLATE(YYX) \ + ((unsigned int) (YYX) <= YYMAXUTOK ? yytranslate[YYX] : YYUNDEFTOK) + +/* YYTRANSLATE[YYLEX] -- Bison symbol number corresponding to YYLEX. */ +static const yytype_uint8 yytranslate[] = +{ + 0, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 12, 14, 2, 2, 13, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 17, 2, 18, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 15, 2, 16, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 1, 2, 3, 4, + 5, 6, 7, 8, 9, 10, 11 +}; + +#if YYDEBUG +/* YYPRHS[YYN] -- Index of the first RHS symbol of rule number YYN in + YYRHS. */ +static const yytype_uint8 yyprhs[] = +{ + 0, 0, 3, 5, 8, 10, 11, 23, 25, 27, + 29, 32, 34, 35, 42, 47, 52, 55, 57, 62, + 67, 72, 76, 78, 80, 81, 84 +}; + +/* YYRHS -- A `-1'-separated list of the rules' RHS. */ +static const yytype_int8 yyrhs[] = +{ + 20, 0, -1, 21, -1, 21, 22, -1, 22, -1, + -1, 9, 12, 11, 13, 11, 14, 23, 15, 24, + 25, 16, -1, 10, -1, 8, -1, 6, -1, 25, + 26, -1, 26, -1, -1, 4, 11, 27, 15, 28, + 16, -1, 7, 17, 32, 18, -1, 5, 17, 32, + 18, -1, 28, 29, -1, 29, -1, 3, 15, 11, + 16, -1, 7, 15, 30, 16, -1, 5, 15, 30, + 16, -1, 30, 31, 11, -1, 11, -1, 13, -1, + -1, 32, 11, -1, 11, -1 +}; + +/* YYRLINE[YYN] -- source line where rule number YYN was defined. */ +static const yytype_uint16 yyrline[] = +{ + 0, 107, 107, 110, 111, 118, 117, 169, 170, 171, + 175, 176, 181, 180, 188, 197, 208, 209, 213, 216, + 223, 233, 245, 251, 251, 254, 264 +}; +#endif + +#if YYDEBUG || YYERROR_VERBOSE || YYTOKEN_TABLE +/* YYTNAME[SYMBOL-NUM] -- String name of the symbol SYMBOL-NUM. + First, the terminals, then, starting at YYNTOKENS, nonterminals. */ +static const char *const yytname[] = +{ + "$end", "error", "$undefined", "K_DC", "K_CHANNEL", "K_HP", + "K_INDEPENDENT", "K_LP", "K_SEPARATE", "K_TILE", "K_UNIFORM", "NUMBER", + "'('", "','", "')'", "'{'", "'}'", "'['", "']'", "$accept", "start", + "tile_list", "tile", "$@1", "tile_comp_mode", "tile_body", "tile_item", + "$@2", "channel_body", "channel_item", "lphp_qp_list", "optional_comma", + "map_list", 0 +}; +#endif + +# ifdef YYPRINT +/* YYTOKNUM[YYLEX-NUM] -- Internal token number corresponding to + token YYLEX-NUM. */ +static const yytype_uint16 yytoknum[] = +{ + 0, 256, 257, 258, 259, 260, 261, 262, 263, 264, + 265, 266, 40, 44, 41, 123, 125, 91, 93 +}; +# endif + +/* YYR1[YYN] -- Symbol number of symbol that rule YYN derives. */ +static const yytype_uint8 yyr1[] = +{ + 0, 19, 20, 21, 21, 23, 22, 24, 24, 24, + 25, 25, 27, 26, 26, 26, 28, 28, 29, 29, + 29, 30, 30, 31, 31, 32, 32 +}; + +/* YYR2[YYN] -- Number of symbols composing right hand side of rule YYN. */ +static const yytype_uint8 yyr2[] = +{ + 0, 2, 1, 2, 1, 0, 11, 1, 1, 1, + 2, 1, 0, 6, 4, 4, 2, 1, 4, 4, + 4, 3, 1, 1, 0, 2, 1 +}; + +/* YYDEFACT[STATE-NAME] -- Default rule to reduce with in state + STATE-NUM when YYTABLE doesn't specify something else to do. Zero + means the default is an error. */ +static const yytype_uint8 yydefact[] = +{ + 0, 0, 0, 2, 4, 0, 1, 3, 0, 0, + 0, 5, 0, 0, 9, 8, 7, 0, 0, 0, + 0, 0, 11, 12, 0, 0, 6, 10, 0, 26, + 0, 0, 0, 25, 15, 14, 0, 0, 0, 0, + 17, 0, 0, 0, 13, 16, 0, 22, 24, 24, + 18, 23, 20, 0, 19, 21 +}; + +/* YYDEFGOTO[NTERM-NUM]. */ +static const yytype_int8 yydefgoto[] = +{ + -1, 2, 3, 4, 12, 17, 21, 22, 28, 39, + 40, 48, 53, 30 +}; + +/* YYPACT[STATE-NUM] -- Index in YYTABLE of the portion describing + STATE-NUM. */ +#define YYPACT_NINF -12 +static const yytype_int8 yypact[] = +{ + 0, -11, 11, 0, -12, 17, -12, -12, 9, 19, + 18, -12, 21, 10, -12, -12, -12, 20, 22, 14, + 23, 1, -12, -12, 24, 24, -12, -12, 26, -12, + -8, -4, 16, -12, -12, -12, 27, 28, 29, -3, + -12, 34, 35, 35, -12, -12, 31, -12, -1, 13, + -12, -12, -12, 37, -12, -12 +}; + +/* YYPGOTO[NTERM-NUM]. */ +static const yytype_int8 yypgoto[] = +{ + -12, -12, -12, 36, -12, -12, -12, 30, -12, -12, + -5, -6, -12, 25 +}; + +/* YYTABLE[YYPACT[STATE-NUM]]. What to do in state STATE-NUM. If + positive, shift that token. If negative, reduce the rule which + number is the opposite. If zero, do what YYDEFACT says. + If YYTABLE_NINF, syntax error. */ +#define YYTABLE_NINF -1 +static const yytype_uint8 yytable[] = +{ + 36, 5, 37, 33, 38, 18, 19, 33, 20, 1, + 34, 6, 51, 44, 35, 52, 14, 26, 15, 36, + 16, 37, 9, 38, 18, 19, 51, 20, 8, 54, + 10, 24, 11, 23, 45, 29, 13, 49, 0, 7, + 25, 32, 41, 42, 43, 46, 47, 50, 55, 0, + 31, 27 +}; + +static const yytype_int8 yycheck[] = +{ + 3, 12, 5, 11, 7, 4, 5, 11, 7, 9, + 18, 0, 13, 16, 18, 16, 6, 16, 8, 3, + 10, 5, 13, 7, 4, 5, 13, 7, 11, 16, + 11, 17, 14, 11, 39, 11, 15, 43, -1, 3, + 17, 15, 15, 15, 15, 11, 11, 16, 11, -1, + 25, 21 +}; + +/* YYSTOS[STATE-NUM] -- The (internal number of the) accessing + symbol of state STATE-NUM. */ +static const yytype_uint8 yystos[] = +{ + 0, 9, 20, 21, 22, 12, 0, 22, 11, 13, + 11, 14, 23, 15, 6, 8, 10, 24, 4, 5, + 7, 25, 26, 11, 17, 17, 16, 26, 27, 11, + 32, 32, 15, 11, 18, 18, 3, 5, 7, 28, + 29, 15, 15, 15, 16, 29, 11, 11, 30, 30, + 16, 13, 16, 31, 16, 11 +}; + +#define yyerrok (yyerrstatus = 0) +#define yyclearin (yychar = YYEMPTY) +#define YYEMPTY (-2) +#define YYEOF 0 + +#define YYACCEPT goto yyacceptlab +#define YYABORT goto yyabortlab +#define YYERROR goto yyerrorlab + + +/* Like YYERROR except do call yyerror. This remains here temporarily + to ease the transition to the new meaning of YYERROR, for GCC. + Once GCC version 2 has supplanted version 1, this can go. */ + +#define YYFAIL goto yyerrlab + +#define YYRECOVERING() (!!yyerrstatus) + +#define YYBACKUP(Token, Value) \ +do \ + if (yychar == YYEMPTY && yylen == 1) \ + { \ + yychar = (Token); \ + yylval = (Value); \ + yytoken = YYTRANSLATE (yychar); \ + YYPOPSTACK (1); \ + goto yybackup; \ + } \ + else \ + { \ + yyerror (YY_("syntax error: cannot back up")); \ + YYERROR; \ + } \ +while (YYID (0)) + + +#define YYTERROR 1 +#define YYERRCODE 256 + + +/* YYLLOC_DEFAULT -- Set CURRENT to span from RHS[1] to RHS[N]. + If N is 0, then set CURRENT to the empty location which ends + the previous symbol: RHS[0] (always defined). */ + +#define YYRHSLOC(Rhs, K) ((Rhs)[K]) +#ifndef YYLLOC_DEFAULT +# define YYLLOC_DEFAULT(Current, Rhs, N) \ + do \ + if (YYID (N)) \ + { \ + (Current).first_line = YYRHSLOC (Rhs, 1).first_line; \ + (Current).first_column = YYRHSLOC (Rhs, 1).first_column; \ + (Current).last_line = YYRHSLOC (Rhs, N).last_line; \ + (Current).last_column = YYRHSLOC (Rhs, N).last_column; \ + } \ + else \ + { \ + (Current).first_line = (Current).last_line = \ + YYRHSLOC (Rhs, 0).last_line; \ + (Current).first_column = (Current).last_column = \ + YYRHSLOC (Rhs, 0).last_column; \ + } \ + while (YYID (0)) +#endif + + +/* YY_LOCATION_PRINT -- Print the location on the stream. + This macro was not mandated originally: define only if we know + we won't break user code: when these are the locations we know. */ + +#ifndef YY_LOCATION_PRINT +# if YYLTYPE_IS_TRIVIAL +# define YY_LOCATION_PRINT(File, Loc) \ + fprintf (File, "%d.%d-%d.%d", \ + (Loc).first_line, (Loc).first_column, \ + (Loc).last_line, (Loc).last_column) +# else +# define YY_LOCATION_PRINT(File, Loc) ((void) 0) +# endif +#endif + + +/* YYLEX -- calling `yylex' with the right arguments. */ + +#ifdef YYLEX_PARAM +# define YYLEX yylex (YYLEX_PARAM) +#else +# define YYLEX yylex () +#endif + +/* Enable debugging if requested. */ +#if YYDEBUG + +# ifndef YYFPRINTF +# include <stdio.h> /* INFRINGES ON USER NAME SPACE */ +# define YYFPRINTF fprintf +# endif + +# define YYDPRINTF(Args) \ +do { \ + if (yydebug) \ + YYFPRINTF Args; \ +} while (YYID (0)) + +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) \ +do { \ + if (yydebug) \ + { \ + YYFPRINTF (stderr, "%s ", Title); \ + yy_symbol_print (stderr, \ + Type, Value); \ + YYFPRINTF (stderr, "\n"); \ + } \ +} while (YYID (0)) + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_value_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_value_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (!yyvaluep) + return; +# ifdef YYPRINT + if (yytype < YYNTOKENS) + YYPRINT (yyoutput, yytoknum[yytype], *yyvaluep); +# else + YYUSE (yyoutput); +# endif + switch (yytype) + { + default: + break; + } +} + + +/*--------------------------------. +| Print this symbol on YYOUTPUT. | +`--------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_symbol_print (FILE *yyoutput, int yytype, YYSTYPE const * const yyvaluep) +#else +static void +yy_symbol_print (yyoutput, yytype, yyvaluep) + FILE *yyoutput; + int yytype; + YYSTYPE const * const yyvaluep; +#endif +{ + if (yytype < YYNTOKENS) + YYFPRINTF (yyoutput, "token %s (", yytname[yytype]); + else + YYFPRINTF (yyoutput, "nterm %s (", yytname[yytype]); + + yy_symbol_value_print (yyoutput, yytype, yyvaluep); + YYFPRINTF (yyoutput, ")"); +} + +/*------------------------------------------------------------------. +| yy_stack_print -- Print the state stack from its BOTTOM up to its | +| TOP (included). | +`------------------------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_stack_print (yytype_int16 *yybottom, yytype_int16 *yytop) +#else +static void +yy_stack_print (yybottom, yytop) + yytype_int16 *yybottom; + yytype_int16 *yytop; +#endif +{ + YYFPRINTF (stderr, "Stack now"); + for (; yybottom <= yytop; yybottom++) + { + int yybot = *yybottom; + YYFPRINTF (stderr, " %d", yybot); + } + YYFPRINTF (stderr, "\n"); +} + +# define YY_STACK_PRINT(Bottom, Top) \ +do { \ + if (yydebug) \ + yy_stack_print ((Bottom), (Top)); \ +} while (YYID (0)) + + +/*------------------------------------------------. +| Report that the YYRULE is going to be reduced. | +`------------------------------------------------*/ + +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yy_reduce_print (YYSTYPE *yyvsp, int yyrule) +#else +static void +yy_reduce_print (yyvsp, yyrule) + YYSTYPE *yyvsp; + int yyrule; +#endif +{ + int yynrhs = yyr2[yyrule]; + int yyi; + unsigned long int yylno = yyrline[yyrule]; + YYFPRINTF (stderr, "Reducing stack by rule %d (line %lu):\n", + yyrule - 1, yylno); + /* The symbols being reduced. */ + for (yyi = 0; yyi < yynrhs; yyi++) + { + YYFPRINTF (stderr, " $%d = ", yyi + 1); + yy_symbol_print (stderr, yyrhs[yyprhs[yyrule] + yyi], + &(yyvsp[(yyi + 1) - (yynrhs)]) + ); + YYFPRINTF (stderr, "\n"); + } +} + +# define YY_REDUCE_PRINT(Rule) \ +do { \ + if (yydebug) \ + yy_reduce_print (yyvsp, Rule); \ +} while (YYID (0)) + +/* Nonzero means print parse trace. It is left uninitialized so that + multiple parsers can coexist. */ +int yydebug; +#else /* !YYDEBUG */ +# define YYDPRINTF(Args) +# define YY_SYMBOL_PRINT(Title, Type, Value, Location) +# define YY_STACK_PRINT(Bottom, Top) +# define YY_REDUCE_PRINT(Rule) +#endif /* !YYDEBUG */ + + +/* YYINITDEPTH -- initial size of the parser's stacks. */ +#ifndef YYINITDEPTH +# define YYINITDEPTH 200 +#endif + +/* YYMAXDEPTH -- maximum size the stacks can grow to (effective only + if the built-in stack extension method is used). + + Do not make this value too large; the results are undefined if + YYSTACK_ALLOC_MAXIMUM < YYSTACK_BYTES (YYMAXDEPTH) + evaluated with infinite-precision integer arithmetic. */ + +#ifndef YYMAXDEPTH +# define YYMAXDEPTH 10000 +#endif + + + +#if YYERROR_VERBOSE + +# ifndef yystrlen +# if defined __GLIBC__ && defined _STRING_H +# define yystrlen strlen +# else +/* Return the length of YYSTR. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static YYSIZE_T +yystrlen (const char *yystr) +#else +static YYSIZE_T +yystrlen (yystr) + const char *yystr; +#endif +{ + YYSIZE_T yylen; + for (yylen = 0; yystr[yylen]; yylen++) + continue; + return yylen; +} +# endif +# endif + +# ifndef yystpcpy +# if defined __GLIBC__ && defined _STRING_H && defined _GNU_SOURCE +# define yystpcpy stpcpy +# else +/* Copy YYSRC to YYDEST, returning the address of the terminating '\0' in + YYDEST. */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static char * +yystpcpy (char *yydest, const char *yysrc) +#else +static char * +yystpcpy (yydest, yysrc) + char *yydest; + const char *yysrc; +#endif +{ + char *yyd = yydest; + const char *yys = yysrc; + + while ((*yyd++ = *yys++) != '\0') + continue; + + return yyd - 1; +} +# endif +# endif + +# ifndef yytnamerr +/* Copy to YYRES the contents of YYSTR after stripping away unnecessary + quotes and backslashes, so that it's suitable for yyerror. The + heuristic is that double-quoting is unnecessary unless the string + contains an apostrophe, a comma, or backslash (other than + backslash-backslash). YYSTR is taken from yytname. If YYRES is + null, do not copy; instead, return the length of what the result + would have been. */ +static YYSIZE_T +yytnamerr (char *yyres, const char *yystr) +{ + if (*yystr == '"') + { + YYSIZE_T yyn = 0; + char const *yyp = yystr; + + for (;;) + switch (*++yyp) + { + case '\'': + case ',': + goto do_not_strip_quotes; + + case '\\': + if (*++yyp != '\\') + goto do_not_strip_quotes; + /* Fall through. */ + default: + if (yyres) + yyres[yyn] = *yyp; + yyn++; + break; + + case '"': + if (yyres) + yyres[yyn] = '\0'; + return yyn; + } + do_not_strip_quotes: ; + } + + if (! yyres) + return yystrlen (yystr); + + return yystpcpy (yyres, yystr) - yyres; +} +# endif + +/* Copy into YYRESULT an error message about the unexpected token + YYCHAR while in state YYSTATE. Return the number of bytes copied, + including the terminating null byte. If YYRESULT is null, do not + copy anything; just return the number of bytes that would be + copied. As a special case, return 0 if an ordinary "syntax error" + message will do. Return YYSIZE_MAXIMUM if overflow occurs during + size calculation. */ +static YYSIZE_T +yysyntax_error (char *yyresult, int yystate, int yychar) +{ + int yyn = yypact[yystate]; + + if (! (YYPACT_NINF < yyn && yyn <= YYLAST)) + return 0; + else + { + int yytype = YYTRANSLATE (yychar); + YYSIZE_T yysize0 = yytnamerr (0, yytname[yytype]); + YYSIZE_T yysize = yysize0; + YYSIZE_T yysize1; + int yysize_overflow = 0; + enum { YYERROR_VERBOSE_ARGS_MAXIMUM = 5 }; + char const *yyarg[YYERROR_VERBOSE_ARGS_MAXIMUM]; + int yyx; + +# if 0 + /* This is so xgettext sees the translatable formats that are + constructed on the fly. */ + YY_("syntax error, unexpected %s"); + YY_("syntax error, unexpected %s, expecting %s"); + YY_("syntax error, unexpected %s, expecting %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s"); + YY_("syntax error, unexpected %s, expecting %s or %s or %s or %s"); +# endif + char *yyfmt; + char const *yyf; + static char const yyunexpected[] = "syntax error, unexpected %s"; + static char const yyexpecting[] = ", expecting %s"; + static char const yyor[] = " or %s"; + char yyformat[sizeof yyunexpected + + sizeof yyexpecting - 1 + + ((YYERROR_VERBOSE_ARGS_MAXIMUM - 2) + * (sizeof yyor - 1))]; + char const *yyprefix = yyexpecting; + + /* Start YYX at -YYN if negative to avoid negative indexes in + YYCHECK. */ + int yyxbegin = yyn < 0 ? -yyn : 0; + + /* Stay within bounds of both yycheck and yytname. */ + int yychecklim = YYLAST - yyn + 1; + int yyxend = yychecklim < YYNTOKENS ? yychecklim : YYNTOKENS; + int yycount = 1; + + yyarg[0] = yytname[yytype]; + yyfmt = yystpcpy (yyformat, yyunexpected); + + for (yyx = yyxbegin; yyx < yyxend; ++yyx) + if (yycheck[yyx + yyn] == yyx && yyx != YYTERROR) + { + if (yycount == YYERROR_VERBOSE_ARGS_MAXIMUM) + { + yycount = 1; + yysize = yysize0; + yyformat[sizeof yyunexpected - 1] = '\0'; + break; + } + yyarg[yycount++] = yytname[yyx]; + yysize1 = yysize + yytnamerr (0, yytname[yyx]); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + yyfmt = yystpcpy (yyfmt, yyprefix); + yyprefix = yyor; + } + + yyf = YY_(yyformat); + yysize1 = yysize + yystrlen (yyf); + yysize_overflow |= (yysize1 < yysize); + yysize = yysize1; + + if (yysize_overflow) + return YYSIZE_MAXIMUM; + + if (yyresult) + { + /* Avoid sprintf, as that infringes on the user's name space. + Don't have undefined behavior even if the translation + produced a string with the wrong number of "%s"s. */ + char *yyp = yyresult; + int yyi = 0; + while ((*yyp = *yyf) != '\0') + { + if (*yyp == '%' && yyf[1] == 's' && yyi < yycount) + { + yyp += yytnamerr (yyp, yyarg[yyi++]); + yyf += 2; + } + else + { + yyp++; + yyf++; + } + } + } + return yysize; + } +} +#endif /* YYERROR_VERBOSE */ + + +/*-----------------------------------------------. +| Release the memory associated to this symbol. | +`-----------------------------------------------*/ + +/*ARGSUSED*/ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +static void +yydestruct (const char *yymsg, int yytype, YYSTYPE *yyvaluep) +#else +static void +yydestruct (yymsg, yytype, yyvaluep) + const char *yymsg; + int yytype; + YYSTYPE *yyvaluep; +#endif +{ + YYUSE (yyvaluep); + + if (!yymsg) + yymsg = "Deleting"; + YY_SYMBOL_PRINT (yymsg, yytype, yyvaluep, yylocationp); + + switch (yytype) + { + + default: + break; + } +} + +/* Prevent warnings from -Wmissing-prototypes. */ +#ifdef YYPARSE_PARAM +#if defined __STDC__ || defined __cplusplus +int yyparse (void *YYPARSE_PARAM); +#else +int yyparse (); +#endif +#else /* ! YYPARSE_PARAM */ +#if defined __STDC__ || defined __cplusplus +int yyparse (void); +#else +int yyparse (); +#endif +#endif /* ! YYPARSE_PARAM */ + + +/* The lookahead symbol. */ +int yychar; + +/* The semantic value of the lookahead symbol. */ +YYSTYPE yylval; + +/* Number of syntax errors so far. */ +int yynerrs; + + + +/*-------------------------. +| yyparse or yypush_parse. | +`-------------------------*/ + +#ifdef YYPARSE_PARAM +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void *YYPARSE_PARAM) +#else +int +yyparse (YYPARSE_PARAM) + void *YYPARSE_PARAM; +#endif +#else /* ! YYPARSE_PARAM */ +#if (defined __STDC__ || defined __C99__FUNC__ \ + || defined __cplusplus || defined _MSC_VER) +int +yyparse (void) +#else +int +yyparse () + +#endif +#endif +{ + + + int yystate; + /* Number of tokens to shift before error messages enabled. */ + int yyerrstatus; + + /* The stacks and their tools: + `yyss': related to states. + `yyvs': related to semantic values. + + Refer to the stacks thru separate pointers, to allow yyoverflow + to reallocate them elsewhere. */ + + /* The state stack. */ + yytype_int16 yyssa[YYINITDEPTH]; + yytype_int16 *yyss; + yytype_int16 *yyssp; + + /* The semantic value stack. */ + YYSTYPE yyvsa[YYINITDEPTH]; + YYSTYPE *yyvs; + YYSTYPE *yyvsp; + + YYSIZE_T yystacksize; + + int yyn; + int yyresult; + /* Lookahead token as an internal (translated) token number. */ + int yytoken; + /* The variables used to return semantic value and location from the + action routines. */ + YYSTYPE yyval; + +#if YYERROR_VERBOSE + /* Buffer for error messages, and its allocated size. */ + char yymsgbuf[128]; + char *yymsg = yymsgbuf; + YYSIZE_T yymsg_alloc = sizeof yymsgbuf; +#endif + +#define YYPOPSTACK(N) (yyvsp -= (N), yyssp -= (N)) + + /* The number of symbols on the RHS of the reduced rule. + Keep to zero when no symbol should be popped. */ + int yylen = 0; + + yytoken = 0; + yyss = yyssa; + yyvs = yyvsa; + yystacksize = YYINITDEPTH; + + YYDPRINTF ((stderr, "Starting parse\n")); + + yystate = 0; + yyerrstatus = 0; + yynerrs = 0; + yychar = YYEMPTY; /* Cause a token to be read. */ + + /* Initialize stack pointers. + Waste one element of value and location stack + so that they stay on the same level as the state stack. + The wasted elements are never initialized. */ + yyssp = yyss; + yyvsp = yyvs; + + goto yysetstate; + +/*------------------------------------------------------------. +| yynewstate -- Push a new state, which is found in yystate. | +`------------------------------------------------------------*/ + yynewstate: + /* In all cases, when you get here, the value and location stacks + have just been pushed. So pushing a state here evens the stacks. */ + yyssp++; + + yysetstate: + *yyssp = yystate; + + if (yyss + yystacksize - 1 <= yyssp) + { + /* Get the current used size of the three stacks, in elements. */ + YYSIZE_T yysize = yyssp - yyss + 1; + +#ifdef yyoverflow + { + /* Give user a chance to reallocate the stack. Use copies of + these so that the &'s don't force the real ones into + memory. */ + YYSTYPE *yyvs1 = yyvs; + yytype_int16 *yyss1 = yyss; + + /* Each stack pointer address is followed by the size of the + data in use in that stack, in bytes. This used to be a + conditional around just the two extra args, but that might + be undefined if yyoverflow is a macro. */ + yyoverflow (YY_("memory exhausted"), + &yyss1, yysize * sizeof (*yyssp), + &yyvs1, yysize * sizeof (*yyvsp), + &yystacksize); + + yyss = yyss1; + yyvs = yyvs1; + } +#else /* no yyoverflow */ +# ifndef YYSTACK_RELOCATE + goto yyexhaustedlab; +# else + /* Extend the stack our own way. */ + if (YYMAXDEPTH <= yystacksize) + goto yyexhaustedlab; + yystacksize *= 2; + if (YYMAXDEPTH < yystacksize) + yystacksize = YYMAXDEPTH; + + { + yytype_int16 *yyss1 = yyss; + union yyalloc *yyptr = + (union yyalloc *) YYSTACK_ALLOC (YYSTACK_BYTES (yystacksize)); + if (! yyptr) + goto yyexhaustedlab; + YYSTACK_RELOCATE (yyss_alloc, yyss); + YYSTACK_RELOCATE (yyvs_alloc, yyvs); +# undef YYSTACK_RELOCATE + if (yyss1 != yyssa) + YYSTACK_FREE (yyss1); + } +# endif +#endif /* no yyoverflow */ + + yyssp = yyss + yysize - 1; + yyvsp = yyvs + yysize - 1; + + YYDPRINTF ((stderr, "Stack size increased to %lu\n", + (unsigned long int) yystacksize)); + + if (yyss + yystacksize - 1 <= yyssp) + YYABORT; + } + + YYDPRINTF ((stderr, "Entering state %d\n", yystate)); + + if (yystate == YYFINAL) + YYACCEPT; + + goto yybackup; + +/*-----------. +| yybackup. | +`-----------*/ +yybackup: + + /* Do appropriate processing given the current state. Read a + lookahead token if we need one and don't already have one. */ + + /* First try to decide what to do without reference to lookahead token. */ + yyn = yypact[yystate]; + if (yyn == YYPACT_NINF) + goto yydefault; + + /* Not known => get a lookahead token if don't already have one. */ + + /* YYCHAR is either YYEMPTY or YYEOF or a valid lookahead symbol. */ + if (yychar == YYEMPTY) + { + YYDPRINTF ((stderr, "Reading a token: ")); + yychar = YYLEX; + } + + if (yychar <= YYEOF) + { + yychar = yytoken = YYEOF; + YYDPRINTF ((stderr, "Now at end of input.\n")); + } + else + { + yytoken = YYTRANSLATE (yychar); + YY_SYMBOL_PRINT ("Next token is", yytoken, &yylval, &yylloc); + } + + /* If the proper action on seeing token YYTOKEN is to reduce or to + detect an error, take that action. */ + yyn += yytoken; + if (yyn < 0 || YYLAST < yyn || yycheck[yyn] != yytoken) + goto yydefault; + yyn = yytable[yyn]; + if (yyn <= 0) + { + if (yyn == 0 || yyn == YYTABLE_NINF) + goto yyerrlab; + yyn = -yyn; + goto yyreduce; + } + + /* Count tokens shifted since error; after three, turn off error + status. */ + if (yyerrstatus) + yyerrstatus--; + + /* Shift the lookahead token. */ + YY_SYMBOL_PRINT ("Shifting", yytoken, &yylval, &yylloc); + + /* Discard the shifted token. */ + yychar = YYEMPTY; + + yystate = yyn; + *++yyvsp = yylval; + + goto yynewstate; + + +/*-----------------------------------------------------------. +| yydefault -- do the default action for the current state. | +`-----------------------------------------------------------*/ +yydefault: + yyn = yydefact[yystate]; + if (yyn == 0) + goto yyerrlab; + goto yyreduce; + + +/*-----------------------------. +| yyreduce -- Do a reduction. | +`-----------------------------*/ +yyreduce: + /* yyn is the number of a rule to reduce with. */ + yylen = yyr2[yyn]; + + /* If YYLEN is nonzero, implement the default value of the action: + `$$ = $1'. + + Otherwise, the following line sets YYVAL to garbage. + This behavior is undocumented and Bison + users should not rely upon it. Assigning to YYVAL + unconditionally makes the parser a bit smaller, and it avoids a + GCC warning that YYVAL may be used uninitialized. */ + yyval = yyvsp[1-yylen]; + + + YY_REDUCE_PRINT (yyn); + switch (yyn) + { + case 5: + +/* Line 1455 of yacc.c */ +#line 118 "qp_parse.y" + { cur_tilex = (yyvsp[(3) - (6)].number), + cur_tiley = (yyvsp[(5) - (6)].number); + assert(cur_tilex < tile_columns); + assert(cur_tiley < tile_rows); + cur_tile = tile_qp + cur_tiley*tile_columns + cur_tilex; + mb_in_tile = jxr_get_TILE_WIDTH(cur_image, cur_tilex) * jxr_get_TILE_HEIGHT(cur_image, cur_tiley); + ;} + break; + + case 6: + +/* Line 1455 of yacc.c */ +#line 126 "qp_parse.y" + { /* Check the sanity of the calculated tile. */ + int idx; + switch (cur_tile->component_mode) { + case JXR_CM_UNIFORM: + break; + case JXR_CM_SEPARATE: + if (cur_tile->channel[0].num_lp != cur_tile->channel[1].num_lp) { + fprintf(stderr, "channel-0 and channel-1 LP counts don't match\n"); + errors += 1; + } + if (cur_tile->channel[0].num_hp != cur_tile->channel[1].num_hp) { + fprintf(stderr, "channel-0 and channel-1 HP counts don't match\n"); + errors += 1; + } + if (jxr_get_IMAGE_CHANNELS(cur_image) == 1) { + fprintf(stderr, "Gray (1-channel) tiles must be channel mode UNIFORM\n"); + errors += 1; + } + break; + case JXR_CM_INDEPENDENT: + for (idx = 1 ; idx < jxr_get_IMAGE_CHANNELS(cur_image) ; idx += 1) { + if (cur_tile->channel[0].num_lp != cur_tile->channel[idx].num_lp) { + fprintf(stderr, "channel-0 and channel-%d LP counts don't match\n", idx); + errors += 1; + } + if (cur_tile->channel[0].num_hp != cur_tile->channel[idx].num_hp) { + fprintf(stderr, "channel-0 and channel-%d HP counts don't match\n", idx); + errors += 1; + } + } + if (jxr_get_IMAGE_CHANNELS(cur_image) == 1) { + fprintf(stderr, "Gray (1-channel) tiles must be channel mode UNIFORM\n"); + errors += 1; + } + break; + case JXR_CM_Reserved: + assert(0); + break; + } + ;} + break; + + case 7: + +/* Line 1455 of yacc.c */ +#line 169 "qp_parse.y" + { cur_tile->component_mode = JXR_CM_UNIFORM; ;} + break; + + case 8: + +/* Line 1455 of yacc.c */ +#line 170 "qp_parse.y" + { cur_tile->component_mode = JXR_CM_SEPARATE; ;} + break; + + case 9: + +/* Line 1455 of yacc.c */ +#line 171 "qp_parse.y" + { cur_tile->component_mode = JXR_CM_INDEPENDENT; ;} + break; + + case 12: + +/* Line 1455 of yacc.c */ +#line 181 "qp_parse.y" + { cur_channel = (yyvsp[(2) - (2)].number); + assert(cur_channel < 16); + cur_tile->channel[cur_channel].num_lp = 0; + cur_tile->channel[cur_channel].num_hp = 0; + ;} + break; + + case 14: + +/* Line 1455 of yacc.c */ +#line 189 "qp_parse.y" + { cur_tile->lp_map = (yyvsp[(3) - (4)].map_list).data; + if ((yyvsp[(3) - (4)].map_list).count != mb_in_tile) { + errors += 1; + fprintf(stderr, "parse qp: In tile %u,%u, expected %u lp blocks, got %u.\n", + cur_tilex, cur_tiley, mb_in_tile, (yyvsp[(3) - (4)].map_list).count); + } + ;} + break; + + case 15: + +/* Line 1455 of yacc.c */ +#line 198 "qp_parse.y" + { cur_tile->hp_map = (yyvsp[(3) - (4)].map_list).data; + if ((yyvsp[(3) - (4)].map_list).count != mb_in_tile) { + errors += 1; + fprintf(stderr, "parse qp: In tile %u,%u, expected %u lp blocks, got %u.\n", + cur_tilex, cur_tiley, mb_in_tile, (yyvsp[(3) - (4)].map_list).count); + } + ;} + break; + + case 18: + +/* Line 1455 of yacc.c */ +#line 214 "qp_parse.y" + { cur_tile->channel[cur_channel].dc_qp = (yyvsp[(3) - (4)].number); ;} + break; + + case 19: + +/* Line 1455 of yacc.c */ +#line 217 "qp_parse.y" + { cur_tile->channel[cur_channel].num_lp = (yyvsp[(3) - (4)].qp_set).num; + int idx; + for (idx = 0 ; idx < (yyvsp[(3) - (4)].qp_set).num ; idx += 1) + cur_tile->channel[cur_channel].lp_qp[idx] = (yyvsp[(3) - (4)].qp_set).qp[idx]; + ;} + break; + + case 20: + +/* Line 1455 of yacc.c */ +#line 224 "qp_parse.y" + { cur_tile->channel[cur_channel].num_hp = (yyvsp[(3) - (4)].qp_set).num; + int idx; + for (idx = 0 ; idx < (yyvsp[(3) - (4)].qp_set).num ; idx += 1) + cur_tile->channel[cur_channel].hp_qp[idx] = (yyvsp[(3) - (4)].qp_set).qp[idx]; + ;} + break; + + case 21: + +/* Line 1455 of yacc.c */ +#line 234 "qp_parse.y" + { unsigned cnt = (yyvsp[(1) - (3)].qp_set).num; + if (cnt >= 16) { + fprintf(stderr, "Too many (>16) QP values in QP list.\n"); + errors += 1; + } else { + assert(cnt < 16); + (yyvsp[(1) - (3)].qp_set).qp[cnt] = (yyvsp[(3) - (3)].number); + (yyvsp[(1) - (3)].qp_set).num += 1; + } + (yyval.qp_set) = (yyvsp[(1) - (3)].qp_set); + ;} + break; + + case 22: + +/* Line 1455 of yacc.c */ +#line 246 "qp_parse.y" + { (yyval.qp_set).num = 1; + (yyval.qp_set).qp[0] = (yyvsp[(1) - (1)].number); + ;} + break; + + case 25: + +/* Line 1455 of yacc.c */ +#line 255 "qp_parse.y" + { if ((yyvsp[(1) - (2)].map_list).count >= mb_in_tile) { + fprintf(stderr, "Too many map items for tile!\n"); + errors += 1; + } else { + (yyvsp[(1) - (2)].map_list).data[(yyvsp[(1) - (2)].map_list).count++] = (yyvsp[(2) - (2)].number); + } + (yyval.map_list) = (yyvsp[(1) - (2)].map_list); + ;} + break; + + case 26: + +/* Line 1455 of yacc.c */ +#line 265 "qp_parse.y" + { assert(mb_in_tile >= 1); + (yyval.map_list).data = (unsigned char*)calloc(mb_in_tile, 1); + (yyval.map_list).count = 1; + (yyval.map_list).data[0] = (yyvsp[(1) - (1)].number); + ;} + break; + + + +/* Line 1455 of yacc.c */ +#line 1660 "qp.tab.c" + default: break; + } + YY_SYMBOL_PRINT ("-> $$ =", yyr1[yyn], &yyval, &yyloc); + + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + + *++yyvsp = yyval; + + /* Now `shift' the result of the reduction. Determine what state + that goes to, based on the state we popped back to and the rule + number reduced by. */ + + yyn = yyr1[yyn]; + + yystate = yypgoto[yyn - YYNTOKENS] + *yyssp; + if (0 <= yystate && yystate <= YYLAST && yycheck[yystate] == *yyssp) + yystate = yytable[yystate]; + else + yystate = yydefgoto[yyn - YYNTOKENS]; + + goto yynewstate; + + +/*------------------------------------. +| yyerrlab -- here on detecting error | +`------------------------------------*/ +yyerrlab: + /* If not already recovering from an error, report this error. */ + if (!yyerrstatus) + { + ++yynerrs; +#if ! YYERROR_VERBOSE + yyerror (YY_("syntax error")); +#else + { + YYSIZE_T yysize = yysyntax_error (0, yystate, yychar); + if (yymsg_alloc < yysize && yymsg_alloc < YYSTACK_ALLOC_MAXIMUM) + { + YYSIZE_T yyalloc = 2 * yysize; + if (! (yysize <= yyalloc && yyalloc <= YYSTACK_ALLOC_MAXIMUM)) + yyalloc = YYSTACK_ALLOC_MAXIMUM; + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); + yymsg = (char *) YYSTACK_ALLOC (yyalloc); + if (yymsg) + yymsg_alloc = yyalloc; + else + { + yymsg = yymsgbuf; + yymsg_alloc = sizeof yymsgbuf; + } + } + + if (0 < yysize && yysize <= yymsg_alloc) + { + (void) yysyntax_error (yymsg, yystate, yychar); + yyerror (yymsg); + } + else + { + yyerror (YY_("syntax error")); + if (yysize != 0) + goto yyexhaustedlab; + } + } +#endif + } + + + + if (yyerrstatus == 3) + { + /* If just tried and failed to reuse lookahead token after an + error, discard it. */ + + if (yychar <= YYEOF) + { + /* Return failure if at end of input. */ + if (yychar == YYEOF) + YYABORT; + } + else + { + yydestruct ("Error: discarding", + yytoken, &yylval); + yychar = YYEMPTY; + } + } + + /* Else will try to reuse lookahead token after shifting the error + token. */ + goto yyerrlab1; + + +/*---------------------------------------------------. +| yyerrorlab -- error raised explicitly by YYERROR. | +`---------------------------------------------------*/ +yyerrorlab: + + /* Pacify compilers like GCC when the user code never invokes + YYERROR and the label yyerrorlab therefore never appears in user + code. */ + if (/*CONSTCOND*/ 0) + goto yyerrorlab; + + /* Do not reclaim the symbols of the rule which action triggered + this YYERROR. */ + YYPOPSTACK (yylen); + yylen = 0; + YY_STACK_PRINT (yyss, yyssp); + yystate = *yyssp; + goto yyerrlab1; + + +/*-------------------------------------------------------------. +| yyerrlab1 -- common code for both syntax error and YYERROR. | +`-------------------------------------------------------------*/ +yyerrlab1: + yyerrstatus = 3; /* Each real token shifted decrements this. */ + + for (;;) + { + yyn = yypact[yystate]; + if (yyn != YYPACT_NINF) + { + yyn += YYTERROR; + if (0 <= yyn && yyn <= YYLAST && yycheck[yyn] == YYTERROR) + { + yyn = yytable[yyn]; + if (0 < yyn) + break; + } + } + + /* Pop the current state because it cannot handle the error token. */ + if (yyssp == yyss) + YYABORT; + + + yydestruct ("Error: popping", + yystos[yystate], yyvsp); + YYPOPSTACK (1); + yystate = *yyssp; + YY_STACK_PRINT (yyss, yyssp); + } + + *++yyvsp = yylval; + + + /* Shift the error token. */ + YY_SYMBOL_PRINT ("Shifting", yystos[yyn], yyvsp, yylsp); + + yystate = yyn; + goto yynewstate; + + +/*-------------------------------------. +| yyacceptlab -- YYACCEPT comes here. | +`-------------------------------------*/ +yyacceptlab: + yyresult = 0; + goto yyreturn; + +/*-----------------------------------. +| yyabortlab -- YYABORT comes here. | +`-----------------------------------*/ +yyabortlab: + yyresult = 1; + goto yyreturn; + +#if !defined(yyoverflow) || YYERROR_VERBOSE +/*-------------------------------------------------. +| yyexhaustedlab -- memory exhaustion comes here. | +`-------------------------------------------------*/ +yyexhaustedlab: + yyerror (YY_("memory exhausted")); + yyresult = 2; + /* Fall through. */ +#endif + +yyreturn: + if (yychar != YYEMPTY) + yydestruct ("Cleanup: discarding lookahead", + yytoken, &yylval); + /* Do not reclaim the symbols of the rule which action triggered + this YYABORT or YYACCEPT. */ + YYPOPSTACK (yylen); + YY_STACK_PRINT (yyss, yyssp); + while (yyssp != yyss) + { + yydestruct ("Cleanup: popping", + yystos[*yyssp], yyvsp); + YYPOPSTACK (1); + } +#ifndef yyoverflow + if (yyss != yyssa) + YYSTACK_FREE (yyss); +#endif +#if YYERROR_VERBOSE + if (yymsg != yymsgbuf) + YYSTACK_FREE (yymsg); +#endif + /* Make sure YYID is used. */ + return YYID (yyresult); +} + + + +/* Line 1675 of yacc.c */ +#line 272 "qp_parse.y" + + +extern void qp_restart(FILE*fd); + +int qp_parse_file(FILE*fd, jxr_image_t image) +{ + cur_image = image; + tile_columns = jxr_get_TILE_COLUMNS(image); + tile_rows = jxr_get_TILE_ROWS(image); + + tile_qp = (struct jxr_tile_qp *) calloc(tile_columns*tile_rows, sizeof(*tile_qp)); + assert(tile_qp); + +#if defined(DETAILED_DEBUG) + printf("qp_parse: tile_columns=%u, tile_rows=%u\n", tile_columns, tile_rows); +#endif + + qp_restart(fd); + yyparse(); + +#if defined(DETAILED_DEBUG) + printf("qp_parse: parse done with %u errors\n", errors); +#endif + + if (errors) return -1; + + jxr_set_QP_DISTRIBUTED(image, tile_qp); + return 0; +} + + + +static void yyerror(const char*txt) +{ + fprintf(stderr, "parsing QP file: %s\n", txt); + errors += 1; +} + diff --git a/jpegxr/qp.tab.h b/jpegxr/qp.tab.h new file mode 100644 index 000000000..fd17ca14a --- /dev/null +++ b/jpegxr/qp.tab.h @@ -0,0 +1,87 @@ + +/* A Bison parser, made by GNU Bison 2.4.1. */ + +/* Skeleton interface for Bison's Yacc-like parsers in C + + Copyright (C) 1984, 1989, 1990, 2000, 2001, 2002, 2003, 2004, 2005, 2006 + Free Software Foundation, Inc. + + This program is free software: you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation, either version 3 of the License, or + (at your option) any later version. + + This program 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 General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +/* As a special exception, you may create a larger work that contains + part or all of the Bison parser skeleton and distribute that work + under terms of your choice, so long as that work isn't itself a + parser generator using the skeleton or a modified version thereof + as a parser skeleton. Alternatively, if you modify or redistribute + the parser skeleton itself, you may (at your option) remove this + special exception, which will cause the skeleton and the resulting + Bison output files to be licensed under the GNU General Public + License without this special exception. + + This special exception was added by the Free Software Foundation in + version 2.2 of Bison. */ + + +/* Tokens. */ +#ifndef YYTOKENTYPE +# define YYTOKENTYPE + /* Put the tokens into the symbol table, so that GDB and other debuggers + know about them. */ + enum yytokentype { + K_DC = 258, + K_CHANNEL = 259, + K_HP = 260, + K_INDEPENDENT = 261, + K_LP = 262, + K_SEPARATE = 263, + K_TILE = 264, + K_UNIFORM = 265, + NUMBER = 266 + }; +#endif + + + +#if ! defined YYSTYPE && ! defined YYSTYPE_IS_DECLARED +typedef union YYSTYPE +{ + +/* Line 1676 of yacc.c */ +#line 82 "qp_parse.y" + + unsigned number; + + struct { + unsigned char*data; + unsigned count; + } map_list; + + struct sixteen_nums { + unsigned char num; + unsigned char qp[16]; + } qp_set; + + + +/* Line 1676 of yacc.c */ +#line 79 "qp.tab.h" +} YYSTYPE; +# define YYSTYPE_IS_TRIVIAL 1 +# define yystype YYSTYPE /* obsolescent; will be withdrawn */ +# define YYSTYPE_IS_DECLARED 1 +#endif + +extern YYSTYPE qp_lval; + + diff --git a/jpegxr/qp_lexor.c b/jpegxr/qp_lexor.c new file mode 100644 index 000000000..8d9a8af7f --- /dev/null +++ b/jpegxr/qp_lexor.c @@ -0,0 +1,1869 @@ +#line 2 "qp_lexor.c" + +#line 4 "qp_lexor.c" + +#define YY_INT_ALIGNED short int + +/* A lexical scanner generated by flex */ + +#define yy_create_buffer qp__create_buffer +#define yy_delete_buffer qp__delete_buffer +#define yy_flex_debug qp__flex_debug +#define yy_init_buffer qp__init_buffer +#define yy_flush_buffer qp__flush_buffer +#define yy_load_buffer_state qp__load_buffer_state +#define yy_switch_to_buffer qp__switch_to_buffer +#define yyin qp_in +#define yyleng qp_leng +#define yylex qp_lex +#define yylineno qp_lineno +#define yyout qp_out +#define yyrestart qp_restart +#define yytext qp_text +#define yywrap qp_wrap +#define yyalloc qp_alloc +#define yyrealloc qp_realloc +#define yyfree qp_free + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 +#define YY_FLEX_SUBMINOR_VERSION 35 +#if YY_FLEX_SUBMINOR_VERSION > 0 +#define FLEX_BETA +#endif + +/* First, we deal with platform-specific or compiler-specific issues. */ + +/* begin standard C headers. */ +#include <stdio.h> +#include <string.h> +#include <errno.h> +#include <stdlib.h> + +/* end standard C headers. */ + +/* flex integer type definitions */ + +#ifndef FLEXINT_H +#define FLEXINT_H + +/* C99 systems have <inttypes.h>. Non-C99 systems may or may not. */ + +#if defined (__STDC_VERSION__) && __STDC_VERSION__ >= 199901L + +/* C99 says to define __STDC_LIMIT_MACROS before including stdint.h, + * if you want the limit (max/min) macros for int types. + */ +#ifndef __STDC_LIMIT_MACROS +#define __STDC_LIMIT_MACROS 1 +#endif + +#include <inttypes.h> +typedef int8_t flex_int8_t; +typedef uint8_t flex_uint8_t; +typedef int16_t flex_int16_t; +typedef uint16_t flex_uint16_t; +typedef int32_t flex_int32_t; +typedef uint32_t flex_uint32_t; +#else +typedef signed char flex_int8_t; +typedef short int flex_int16_t; +typedef int flex_int32_t; +typedef unsigned char flex_uint8_t; +typedef unsigned short int flex_uint16_t; +typedef unsigned int flex_uint32_t; + +/* Limits of integral types. */ +#ifndef INT8_MIN +#define INT8_MIN (-128) +#endif +#ifndef INT16_MIN +#define INT16_MIN (-32767-1) +#endif +#ifndef INT32_MIN +#define INT32_MIN (-2147483647-1) +#endif +#ifndef INT8_MAX +#define INT8_MAX (127) +#endif +#ifndef INT16_MAX +#define INT16_MAX (32767) +#endif +#ifndef INT32_MAX +#define INT32_MAX (2147483647) +#endif +#ifndef UINT8_MAX +#define UINT8_MAX (255U) +#endif +#ifndef UINT16_MAX +#define UINT16_MAX (65535U) +#endif +#ifndef UINT32_MAX +#define UINT32_MAX (4294967295U) +#endif + +#endif /* ! C99 */ + +#endif /* ! FLEXINT_H */ + +#ifdef __cplusplus + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +/* C99 requires __STDC__ to be defined as 1. */ +#if defined (__STDC__) + +#define YY_USE_CONST + +#endif /* defined (__STDC__) */ +#endif /* ! __cplusplus */ + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN (yy_start) = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START (((yy_start) - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE qp_restart(qp_in ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#ifndef YY_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k. + * Moreover, YY_BUF_SIZE is 2*YY_READ_BUF_SIZE in the general case. + * Ditto for the __ia64__ case accordingly. + */ +#define YY_BUF_SIZE 32768 +#else +#define YY_BUF_SIZE 16384 +#endif /* __ia64__ */ +#endif + +/* The state buf must be large enough to hold one state per character in the main buffer. + */ +#define YY_STATE_BUF_SIZE ((YY_BUF_SIZE + 2) * sizeof(yy_state_type)) + +#ifndef YY_TYPEDEF_YY_BUFFER_STATE +#define YY_TYPEDEF_YY_BUFFER_STATE +typedef struct yy_buffer_state *YY_BUFFER_STATE; +#endif + +extern int qp_leng; + +extern FILE *qp_in, *qp_out; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + + #define YY_LESS_LINENO(n) + +/* Return all but the first "n" matched characters back to the input stream. */ +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up qp_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + *yy_cp = (yy_hold_char); \ + YY_RESTORE_YY_MORE_OFFSET \ + (yy_c_buf_p) = yy_cp = yy_bp + yyless_macro_arg - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up qp_text again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, (yytext_ptr) ) + +#ifndef YY_TYPEDEF_YY_SIZE_T +#define YY_TYPEDEF_YY_SIZE_T +typedef size_t yy_size_t; +#endif + +#ifndef YY_STRUCT_YY_BUFFER_STATE +#define YY_STRUCT_YY_BUFFER_STATE +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + int yy_bs_lineno; /**< The line count. */ + int yy_bs_column; /**< The column count. */ + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; + +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via qp_restart()), so that the user can continue scanning by + * just pointing qp_in at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + + }; +#endif /* !YY_STRUCT_YY_BUFFER_STATE */ + +/* Stack of input buffers. */ +static size_t yy_buffer_stack_top = 0; /**< index of top of stack. */ +static size_t yy_buffer_stack_max = 0; /**< capacity of stack. */ +static YY_BUFFER_STATE * yy_buffer_stack = 0; /**< Stack as an array. */ + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + * + * Returns the top of the stack, or NULL. + */ +#define YY_CURRENT_BUFFER ( (yy_buffer_stack) \ + ? (yy_buffer_stack)[(yy_buffer_stack_top)] \ + : NULL) + +/* Same as previous macro, but useful when we know that the buffer stack is not + * NULL or when we need an lvalue. For internal use only. + */ +#define YY_CURRENT_BUFFER_LVALUE (yy_buffer_stack)[(yy_buffer_stack_top)] + +/* yy_hold_char holds the character lost when qp_text is formed. */ +static char yy_hold_char; +static int yy_n_chars; /* number of characters read into yy_ch_buf */ +int qp_leng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 0; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow qp_wrap()'s to do buffer switches + * instead of setting up a fresh qp_in. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void qp_restart (FILE *input_file ); +void qp__switch_to_buffer (YY_BUFFER_STATE new_buffer ); +YY_BUFFER_STATE qp__create_buffer (FILE *file,int size ); +void qp__delete_buffer (YY_BUFFER_STATE b ); +void qp__flush_buffer (YY_BUFFER_STATE b ); +void qp_push_buffer_state (YY_BUFFER_STATE new_buffer ); +void qp_pop_buffer_state (void ); + +static void qp_ensure_buffer_stack (void ); +static void qp__load_buffer_state (void ); +static void qp__init_buffer (YY_BUFFER_STATE b,FILE *file ); + +#define YY_FLUSH_BUFFER qp__flush_buffer(YY_CURRENT_BUFFER ) + +YY_BUFFER_STATE qp__scan_buffer (char *base,yy_size_t size ); +YY_BUFFER_STATE qp__scan_string (yyconst char *yy_str ); +YY_BUFFER_STATE qp__scan_bytes (yyconst char *bytes,int len ); + +void *qp_alloc (yy_size_t ); +void *qp_realloc (void *,yy_size_t ); +void qp_free (void * ); + +#define yy_new_buffer qp__create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! YY_CURRENT_BUFFER ){ \ + qp_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + qp__create_buffer(qp_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! YY_CURRENT_BUFFER ){\ + qp_ensure_buffer_stack (); \ + YY_CURRENT_BUFFER_LVALUE = \ + qp__create_buffer(qp_in,YY_BUF_SIZE ); \ + } \ + YY_CURRENT_BUFFER_LVALUE->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (YY_CURRENT_BUFFER_LVALUE->yy_at_bol) + +/* Begin user sect3 */ + +#define qp_wrap(n) 1 +#define YY_SKIP_YYWRAP + +typedef unsigned char YY_CHAR; + +FILE *qp_in = (FILE *) 0, *qp_out = (FILE *) 0; + +typedef int yy_state_type; + +extern int qp_lineno; + +int qp_lineno = 1; + +extern char *qp_text; +#define yytext_ptr qp_text + +static yy_state_type yy_get_previous_state (void ); +static yy_state_type yy_try_NUL_trans (yy_state_type current_state ); +static int yy_get_next_buffer (void ); +static void yy_fatal_error (yyconst char msg[] ); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up qp_text. + */ +#define YY_DO_BEFORE_ACTION \ + (yytext_ptr) = yy_bp; \ + qp_leng = (size_t) (yy_cp - yy_bp); \ + (yy_hold_char) = *yy_cp; \ + *yy_cp = '\0'; \ + (yy_c_buf_p) = yy_cp; + +#define YY_NUM_RULES 13 +#define YY_END_OF_BUFFER 14 +/* This struct is not used in this scanner, + but its presence is necessary. */ +struct yy_trans_info + { + flex_int32_t yy_verify; + flex_int32_t yy_nxt; + }; +static yyconst flex_int16_t yy_accept[55] = + { 0, + 0, 0, 14, 12, 1, 1, 2, 11, 12, 12, + 12, 12, 12, 12, 12, 12, 2, 11, 3, 5, + 4, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 9, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 6, 0, 0, 10, 0, 8, + 0, 0, 7, 0 + } ; + +static yyconst flex_int32_t yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 2, 3, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 2, 1, 1, 4, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 6, 7, 1, 1, + 1, 8, 1, 1, 1, 9, 1, 1, 1, 10, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 11, 1, 12, 13, + + 14, 15, 1, 16, 17, 1, 1, 18, 19, 20, + 21, 22, 1, 23, 24, 25, 26, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int32_t yy_meta[27] = + { 0, + 1, 1, 2, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1 + } ; + +static yyconst flex_int16_t yy_base[56] = + { 0, + 0, 0, 65, 66, 66, 66, 0, 59, 57, 52, + 51, 44, 39, 44, 40, 36, 0, 50, 66, 66, + 66, 43, 40, 30, 33, 33, 29, 34, 36, 32, + 30, 24, 21, 19, 66, 20, 26, 25, 27, 14, + 18, 15, 9, 14, 66, 19, 17, 66, 16, 66, + 9, 3, 66, 66, 26 + } ; + +static yyconst flex_int16_t yy_def[56] = + { 0, + 54, 1, 54, 54, 54, 54, 55, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 55, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 0, 54 + } ; + +static yyconst flex_int16_t yy_nxt[93] = + { 0, + 4, 5, 6, 7, 8, 4, 9, 10, 11, 4, + 4, 12, 4, 4, 4, 4, 13, 4, 4, 4, + 4, 4, 4, 14, 15, 16, 17, 53, 52, 51, + 50, 49, 48, 47, 46, 45, 44, 43, 42, 41, + 40, 39, 38, 37, 36, 35, 34, 33, 32, 31, + 30, 29, 28, 27, 18, 26, 25, 24, 23, 22, + 21, 20, 19, 18, 54, 3, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54 + + } ; + +static yyconst flex_int16_t yy_chk[93] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 55, 52, 51, 49, + 47, 46, 44, 43, 42, 41, 40, 39, 38, 37, + 36, 34, 33, 32, 31, 30, 29, 28, 27, 26, + 25, 24, 23, 22, 18, 16, 15, 14, 13, 12, + 11, 10, 9, 8, 3, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54, 54, 54, 54, 54, 54, 54, 54, 54, + 54, 54 + + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +extern int qp__flex_debug; +int qp__flex_debug = 0; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *qp_text; +#line 1 "qp_lexor.lex" +#line 3 "qp_lexor.lex" + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: qp_lexor.lex,v 1.6 2008/03/14 16:08:04 steve Exp $") +#else +#ident "$Id: qp_lexor.lex,v 1.6 2008/03/14 16:08:04 steve Exp $" +#endif + +# include "qp.tab.h" +# include "jxr_priv.h" + +/* Windows VidualStudio does not have a <unistd.h> header file, */ +/* so we want the nounistd option to prevent it. However, this */ +/* option doesn't seem to work properly, so we instead rely on */ +/* "sed" to remove the include from the */ +/* generated code. */ +/* %option nounistd */ +#line 575 "qp_lexor.c" + +#define INITIAL 0 + +#ifndef YY_NO_UNISTD_H +/* Special case for "unistd.h", since it is non-ANSI. We include it way + * down here because we want the user's section 1 to have been scanned first. + * The user has a chance to override it with an option. + */ +#include <unistd.h> +#endif + +#ifndef YY_EXTRA_TYPE +#define YY_EXTRA_TYPE void * +#endif + +static int yy_init_globals (void ); + +/* Accessor methods to globals. + These are made visible to non-reentrant scanners for convenience. */ + +int qp_lex_destroy (void ); + +int qp_get_debug (void ); + +void qp_set_debug (int debug_flag ); + +YY_EXTRA_TYPE qp_get_extra (void ); + +void qp_set_extra (YY_EXTRA_TYPE user_defined ); + +FILE *qp_get_in (void ); + +void qp_set_in (FILE * in_str ); + +FILE *qp_get_out (void ); + +void qp_set_out (FILE * out_str ); + +int qp_get_leng (void ); + +char *qp_get_text (void ); + +int qp_get_lineno (void ); + +void qp_set_lineno (int line_number ); + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int qp_wrap (void ); +#else +extern int qp_wrap (void ); +#endif +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy (char *,yyconst char *,int ); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * ); +#endif + +#ifndef YY_NO_INPUT + +#ifdef __cplusplus +static int yyinput (void ); +#else +static int input (void ); +#endif + +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#ifdef __ia64__ +/* On IA-64, the buffer size is 16k, not 8k */ +#define YY_READ_BUF_SIZE 16384 +#else +#define YY_READ_BUF_SIZE 8192 +#endif /* __ia64__ */ +#endif + +/* Copy whatever the last rule matched to the standard output. */ +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO do { if (fwrite( qp_text, qp_leng, 1, qp_out )) {} } while (0) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( YY_CURRENT_BUFFER_LVALUE->yy_is_interactive ) \ + { \ + int c = '*'; \ + size_t n; \ + for ( n = 0; n < max_size && \ + (c = getc( qp_in )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( qp_in ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else \ + { \ + errno=0; \ + while ( (result = fread(buf, 1, max_size, qp_in))==0 && ferror(qp_in)) \ + { \ + if( errno != EINTR) \ + { \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + break; \ + } \ + errno=0; \ + clearerr(qp_in); \ + } \ + }\ +\ + +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* end tables serialization structures and prototypes */ + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL_IS_OURS 1 + +extern int qp_lex (void); + +#define YY_DECL int qp_lex (void) +#endif /* !YY_DECL */ + +/* Code executed at the beginning of each rule, after qp_text and qp_leng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +/** The main scanner function which does all the work. + */ +YY_DECL +{ + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 67 "qp_lexor.lex" + + + +#line 764 "qp_lexor.c" + + if ( !(yy_init) ) + { + (yy_init) = 1; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! (yy_start) ) + (yy_start) = 1; /* first start state */ + + if ( ! qp_in ) + qp_in = stdin; + + if ( ! qp_out ) + qp_out = stdout; + + if ( ! YY_CURRENT_BUFFER ) { + qp_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + qp__create_buffer(qp_in,YY_BUF_SIZE ); + } + + qp__load_buffer_state( ); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = (yy_c_buf_p); + + /* Support of qp_text. */ + *yy_cp = (yy_hold_char); + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = (yy_start); +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 55 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_current_state != 54 ); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + + YY_DO_BEFORE_ACTION; + +do_action: /* This label is used only to access EOF actions. */ + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = (yy_hold_char); + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + +case 1: +/* rule 1 can match eol */ +YY_RULE_SETUP +#line 70 "qp_lexor.lex" +{ /* Skip white space */; } + YY_BREAK +case 2: +YY_RULE_SETUP +#line 71 "qp_lexor.lex" +{ /* Skip comments */; } + YY_BREAK +case 3: +YY_RULE_SETUP +#line 73 "qp_lexor.lex" +{ return K_DC; } + YY_BREAK +case 4: +YY_RULE_SETUP +#line 74 "qp_lexor.lex" +{ return K_LP; } + YY_BREAK +case 5: +YY_RULE_SETUP +#line 75 "qp_lexor.lex" +{ return K_HP; } + YY_BREAK +case 6: +YY_RULE_SETUP +#line 77 "qp_lexor.lex" +{ return K_CHANNEL; } + YY_BREAK +case 7: +YY_RULE_SETUP +#line 78 "qp_lexor.lex" +{ return K_INDEPENDENT; } + YY_BREAK +case 8: +YY_RULE_SETUP +#line 79 "qp_lexor.lex" +{ return K_SEPARATE; } + YY_BREAK +case 9: +YY_RULE_SETUP +#line 80 "qp_lexor.lex" +{ return K_TILE; } + YY_BREAK +case 10: +YY_RULE_SETUP +#line 81 "qp_lexor.lex" +{ return K_UNIFORM; } + YY_BREAK +case 11: +YY_RULE_SETUP +#line 83 "qp_lexor.lex" +{ qp_lval.number = strtoul(qp_text, 0, 0); return NUMBER; } + YY_BREAK +case 12: +YY_RULE_SETUP +#line 85 "qp_lexor.lex" +{ return qp_text[0]; } + YY_BREAK +case 13: +YY_RULE_SETUP +#line 87 "qp_lexor.lex" +ECHO; + YY_BREAK +#line 909 "qp_lexor.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - (yytext_ptr)) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = (yy_hold_char); + YY_RESTORE_YY_MORE_OFFSET + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed qp_in at a new source and called + * qp_lex(). If so, then we have to assure + * consistency between YY_CURRENT_BUFFER and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + YY_CURRENT_BUFFER_LVALUE->yy_input_file = qp_in; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( (yy_c_buf_p) <= &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + (yy_c_buf_p) = (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++(yy_c_buf_p); + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = (yy_last_accepting_cpos); + yy_current_state = (yy_last_accepting_state); + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_END_OF_FILE: + { + (yy_did_buffer_switch_on_eof) = 0; + + if ( qp_wrap( ) ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * qp_text, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + (yy_c_buf_p) = (yytext_ptr) + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = + (yytext_ptr) + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + (yy_c_buf_p) = + &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)]; + + yy_current_state = yy_get_previous_state( ); + + yy_cp = (yy_c_buf_p); + yy_bp = (yytext_ptr) + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ +} /* end of qp_lex */ + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ +static int yy_get_next_buffer (void) +{ + register char *dest = YY_CURRENT_BUFFER_LVALUE->yy_ch_buf; + register char *source = (yytext_ptr); + register int number_to_move, i; + int ret_val; + + if ( (yy_c_buf_p) > &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( (yy_c_buf_p) - (yytext_ptr) - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) ((yy_c_buf_p) - (yytext_ptr)) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( YY_CURRENT_BUFFER_LVALUE->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars) = 0; + + else + { + int num_to_read = + YY_CURRENT_BUFFER_LVALUE->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = YY_CURRENT_BUFFER; + + int yy_c_buf_p_offset = + (int) ((yy_c_buf_p) - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + qp_realloc((void *) b->yy_ch_buf,b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + (yy_c_buf_p) = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = YY_CURRENT_BUFFER_LVALUE->yy_buf_size - + number_to_move - 1; + + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[number_to_move]), + (yy_n_chars), (size_t) num_to_read ); + + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + if ( (yy_n_chars) == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + qp_restart(qp_in ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + YY_CURRENT_BUFFER_LVALUE->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + if ((yy_size_t) ((yy_n_chars) + number_to_move) > YY_CURRENT_BUFFER_LVALUE->yy_buf_size) { + /* Extend the array by 50%, plus the number we really need. */ + yy_size_t new_size = (yy_n_chars) + number_to_move + ((yy_n_chars) >> 1); + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf = (char *) qp_realloc((void *) YY_CURRENT_BUFFER_LVALUE->yy_ch_buf,new_size ); + if ( ! YY_CURRENT_BUFFER_LVALUE->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_get_next_buffer()" ); + } + + (yy_n_chars) += number_to_move; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] = YY_END_OF_BUFFER_CHAR; + YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars) + 1] = YY_END_OF_BUFFER_CHAR; + + (yytext_ptr) = &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[0]; + + return ret_val; +} + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + + static yy_state_type yy_get_previous_state (void) +{ + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = (yy_start); + + for ( yy_cp = (yytext_ptr) + YY_MORE_ADJ; yy_cp < (yy_c_buf_p); ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 55 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; +} + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + static yy_state_type yy_try_NUL_trans (yy_state_type yy_current_state ) +{ + register int yy_is_jam; + register char *yy_cp = (yy_c_buf_p); + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + (yy_last_accepting_state) = yy_current_state; + (yy_last_accepting_cpos) = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 55 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 54); + + return yy_is_jam ? 0 : yy_current_state; +} + +#ifndef YY_NO_INPUT +#ifdef __cplusplus + static int yyinput (void) +#else + static int input (void) +#endif + +{ + int c; + + *(yy_c_buf_p) = (yy_hold_char); + + if ( *(yy_c_buf_p) == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( (yy_c_buf_p) < &YY_CURRENT_BUFFER_LVALUE->yy_ch_buf[(yy_n_chars)] ) + /* This was really a NUL. */ + *(yy_c_buf_p) = '\0'; + + else + { /* need more input */ + int offset = (yy_c_buf_p) - (yytext_ptr); + ++(yy_c_buf_p); + + switch ( yy_get_next_buffer( ) ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + qp_restart(qp_in ); + + /*FALLTHROUGH*/ + + case EOB_ACT_END_OF_FILE: + { + if ( qp_wrap( ) ) + return EOF; + + if ( ! (yy_did_buffer_switch_on_eof) ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + (yy_c_buf_p) = (yytext_ptr) + offset; + break; + } + } + } + + c = *(unsigned char *) (yy_c_buf_p); /* cast for 8-bit char's */ + *(yy_c_buf_p) = '\0'; /* preserve qp_text */ + (yy_hold_char) = *++(yy_c_buf_p); + + return c; +} +#endif /* ifndef YY_NO_INPUT */ + +/** Immediately switch to a different input stream. + * @param input_file A readable stream. + * + * @note This function does not reset the start condition to @c INITIAL . + */ + void qp_restart (FILE * input_file ) +{ + + if ( ! YY_CURRENT_BUFFER ){ + qp_ensure_buffer_stack (); + YY_CURRENT_BUFFER_LVALUE = + qp__create_buffer(qp_in,YY_BUF_SIZE ); + } + + qp__init_buffer(YY_CURRENT_BUFFER,input_file ); + qp__load_buffer_state( ); +} + +/** Switch to a different input buffer. + * @param new_buffer The new input buffer. + * + */ + void qp__switch_to_buffer (YY_BUFFER_STATE new_buffer ) +{ + + /* TODO. We should be able to replace this entire function body + * with + * qp_pop_buffer_state(); + * qp_push_buffer_state(new_buffer); + */ + qp_ensure_buffer_stack (); + if ( YY_CURRENT_BUFFER == new_buffer ) + return; + + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + YY_CURRENT_BUFFER_LVALUE = new_buffer; + qp__load_buffer_state( ); + + /* We don't actually know whether we did this switch during + * EOF (qp_wrap()) processing, but the only time this flag + * is looked at is after qp_wrap() is called, so it's safe + * to go ahead and always set it. + */ + (yy_did_buffer_switch_on_eof) = 1; +} + +static void qp__load_buffer_state (void) +{ + (yy_n_chars) = YY_CURRENT_BUFFER_LVALUE->yy_n_chars; + (yytext_ptr) = (yy_c_buf_p) = YY_CURRENT_BUFFER_LVALUE->yy_buf_pos; + qp_in = YY_CURRENT_BUFFER_LVALUE->yy_input_file; + (yy_hold_char) = *(yy_c_buf_p); +} + +/** Allocate and initialize an input buffer state. + * @param file A readable stream. + * @param size The character buffer size in bytes. When in doubt, use @c YY_BUF_SIZE. + * + * @return the allocated buffer state. + */ + YY_BUFFER_STATE qp__create_buffer (FILE * file, int size ) +{ + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) qp_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in qp__create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) qp_alloc(b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in qp__create_buffer()" ); + + b->yy_is_our_buffer = 1; + + qp__init_buffer(b,file ); + + return b; +} + +/** Destroy the buffer. + * @param b a buffer created with qp__create_buffer() + * + */ + void qp__delete_buffer (YY_BUFFER_STATE b ) +{ + + if ( ! b ) + return; + + if ( b == YY_CURRENT_BUFFER ) /* Not sure if we should pop here. */ + YY_CURRENT_BUFFER_LVALUE = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + qp_free((void *) b->yy_ch_buf ); + + qp_free((void *) b ); +} + +/* Initializes or reinitializes a buffer. + * This function is sometimes called more than once on the same buffer, + * such as during a qp_restart() or at EOF. + */ + static void qp__init_buffer (YY_BUFFER_STATE b, FILE * file ) + +{ + int oerrno = errno; + + qp__flush_buffer(b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + + /* If b is the current buffer, then qp__init_buffer was _probably_ + * called from qp_restart() or through yy_get_next_buffer. + * In that case, we don't want to reset the lineno or column. + */ + if (b != YY_CURRENT_BUFFER){ + b->yy_bs_lineno = 1; + b->yy_bs_column = 0; + } + + b->yy_is_interactive = 0; + + errno = oerrno; +} + +/** Discard all buffered characters. On the next scan, YY_INPUT will be called. + * @param b the buffer state to be flushed, usually @c YY_CURRENT_BUFFER. + * + */ + void qp__flush_buffer (YY_BUFFER_STATE b ) +{ + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == YY_CURRENT_BUFFER ) + qp__load_buffer_state( ); +} + +/** Pushes the new state onto the stack. The new state becomes + * the current state. This function will allocate the stack + * if necessary. + * @param new_buffer The new state. + * + */ +void qp_push_buffer_state (YY_BUFFER_STATE new_buffer ) +{ + if (new_buffer == NULL) + return; + + qp_ensure_buffer_stack(); + + /* This block is copied from qp__switch_to_buffer. */ + if ( YY_CURRENT_BUFFER ) + { + /* Flush out information for old buffer. */ + *(yy_c_buf_p) = (yy_hold_char); + YY_CURRENT_BUFFER_LVALUE->yy_buf_pos = (yy_c_buf_p); + YY_CURRENT_BUFFER_LVALUE->yy_n_chars = (yy_n_chars); + } + + /* Only push if top exists. Otherwise, replace top. */ + if (YY_CURRENT_BUFFER) + (yy_buffer_stack_top)++; + YY_CURRENT_BUFFER_LVALUE = new_buffer; + + /* copied from qp__switch_to_buffer. */ + qp__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; +} + +/** Removes and deletes the top of the stack, if present. + * The next element becomes the new top. + * + */ +void qp_pop_buffer_state (void) +{ + if (!YY_CURRENT_BUFFER) + return; + + qp__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + if ((yy_buffer_stack_top) > 0) + --(yy_buffer_stack_top); + + if (YY_CURRENT_BUFFER) { + qp__load_buffer_state( ); + (yy_did_buffer_switch_on_eof) = 1; + } +} + +/* Allocates the stack if it does not exist. + * Guarantees space for at least one push. + */ +static void qp_ensure_buffer_stack (void) +{ + int num_to_alloc; + + if (!(yy_buffer_stack)) { + + /* First allocation is just for 2 elements, since we don't know if this + * scanner will even need a stack. We use 2 instead of 1 to avoid an + * immediate realloc on the next call. + */ + num_to_alloc = 1; + (yy_buffer_stack) = (struct yy_buffer_state**)qp_alloc + (num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in qp_ensure_buffer_stack()" ); + + memset((yy_buffer_stack), 0, num_to_alloc * sizeof(struct yy_buffer_state*)); + + (yy_buffer_stack_max) = num_to_alloc; + (yy_buffer_stack_top) = 0; + return; + } + + if ((yy_buffer_stack_top) >= ((yy_buffer_stack_max)) - 1){ + + /* Increase the buffer to prepare for a possible push. */ + int grow_size = 8 /* arbitrary grow size */; + + num_to_alloc = (yy_buffer_stack_max) + grow_size; + (yy_buffer_stack) = (struct yy_buffer_state**)qp_realloc + ((yy_buffer_stack), + num_to_alloc * sizeof(struct yy_buffer_state*) + ); + if ( ! (yy_buffer_stack) ) + YY_FATAL_ERROR( "out of dynamic memory in qp_ensure_buffer_stack()" ); + + /* zero only the new slots.*/ + memset((yy_buffer_stack) + (yy_buffer_stack_max), 0, grow_size * sizeof(struct yy_buffer_state*)); + (yy_buffer_stack_max) = num_to_alloc; + } +} + +/** Setup the input buffer state to scan directly from a user-specified character buffer. + * @param base the character buffer + * @param size the size in bytes of the character buffer + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE qp__scan_buffer (char * base, yy_size_t size ) +{ + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) qp_alloc(sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in qp__scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + qp__switch_to_buffer(b ); + + return b; +} + +/** Setup the input buffer state to scan a string. The next call to qp_lex() will + * scan from a @e copy of @a str. + * @param yystr a NUL-terminated string to scan + * + * @return the newly allocated buffer state object. + * @note If you want to scan bytes that may contain NUL values, then use + * qp__scan_bytes() instead. + */ +YY_BUFFER_STATE qp__scan_string (yyconst char * yystr ) +{ + + return qp__scan_bytes(yystr,strlen(yystr) ); +} + +/** Setup the input buffer state to scan the given bytes. The next call to qp_lex() will + * scan from a @e copy of @a bytes. + * @param yybytes the byte buffer to scan + * @param _yybytes_len the number of bytes in the buffer pointed to by @a bytes. + * + * @return the newly allocated buffer state object. + */ +YY_BUFFER_STATE qp__scan_bytes (yyconst char * yybytes, int _yybytes_len ) +{ + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = _yybytes_len + 2; + buf = (char *) qp_alloc(n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in qp__scan_bytes()" ); + + for ( i = 0; i < _yybytes_len; ++i ) + buf[i] = yybytes[i]; + + buf[_yybytes_len] = buf[_yybytes_len+1] = YY_END_OF_BUFFER_CHAR; + + b = qp__scan_buffer(buf,n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in qp__scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; +} + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +static void yy_fatal_error (yyconst char* msg ) +{ + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); +} + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up qp_text. */ \ + int yyless_macro_arg = (n); \ + YY_LESS_LINENO(yyless_macro_arg);\ + qp_text[qp_leng] = (yy_hold_char); \ + (yy_c_buf_p) = qp_text + yyless_macro_arg; \ + (yy_hold_char) = *(yy_c_buf_p); \ + *(yy_c_buf_p) = '\0'; \ + qp_leng = yyless_macro_arg; \ + } \ + while ( 0 ) + +/* Accessor methods (get/set functions) to struct members. */ + +/** Get the current line number. + * + */ +int qp_get_lineno (void) +{ + + return qp_lineno; +} + +/** Get the input stream. + * + */ +FILE *qp_get_in (void) +{ + return qp_in; +} + +/** Get the output stream. + * + */ +FILE *qp_get_out (void) +{ + return qp_out; +} + +/** Get the length of the current token. + * + */ +int qp_get_leng (void) +{ + return qp_leng; +} + +/** Get the current token. + * + */ + +char *qp_get_text (void) +{ + return qp_text; +} + +/** Set the current line number. + * @param line_number + * + */ +void qp_set_lineno (int line_number ) +{ + + qp_lineno = line_number; +} + +/** Set the input stream. This does not discard the current + * input buffer. + * @param in_str A readable stream. + * + * @see qp__switch_to_buffer + */ +void qp_set_in (FILE * in_str ) +{ + qp_in = in_str ; +} + +void qp_set_out (FILE * out_str ) +{ + qp_out = out_str ; +} + +int qp_get_debug (void) +{ + return qp__flex_debug; +} + +void qp_set_debug (int bdebug ) +{ + qp__flex_debug = bdebug ; +} + +static int yy_init_globals (void) +{ + /* Initialization is the same as for the non-reentrant scanner. + * This function is called from qp_lex_destroy(), so don't allocate here. + */ + + (yy_buffer_stack) = 0; + (yy_buffer_stack_top) = 0; + (yy_buffer_stack_max) = 0; + (yy_c_buf_p) = (char *) 0; + (yy_init) = 0; + (yy_start) = 0; + +/* Defined in main.c */ +#ifdef YY_STDINIT + qp_in = stdin; + qp_out = stdout; +#else + qp_in = (FILE *) 0; + qp_out = (FILE *) 0; +#endif + + /* For future reference: Set errno on error, since we are called by + * qp_lex_init() + */ + return 0; +} + +/* qp_lex_destroy is for both reentrant and non-reentrant scanners. */ +int qp_lex_destroy (void) +{ + + /* Pop the buffer stack, destroying each element. */ + while(YY_CURRENT_BUFFER){ + qp__delete_buffer(YY_CURRENT_BUFFER ); + YY_CURRENT_BUFFER_LVALUE = NULL; + qp_pop_buffer_state(); + } + + /* Destroy the stack itself. */ + qp_free((yy_buffer_stack) ); + (yy_buffer_stack) = NULL; + + /* Reset the globals. This is important in a non-reentrant scanner so the next time + * qp_lex() is called, initialization will occur. */ + yy_init_globals( ); + + return 0; +} + +/* + * Internal utility routines. + */ + +#ifndef yytext_ptr +static void yy_flex_strncpy (char* s1, yyconst char * s2, int n ) +{ + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; +} +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen (yyconst char * s ) +{ + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; +} +#endif + +void *qp_alloc (yy_size_t size ) +{ + return (void *) malloc( size ); +} + +void *qp_realloc (void * ptr, yy_size_t size ) +{ + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); +} + +void qp_free (void * ptr ) +{ + free( (char *) ptr ); /* see qp_realloc() for (char *) cast */ +} + +#define YYTABLES_NAME "yytables" + +#line 87 "qp_lexor.lex" + + + diff --git a/jpegxr/qp_lexor.lex b/jpegxr/qp_lexor.lex new file mode 100644 index 000000000..3dda90448 --- /dev/null +++ b/jpegxr/qp_lexor.lex @@ -0,0 +1,87 @@ + +%{ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: qp_lexor.lex,v 1.6 2008/03/14 16:08:04 steve Exp $") +#else +#ident "$Id: qp_lexor.lex,v 1.6 2008/03/14 16:08:04 steve Exp $" +#endif + +# include "qp.tab.h" +# include "jxr_priv.h" + +%} + +%option noyywrap +%option batch +%option never-interactive +%option nounput + + /* Windows VidualStudio does not have a <unistd.h> header file, */ + /* so we want the nounistd option to prevent it. However, this */ + /* option doesn't seem to work properly, so we instead rely on */ + /* "sed" to remove the include from the */ + /* generated code. */ + /* %option nounistd */ + +%% + + +[ \t\r\n] { /* Skip white space */; } +"#".* { /* Skip comments */; } + +"DC" { return K_DC; } +"LP" { return K_LP; } +"HP" { return K_HP; } + +"channel" { return K_CHANNEL; } +"independent" { return K_INDEPENDENT; } +"separate" { return K_SEPARATE; } +"tile" { return K_TILE; } +"uniform" { return K_UNIFORM; } + +[0-9]+ { qp_lval.number = strtoul(yytext, 0, 0); return NUMBER; } + +. { return yytext[0]; } + +%% diff --git a/jpegxr/qp_parse.y b/jpegxr/qp_parse.y new file mode 100644 index 000000000..9544290bf --- /dev/null +++ b/jpegxr/qp_parse.y @@ -0,0 +1,308 @@ + +%{ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: qp_parse.y,v 1.8 2008/03/20 18:10:29 steve Exp $") +#else +#ident "$Id: qp_parse.y,v 1.8 2008/03/20 18:10:29 steve Exp $" +#endif + +# include "jpegxr.h" +# include <stdlib.h> +# include <assert.h> +# define YYINCLUDED_STDLIB_H + + extern int qp_lex(void); + static void yyerror(const char*txt); + + static int errors = 0; + + /* Parse state variables. */ + + /* The image we are getting QP values for */ + static jxr_image_t cur_image; + /* Some characteristics of that image. */ + static unsigned tile_columns; + static unsigned tile_rows; + + /* The array of all the tiles to be calculated. */ + static struct jxr_tile_qp* tile_qp = 0; + + /* Tile currently in progress. */ + static unsigned cur_tilex = 0; + static unsigned cur_tiley = 0; + static struct jxr_tile_qp*cur_tile = 0; + + static unsigned mb_in_tile = 0; + + static unsigned cur_channel = 0; + +%} + +%union { + unsigned number; + + struct { + unsigned char*data; + unsigned count; + } map_list; + + struct sixteen_nums { + unsigned char num; + unsigned char qp[16]; + } qp_set; +} + + + /* Keywords */ +%token K_DC K_CHANNEL K_HP K_INDEPENDENT K_LP K_SEPARATE K_TILE K_UNIFORM + /* Other tokens */ +%token <number> NUMBER + +%type <qp_set> lphp_qp_list +%type <map_list> map_list + +%% + +start : tile_list ; + +tile_list + : tile_list tile + | tile + ; + + /* Describe the QP for a specific tile in the image, with the tile + position given in tile-column/tile-row coordinates. */ +tile + : K_TILE '(' NUMBER ',' NUMBER ')' + { cur_tilex = $3, + cur_tiley = $5; + assert(cur_tilex < tile_columns); + assert(cur_tiley < tile_rows); + cur_tile = tile_qp + cur_tiley*tile_columns + cur_tilex; + mb_in_tile = jxr_get_TILE_WIDTH(cur_image, cur_tilex) * jxr_get_TILE_HEIGHT(cur_image, cur_tiley); + } + '{' tile_comp_mode tile_body '}' + { /* Check the sanity of the calculated tile. */ + int idx; + switch (cur_tile->component_mode) { + case JXR_CM_UNIFORM: + break; + case JXR_CM_SEPARATE: + if (cur_tile->channel[0].num_lp != cur_tile->channel[1].num_lp) { + fprintf(stderr, "channel-0 and channel-1 LP counts don't match\n"); + errors += 1; + } + if (cur_tile->channel[0].num_hp != cur_tile->channel[1].num_hp) { + fprintf(stderr, "channel-0 and channel-1 HP counts don't match\n"); + errors += 1; + } + if (jxr_get_IMAGE_CHANNELS(cur_image) == 1) { + fprintf(stderr, "Gray (1-channel) tiles must be channel mode UNIFORM\n"); + errors += 1; + } + break; + case JXR_CM_INDEPENDENT: + for (idx = 1 ; idx < jxr_get_IMAGE_CHANNELS(cur_image) ; idx += 1) { + if (cur_tile->channel[0].num_lp != cur_tile->channel[idx].num_lp) { + fprintf(stderr, "channel-0 and channel-%d LP counts don't match\n", idx); + errors += 1; + } + if (cur_tile->channel[0].num_hp != cur_tile->channel[idx].num_hp) { + fprintf(stderr, "channel-0 and channel-%d HP counts don't match\n", idx); + errors += 1; + } + } + if (jxr_get_IMAGE_CHANNELS(cur_image) == 1) { + fprintf(stderr, "Gray (1-channel) tiles must be channel mode UNIFORM\n"); + errors += 1; + } + break; + case JXR_CM_Reserved: + assert(0); + break; + } + } + ; + +tile_comp_mode + : K_UNIFORM { cur_tile->component_mode = JXR_CM_UNIFORM; } + | K_SEPARATE { cur_tile->component_mode = JXR_CM_SEPARATE; } + | K_INDEPENDENT { cur_tile->component_mode = JXR_CM_INDEPENDENT; } + ; + +tile_body + : tile_body tile_item + | tile_item + ; + +tile_item + : K_CHANNEL NUMBER + { cur_channel = $2; + assert(cur_channel < 16); + cur_tile->channel[cur_channel].num_lp = 0; + cur_tile->channel[cur_channel].num_hp = 0; + } + '{' channel_body '}' + + | K_LP '[' map_list ']' + { cur_tile->lp_map = $3.data; + if ($3.count != mb_in_tile) { + errors += 1; + fprintf(stderr, "parse qp: In tile %u,%u, expected %u lp blocks, got %u.\n", + cur_tilex, cur_tiley, mb_in_tile, $3.count); + } + } + + | K_HP '[' map_list ']' + { cur_tile->hp_map = $3.data; + if ($3.count != mb_in_tile) { + errors += 1; + fprintf(stderr, "parse qp: In tile %u,%u, expected %u lp blocks, got %u.\n", + cur_tilex, cur_tiley, mb_in_tile, $3.count); + } + } + ; + +channel_body + : channel_body channel_item + | channel_item + ; + +channel_item + : K_DC '{' NUMBER '}' + { cur_tile->channel[cur_channel].dc_qp = $3; } + + | K_LP '{' lphp_qp_list '}' + { cur_tile->channel[cur_channel].num_lp = $3.num; + int idx; + for (idx = 0 ; idx < $3.num ; idx += 1) + cur_tile->channel[cur_channel].lp_qp[idx] = $3.qp[idx]; + } + + | K_HP '{' lphp_qp_list '}' + { cur_tile->channel[cur_channel].num_hp = $3.num; + int idx; + for (idx = 0 ; idx < $3.num ; idx += 1) + cur_tile->channel[cur_channel].hp_qp[idx] = $3.qp[idx]; + } + + ; + +lphp_qp_list + : lphp_qp_list optional_comma NUMBER + { unsigned cnt = $1.num; + if (cnt >= 16) { + fprintf(stderr, "Too many (>16) QP values in QP list.\n"); + errors += 1; + } else { + assert(cnt < 16); + $1.qp[cnt] = $3; + $1.num += 1; + } + $$ = $1; + } + | NUMBER + { $$.num = 1; + $$.qp[0] = $1; + } + ; + +optional_comma: ',' | ; + +map_list + : map_list NUMBER + { if ($1.count >= mb_in_tile) { + fprintf(stderr, "Too many map items for tile!\n"); + errors += 1; + } else { + $1.data[$1.count++] = $2; + } + $$ = $1; + } + + | NUMBER + { assert(mb_in_tile >= 1); + $$.data = (unsigned char*)calloc(mb_in_tile, 1); + $$.count = 1; + $$.data[0] = $1; + } + ; + +%% + +extern void qp_restart(FILE*fd); + +int qp_parse_file(FILE*fd, jxr_image_t image) +{ + cur_image = image; + tile_columns = jxr_get_TILE_COLUMNS(image); + tile_rows = jxr_get_TILE_ROWS(image); + + tile_qp = (struct jxr_tile_qp *) calloc(tile_columns*tile_rows, sizeof(*tile_qp)); + assert(tile_qp); + +#if defined(DETAILED_DEBUG) + printf("qp_parse: tile_columns=%u, tile_rows=%u\n", tile_columns, tile_rows); +#endif + + qp_restart(fd); + yyparse(); + +#if defined(DETAILED_DEBUG) + printf("qp_parse: parse done with %u errors\n", errors); +#endif + + if (errors) return -1; + + jxr_set_QP_DISTRIBUTED(image, tile_qp); + return 0; +} + + + +static void yyerror(const char*txt) +{ + fprintf(stderr, "parsing QP file: %s\n", txt); + errors += 1; +} diff --git a/jpegxr/r_parse.c b/jpegxr/r_parse.c new file mode 100644 index 000000000..2b4df846e --- /dev/null +++ b/jpegxr/r_parse.c @@ -0,0 +1,3378 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: r_parse.c,v 1.39 2008/03/24 18:06:56 steve Exp $") +#else +#ident "$Id: r_parse.c,v 1.39 2008/03/24 18:06:56 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <memory.h> +# include <assert.h> + +static int r_image_header(jxr_image_t image, struct rbitstream*str); +static int r_image_plane_header(jxr_image_t image, struct rbitstream*str, int alpha); +static int r_INDEX_TABLE(jxr_image_t image, struct rbitstream*str); +static int64_t r_PROFILE_LEVEL_INFO(jxr_image_t image, struct rbitstream*str); +static int r_TILE(jxr_image_t image, struct rbitstream*str); + +static int r_HP_QP(jxr_image_t image, struct rbitstream*str); + +static int32_t r_DEC_DC(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + int model_bits, int chroma_flag, int is_dc_ch); +static uint32_t r_DECODE_ABS_LEVEL(jxr_image_t image, struct rbitstream*str, + int band, int chroma_flag); +static int r_DECODE_FIRST_INDEX(jxr_image_t image, struct rbitstream*str, + int chroma_flag, int band); +static int r_DECODE_INDEX(jxr_image_t image, struct rbitstream*str, + int location, int chroma_flag, int band, int context); +static int r_DECODE_RUN(jxr_image_t image, struct rbitstream*str, int max_run); +static int r_REFINE_LP(struct rbitstream*str, int coeff, int model_bits); +static int r_REFINE_CBP(struct rbitstream*str, int cbp); +static void r_PredCBP(jxr_image_t image, int*diff_cbp, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +static int r_DECODE_BLOCK_ADAPTIVE(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned mx, + int cbp_flag, int chroma_flag, + int channel, int block, int mbhp_pred_mode, + unsigned model_bits); +static void r_BLOCK_FLEXBITS(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + unsigned chan, unsigned bl, unsigned model_bits); +static int r_calculate_mbhp_mode(jxr_image_t image, int tx, int mx); +static int get_is_dc_yuv(struct rbitstream*str); +static int dec_cbp_yuv_lp1(jxr_image_t image, struct rbitstream*str); +static int dec_abslevel_index(jxr_image_t image, struct rbitstream*str, int vlc_select); +static int get_num_cbp(struct rbitstream*str, struct adaptive_vlc_s*vlc); +static int get_num_blkcbp(jxr_image_t image, struct rbitstream*str, struct adaptive_vlc_s*vlc); +static int get_value_012(struct rbitstream*str); +static int get_num_ch_blk(struct rbitstream*str); + + + +int jxr_read_image_bitstream(jxr_image_t image, FILE*fd) +{ + int rc; + struct rbitstream bits; + uint8_t input_profile; + uint8_t input_level; + int64_t subsequent_bytes; + + _jxr_rbitstream_initialize(&bits, fd); + + /* Image header for the image overall */ + rc = r_image_header(image, &bits); + if (rc < 0) return rc; + + /* Image plane. */ + rc = r_image_plane_header(image, &bits, 0); + if (rc < 0) return rc; + + /* Make image structures that need header details. */ + _jxr_make_mbstore(image, 0); + + /* If there is an alpa channel, process the image place header + for it. */ + if (ALPHACHANNEL_FLAG(image)) { + int ch; + + image->alpha = jxr_create_input(); + *image->alpha = *image; + + rc = r_image_plane_header(image->alpha, &bits, 1); + if (rc < 0) return rc; + + for(ch = 0; ch < image->num_channels; ch ++) + memset(&image->alpha->strip[ch], 0, sizeof(image->alpha->strip[ch])); + + _jxr_make_mbstore(image->alpha, 0); + image->alpha->primary = 0; + } + + rc = r_INDEX_TABLE(image, &bits); + + /* Store command line input values for later comparison */ + input_profile = image->profile_idc; + input_level = image->level_idc; + + /* inferred value as per Appendix B */ + image->profile_idc = 111; + image->level_idc = 255; + + subsequent_bytes = _jxr_rbitstream_intVLW(&bits); + DEBUG(" Subsequent bytes with %ld bytes\n", subsequent_bytes); + if (subsequent_bytes > 0) { + int64_t read_bytes = r_PROFILE_LEVEL_INFO(image,&bits); + int64_t additional_bytes = subsequent_bytes - read_bytes; + int64_t idx; + for (idx = 0 ; idx < additional_bytes ; idx += 1) { + _jxr_rbitstream_uint8(&bits); /* RESERVED_A_BYTE */ + } + } + + assert(image->profile_idc <= input_profile); + assert(image->level_idc <= input_level); + + rc = jxr_test_PROFILE_IDC(image, 1); + rc = jxr_test_LEVEL_IDC(image, 1); + + DEBUG("MARK HERE as the tile base. bitpos=%zu\n", _jxr_rbitstream_bitpos(&bits)); + _jxr_rbitstream_mark(&bits); + + /* The image data is in a TILE element even if there is no + tiling. No tiling just means 1 big tile. */ + rc = r_TILE(image, &bits); + + DEBUG("Consumed %zu bytes of the bitstream\n", bits.read_count); + +#ifdef VERIFY_16BIT + if(image->lwf_test == 0) + DEBUG("Meet conditions for LONG_WORD_FLAG == 0!"); + else { + DEBUG("Don't meet conditions for LONG_WORD_FLAG == 0!"); + if (LONG_WORD_FLAG(image) == 0) + return JXR_EC_BADFORMAT; + } +#endif + + return rc; +} + +int jxr_test_LONG_WORD_FLAG(jxr_image_t image, int flag) +{ +#ifdef VERIFY_16BIT + if (flag == 0 && image->lwf_test != 0) { + DEBUG("Using LONG_WORD_FLAG decoder but did not meet LONG_WORD_FLAG == 0 conditions!"); + return JXR_EC_BADFORMAT; + } + else +#endif + return 0; + +} + +#if defined(DETAILED_DEBUG) +static const char*bitdepth_names[16] = { + "BD1WHITE1", "BD8", "BD16", "BD16S", + "BD16F", "RESERVED5", "BD32S", "BD32F", + "BD5", "BD10", "BD565", "RESERVED11" + "RESERVED12", "RESERVED12", "RESERVED12","BD1BLACK1" +}; + +#endif + +static int r_image_header(jxr_image_t image, struct rbitstream*str) +{ + const char GDI_SIG[] = "WMPHOTO\0"; + unsigned idx; + + unsigned version_info, version_sub_info; + unsigned hei_sum; + unsigned wid_sum = 0; + + /* Read and test the GDI_SIGNATURE magic number */ + for (idx = 0 ; idx < 8 ; idx += 1) { + uint8_t byte = _jxr_rbitstream_uint8(str); + if (byte != GDI_SIG[idx]) { + return JXR_EC_BADMAGIC; + } + } + + DEBUG("Got magic number.\n"); + DEBUG("START IMAGE_HEADER (bitpos=%zu)\n", _jxr_rbitstream_bitpos(str)); + + /* Get the version info */ + version_info = _jxr_rbitstream_uint4(str); + + image->disableTileOverlapFlag = _jxr_rbitstream_uint1(str); + DEBUG(" disableTileOverlapFlag: %d\n", image->disableTileOverlapFlag); + + version_sub_info = _jxr_rbitstream_uint3(str); + DEBUG(" Version: %u.%u\n", version_info, version_sub_info); + + /* Read some of the flags as a group. There are a bunch of + small flag values together here, so it is economical to + just collect them all at once. */ + image->header_flags1 = _jxr_rbitstream_uint8(str); + image->header_flags2 = _jxr_rbitstream_uint8(str); + image->header_flags_fmt = _jxr_rbitstream_uint8(str); + + /* check container conformance */ + if (image->container_current_separate_alpha == 0) + assert(SOURCE_CLR_FMT(image) == image->container_color); + assert(((image->header_flags_fmt & 0x0f) == 15 ? 0 : (image->header_flags_fmt & 0x0f)) == image->container_bpc); + if (image->container_separate_alpha == 0) + assert(image->container_alpha == ALPHACHANNEL_FLAG(image)); + else + assert(ALPHACHANNEL_FLAG(image) == 0); + + DEBUG(" Flags group1=0x%02x\n", image->header_flags1); + DEBUG(" Flags group2=0x%02x\n", image->header_flags2); + DEBUG(" OUTPUT_CLR_FMT=%d\n", SOURCE_CLR_FMT(image)); + DEBUG(" OUTPUT_BITDEPTH=%d (%s)\n", SOURCE_BITDEPTH(image), bitdepth_names[SOURCE_BITDEPTH(image)]); + + /* Get the configured image dimensions. */ + if (SHORT_HEADER_FLAG(image)) { + DEBUG(" SHORT_HEADER_FLAG=true\n"); + image->width1 = _jxr_rbitstream_uint16(str); + image->height1 = _jxr_rbitstream_uint16(str); + } else { + DEBUG(" SHORT_HEADER_FLAG=false\n"); + image->width1 = _jxr_rbitstream_uint32(str); + image->height1 = _jxr_rbitstream_uint32(str); + } + + /* check container conformance */ + assert(image->width1 + 1 == image->container_width); + assert(image->height1 + 1 == image->container_height); + + DEBUG(" Image dimensions: %u x %u\n", image->width1+1, image->height1+1); + + assert(image->tile_row_height == 0); + assert(image->tile_column_width == 0); + assert(image->tile_column_position == 0); + if (jxr_get_TILING_FLAG(image)) { + image->tile_columns = _jxr_rbitstream_uint12(str) + 1; + image->tile_rows = _jxr_rbitstream_uint12(str) + 1; + DEBUG(" TILING %u columns, %u rows (bitpos=%zu)\n", + image->tile_columns, image->tile_rows, + _jxr_rbitstream_bitpos(str)); + + + } else { + /* NO TILING means that the entire image is exactly 1 + tile. Configure the single tile to be the size of the + entire image. */ + image->tile_columns = 1; + image->tile_rows = 1; + DEBUG(" NO TILING\n"); + } + + /* Collect the widths of the tile columns. All but the last + column width are encoded in the input stream. The last is + inferred from the accumulated width of the columns and the + total width of the image. If there is no tiling, then there + is exactly 1 tile, and this degenerates to the width of the + image. + + The heights of tile rows is processed exactly the same way. */ + + image->tile_column_width = (unsigned*)calloc(2*image->tile_columns, sizeof(unsigned)); + image->tile_column_position = image->tile_column_width + image->tile_columns; + image->tile_row_height = (unsigned*)calloc(2*image->tile_rows, sizeof(unsigned)); + image->tile_row_position = image->tile_row_height + image->tile_rows; + + wid_sum = 0; + if (SHORT_HEADER_FLAG(image)) { + for (idx = 0 ; idx < image->tile_columns-1 ; idx += 1) { + image->tile_column_width[idx] = _jxr_rbitstream_uint8(str); + image->tile_column_position[idx] = wid_sum; + wid_sum += image->tile_column_width[idx]; + } + + } else { + for (idx = 0 ; idx < image->tile_columns-1 ; idx += 1) { + image->tile_column_width[idx] = _jxr_rbitstream_uint16(str); + image->tile_column_position[idx] = wid_sum; + wid_sum += image->tile_column_width[idx]; + } + } + /* calculate final tile width after windowing parameters are found */ + + hei_sum = 0; + if (SHORT_HEADER_FLAG(image)) { + for (idx = 0 ; idx < image->tile_rows-1 ; idx += 1) { + image->tile_row_height[idx] = _jxr_rbitstream_uint8(str); + image->tile_row_position[idx] = hei_sum; + hei_sum += image->tile_row_height[idx]; + } + + } else { + for (idx = 0 ; idx < image->tile_rows-1 ; idx += 1) { + image->tile_row_height[idx] = _jxr_rbitstream_uint16(str); + image->tile_row_position[idx] = hei_sum; + hei_sum += image->tile_row_height[idx]; + } + } + /* calculate final tile height after windowing parameters are found */ + + if (WINDOWING_FLAG(image)) { + image->window_extra_top = _jxr_rbitstream_uint6(str); + image->window_extra_left = _jxr_rbitstream_uint6(str); + image->window_extra_bottom = _jxr_rbitstream_uint6(str); + image->window_extra_right = _jxr_rbitstream_uint6(str); + } else { + image->window_extra_top = 0; + image->window_extra_left = 0; + if ((image->height1 + 1) % 16 == 0) + image->window_extra_bottom = 0; + else + image->window_extra_bottom = 16 - ((image->height1 + 1) % 16); + if ((image->width1 + 1) % 16 == 0) + image->window_extra_right = 0; + else + image->window_extra_right = 16 - ((image->width1 + 1) % 16); + DEBUG(" NO WINDOWING\n"); + } + image->extended_width = image->width1 + 1 + image->window_extra_left + image->window_extra_right; + image->extended_height = image->height1 + 1 + image->window_extra_top + image->window_extra_bottom; + + image->lwf_test = 0; + + image->tile_column_width[image->tile_columns-1] = (image->extended_width >> 4)-wid_sum; + image->tile_column_position[image->tile_columns-1] = wid_sum; + + image->tile_row_height[image->tile_rows-1] = (image->extended_height >> 4)-hei_sum; + image->tile_row_position[image->tile_rows-1] = hei_sum; + +#if defined(DETAILED_DEBUG) + DEBUG(" Tile widths:"); + for (idx = 0 ; idx < image->tile_columns ; idx += 1) + DEBUG(" %u", image->tile_column_width[idx]); + DEBUG("\n"); + DEBUG(" Tile heights:"); + for (idx = 0 ; idx < image->tile_rows ; idx += 1) + DEBUG(" %u", image->tile_row_height[idx]); + DEBUG("\n"); +#endif + + /* Perform some checks */ + assert(image->extended_width % 16 == 0); + if ((OVERLAP_INFO(image) >= 2) && (image->use_clr_fmt == 1 || image->use_clr_fmt == 2)) + { + assert(image->extended_width >= 32); + if (image->disableTileOverlapFlag) { + unsigned int idx = 0; + for (idx = 0; idx < image->tile_columns ; idx += 1) + assert(image->tile_column_width[idx] > 1); + } + } + assert(image->extended_height % 16 == 0); + + DEBUG("END IMAGE_HEADER (%zu bytes)\n", str->read_count); + return 0; +} + +static int r_image_plane_header(jxr_image_t image, struct rbitstream*str, int alpha) +{ + size_t save_count = str->read_count; + uint16_t num_components; + + DEBUG("START IMAGE_PLANE_HEADER (bitpos=%zu)\n", _jxr_rbitstream_bitpos(str)); + + /* NOTE: The "use_clr_fmt" is the encoded color format, and is + not necessarily the same as the image color format + signaled in the image header. All of our processing of an + image plane is handled using the "use_clr_fmt", and only + transformed to the image color format on the way out. */ + + image->use_clr_fmt = _jxr_rbitstream_uint3(str); /* INTERNAL_CLR_FMT */ + image->scaled_flag = _jxr_rbitstream_uint1(str); /* NO_SCALED_FLAG */ + image->bands_present = _jxr_rbitstream_uint4(str); /* BANDS_PRESENT */ + + /* for alpha image plane, INTERNAL_CLR_FMT == YONLY */ + if (alpha) + assert(image->use_clr_fmt == 0); + + DEBUG(" INTERNAL_CLR_FMT = %d\n", image->use_clr_fmt); + DEBUG(" SCALED_FLAG = %s\n", image->scaled_flag? "true" : "false"); + DEBUG(" BANDS_PRESENT = %d\n", image->bands_present); + + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + image->num_channels = 1; + break; + case 1: /* YUV420 */ + _jxr_rbitstream_uint1(str); /* RESERVED_E_BIT */ + image->chroma_centering_x = _jxr_rbitstream_uint3(str); /* CHROMA_CENTERING_X */ + _jxr_rbitstream_uint1(str); /* RESERVED_G_BIT */ + image->chroma_centering_y = _jxr_rbitstream_uint3(str); /* CHROMA_CENTERING_Y */ + image->num_channels = 3; + break; + case 2: /* YUV422 */ + _jxr_rbitstream_uint1(str); /* RESERVED_E_BIT */ + image->chroma_centering_x = _jxr_rbitstream_uint3(str); /* CHROMA_CENTERING_X */ + _jxr_rbitstream_uint4(str); /* RESERVED_H */ + image->chroma_centering_y = 0; + image->num_channels = 3; + break; + case 3: /* YUV444 */ + _jxr_rbitstream_uint4(str); /* RESERVED_F */ + _jxr_rbitstream_uint4(str); /* RESERVED_H */ + image->num_channels = 3; + break; + case 4: /* YUVK */ + image->num_channels = 4; + break; + case 6: /* NCOMPONENT */ + num_components = _jxr_rbitstream_uint4(str); + if (num_components == 0xf) { + image->num_channels = 16 + _jxr_rbitstream_uint12(str); + } + else { + image->num_channels = 1 + num_components; + _jxr_rbitstream_uint4(str); /* RESERVED_H */ + } + break; + case 5: /* RESERVED */ + case 7: /* RESERVED */ + break; + } + + /* + check container conformance - specific for tag based container + this section should be modified when the container is + */ + if (image->container_alpha) { + if (image->container_separate_alpha) { + if (image->container_current_separate_alpha) { + assert(image->num_channels == 1); + assert(image->bands_present == image->container_alpha_band_presence || image->container_alpha_band_presence > 3 || image->container_alpha_band_presence < 0); + } + else { + assert(image->num_channels == image->container_nc - 1); + assert((image->bands_present == image->container_image_band_presence) || (image->container_image_band_presence > 3) || (image->container_image_band_presence < 0)); + } + } + else { + if (alpha) { + assert(image->num_channels == 1); + assert(image->bands_present == image->container_alpha_band_presence || image->container_alpha_band_presence > 3 || image->container_alpha_band_presence < 0); + } + else { + assert(image->num_channels == image->container_nc - 1); + assert(image->bands_present == image->container_image_band_presence || image->container_image_band_presence > 3 || (image->container_image_band_presence < 0)); + } + } + } + else { + assert(image->num_channels == image->container_nc); + assert(image->bands_present == image->container_image_band_presence || image->container_image_band_presence > 3 || (image->container_image_band_presence < 0)); + } + + + switch (SOURCE_BITDEPTH(image)) { + case 0: /* BD1WHITE1 */ + case 1: /* BD8 */ + case 4: /* BD16F */ + case 8: /* BD5 */ + case 9: /* BD10 */ + case 15: /* BD1BLACK1 */ + image->shift_bits = 0; + break; + case 2: /* BD16 */ + case 3: /* BD16S */ + case 6: /* BD32S */ + image->shift_bits = _jxr_rbitstream_uint8(str); /* SHIFT_BITS */ + DEBUG(" SHIFT_BITS = %u\n", image->shift_bits); + break; + case 7: /* BD32F */ + image->len_mantissa = _jxr_rbitstream_uint8(str); /* LEN_MANTISSA */ + image->exp_bias = _jxr_rbitstream_uint8(str); /* EXP_BIAS */ + DEBUG(" LEN_MANTISSA = %u\n", image->len_mantissa); + DEBUG(" EXP_BIAS = %u\n", image->exp_bias); + break; + default: /* RESERVED */ + DEBUG(" XXXX Inexplicable SOURCE_BITDEPTH=%u\n", SOURCE_BITDEPTH(image)); + break; + } + + /* If the stream signals that the DC frames use a uniform + quantization parameter, then collect that parameter + here. In this case, DC quantization parameters elsewhere in + the image are suppressed. Note that per macroblock, there + is only 1 DC value, so only 1 DC QP is needed. */ + image->dc_frame_uniform = _jxr_rbitstream_uint1(str); + DEBUG(" DC_FRAME_UNIFORM = %s\n", image->dc_frame_uniform?"true":"false"); + if (image->dc_frame_uniform) { + _jxr_r_DC_QP(image, str); + } + + if (image->bands_present != 3 /*DCONLY*/) { + _jxr_rbitstream_uint1(str); /* RESERVED_I_BIT */ + + image->lp_frame_uniform = _jxr_rbitstream_uint1(str); + DEBUG(" LP_FRAME_UNIFORM = %s\n", image->lp_frame_uniform?"true":"false"); + if (image->lp_frame_uniform) { + image->num_lp_qps = 1; + _jxr_r_LP_QP(image, str); + } + + if (image->bands_present != 2 /*NOHIGHPASS*/) { + _jxr_rbitstream_uint1(str); /* RESERVED_J_BIT */ + + image->hp_frame_uniform = _jxr_rbitstream_uint1(str); + DEBUG(" HP_FRAME_UNIFORM = %s\n", image->hp_frame_uniform?"true":"false"); + if (image->hp_frame_uniform) { + image->num_hp_qps = 1; + r_HP_QP(image, str); + } + } + + } + + _jxr_rbitstream_syncbyte(str); + DEBUG("END IMAGE_PLANE_HEADER (%zd bytes, bitpos=%zu)\n", + str->read_count - save_count, _jxr_rbitstream_bitpos(str)); + + return 0; +} + +static int get_ch_mode(jxr_image_t image, struct rbitstream*str) +{ + int ch_mode; + if (image->num_channels == 1) { + ch_mode = 0; /* UNIFORM */ + } else { + ch_mode = _jxr_rbitstream_uint2(str); + } + return ch_mode; +} + +int _jxr_r_DC_QP(jxr_image_t image, struct rbitstream*str) +{ + unsigned idx; + + int ch_mode = get_ch_mode(image, str); + DEBUG(" DC_QP CH_MODE=%d ", ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + image->dc_quant_ch[0] = _jxr_rbitstream_uint8(str); + DEBUG(" DC_QUANT UNIFORM =%u", image->dc_quant_ch[0]); + for (idx = 1 ; idx < image->num_channels ; idx += 1) + image->dc_quant_ch[idx] = image->dc_quant_ch[0]; + break; + case 1: /* SEPARATE */ + image->dc_quant_ch[0] = _jxr_rbitstream_uint8(str); + image->dc_quant_ch[1] = _jxr_rbitstream_uint8(str); + image->dc_quant_ch[2] = image->dc_quant_ch[1]; + DEBUG(" DC_QUANT SEPARATE Y=%u, Chr=%u", image->dc_quant_ch[0],image->dc_quant_ch[1]); + break; + case 2: /* INDEPENDENT */ + assert(image->num_channels <= MAX_CHANNELS); + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + image->dc_quant_ch[idx] = _jxr_rbitstream_uint8(str); + DEBUG(" DC_QUANT INDEPENDENT[%d] = %u", idx, image->dc_quant_ch[idx]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + break; + } + DEBUG("\n"); + + return 0; +} + +int _jxr_r_LP_QP(jxr_image_t image, struct rbitstream*str) +{ + unsigned q; + + for (q = 0 ; q < image->num_lp_qps ; q += 1) { + unsigned idx; + int ch_mode = get_ch_mode(image, str); + DEBUG(" LP_QP[%u] CH_MODE=%d LP_QUANT=", q, ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + image->lp_quant_ch[0][q] = _jxr_rbitstream_uint8(str); + DEBUG("%d", image->lp_quant_ch[0][q]); + for (idx = 1 ; idx < image->num_channels ; idx += 1) + image->lp_quant_ch[idx][q] = image->lp_quant_ch[0][q]; + break; + case 1: /* SEPARATE */ + image->lp_quant_ch[0][q] = _jxr_rbitstream_uint8(str); + image->lp_quant_ch[1][q] = _jxr_rbitstream_uint8(str); + DEBUG("SEPARATE Y=%d Chr=%d", image->lp_quant_ch[0][q], image->lp_quant_ch[1][q]); + for (idx = 2 ; idx < image->num_channels ; idx += 1) + image->lp_quant_ch[idx][q] = image->lp_quant_ch[1][q]; + break; + case 2: /* INDEPENDENT */ + DEBUG("INDEPENDENT ="); + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + image->lp_quant_ch[idx][q] = _jxr_rbitstream_uint8(str); + DEBUG(" %d", image->lp_quant_ch[idx][q]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + break; + } + DEBUG("\n"); + } + + return 0; +} + +static int r_HP_QP(jxr_image_t image, struct rbitstream*str) +{ + unsigned q; + + for (q = 0 ; q < image->num_hp_qps ; q += 1) { + unsigned idx; + int ch_mode = get_ch_mode(image, str); + DEBUG("HP_QP[%u] CH_MODE: %d ", q, ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + image->HP_QUANT_Y[q] = _jxr_rbitstream_uint8(str); + DEBUG("UNIFORM %d", image->hp_quant_ch[0][q]); + for (idx = 1 ; idx < image->num_channels ; idx += 1) + image->hp_quant_ch[idx][q] = image->hp_quant_ch[0][q]; + break; + case 1: /* SEPARATE */ + image->HP_QUANT_Y[q] = _jxr_rbitstream_uint8(str); + image->hp_quant_ch[1][q] = _jxr_rbitstream_uint8(str); + DEBUG("SEPARATE Y=%d Chr=%d", image->hp_quant_ch[0][q], image->hp_quant_ch[1][q]); + for (idx = 2 ; idx < image->num_channels ; idx += 1) + image->hp_quant_ch[idx][q] = image->hp_quant_ch[1][q]; + break; + case 2: /* INDEPENDENT */ + DEBUG("INDEPENDENT ="); + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + image->hp_quant_ch[idx][q] = _jxr_rbitstream_uint8(str); + DEBUG(" %d", image->hp_quant_ch[idx][q]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + break; + } + DEBUG(" bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + } + + return 0; +} + +static int r_INDEX_TABLE(jxr_image_t image, struct rbitstream*str) +{ + DEBUG("INDEX_TABLE START bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + if (INDEXTABLE_PRESENT_FLAG(image)) { + int num_index_table_entries; + int idx; + + uint8_t s0 = _jxr_rbitstream_uint8(str); + uint8_t s1 = _jxr_rbitstream_uint8(str); + DEBUG(" STARTCODE = 0x%02x 0x%02x\n", s0, s1); + if (s0 != 0x00 || s1 != 0x01) + return JXR_EC_ERROR; + + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) == 0 /* SPATIALMODE */) { + num_index_table_entries = image->tile_rows * image->tile_columns; + + } else { + num_index_table_entries = image->tile_rows * image->tile_columns; + switch (image->bands_present) { + case 4: /* ISOLATED */ + num_index_table_entries *= 4; + break; + default: + num_index_table_entries *= 4 - image->bands_present; + break; + } + } + image->tile_index_table_length = num_index_table_entries; + + assert(image->tile_index_table == 0); + image->tile_index_table = (int64_t*)calloc(num_index_table_entries, sizeof(int64_t)); + DEBUG(" INDEX_TABLE has %d table entries\n", num_index_table_entries); + + for (idx = 0 ; idx < num_index_table_entries ; idx += 1) { + int64_t off = _jxr_rbitstream_intVLW(str); + DEBUG(" ... %ld\n", off); + image->tile_index_table[idx] = off; + } + } + + DEBUG("INTEX_TABLE DONE bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + return 0; +} + +static int64_t r_PROFILE_LEVEL_INFO(jxr_image_t image, struct rbitstream*str) +{ + int64_t num_bytes = 0; + uint16_t reserved_l; + unsigned last_flag; + + int64_t last; + for (last = 0 ; last == 0 ; last = last_flag) { + image->profile_idc = _jxr_rbitstream_uint8(str); /* PROFILE_IDC */ + DEBUG(" Profile signaled in file %ld bytes\n", image->profile_idc); + image->level_idc = _jxr_rbitstream_uint8(str); /* LEVEL_IDC */ + DEBUG(" Level signaled in file %ld bytes\n", image->level_idc); + reserved_l = _jxr_rbitstream_uint15(str); /* RESERVED_L */ + last_flag = _jxr_rbitstream_uint1(str); /* LAST_FLAG */ + num_bytes += 4; + } + + return num_bytes; +} + +static int r_TILE(jxr_image_t image, struct rbitstream*str) +{ + int rc = 0; + image->tile_quant = (struct jxr_tile_qp *) calloc(image->tile_columns*image->tile_rows, sizeof(*(image->tile_quant))); + assert(image->tile_quant); + + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) == 0 /* SPATIALMODE */) { + + unsigned tx, ty, tt=0; + for (ty = 0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + if(INDEXTABLE_PRESENT_FLAG(image)) + { + _jxr_rbitstream_seek(str, image->tile_index_table[tt]); + tt++; + } + rc = _jxr_r_TILE_SPATIAL(image, str, tx, ty); + if (rc < 0) goto RET; + } + } + } else { /* FREQUENCYMODE */ + + unsigned tx, ty, tt; + int num_bands = 0; + switch (image->bands_present) { + case 0: /* ALL */ + num_bands = 4; + break; + case 1: /* NOFLEXBITS */ + num_bands = 3; + break; + case 2: /* NOHIGHPASS */ + num_bands = 2; + break; + case 3: /* DCONLY */ + num_bands = 1; + break; + case 4: /* ISOLATED */ + break; + } + + for (ty = 0, tt=0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + _jxr_rbitstream_seek(str, image->tile_index_table[tt*num_bands+0]); + rc = _jxr_r_TILE_DC(image, str, tx, ty); + if (rc < 0) goto RET; + tt += 1; + } + } + + if (num_bands > 1) { + for (ty = 0, tt=0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + _jxr_rbitstream_seek(str, image->tile_index_table[tt*num_bands+1]); + rc = _jxr_r_TILE_LP(image, str, tx, ty); + if (rc < 0) goto RET; + tt += 1; + } + } + } + + if (num_bands > 2) { + for (ty = 0, tt=0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + _jxr_rbitstream_seek(str, image->tile_index_table[tt*num_bands+2]); + rc = _jxr_r_TILE_HP(image, str, tx, ty); + if (rc < 0) goto RET; + tt += 1; + } + } + } + + if (num_bands > 3) { + for (ty = 0, tt=0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + int64_t off = image->tile_index_table[tt*num_bands+3]; + if (off >= 0) { + _jxr_rbitstream_seek(str, off); + rc = _jxr_r_TILE_FLEXBITS(image, str, tx, ty); + if (rc < 0) goto RET; + } else { + _jxr_r_TILE_FLEXBITS_ESCAPE(image, tx, ty); + } + tt += 1; + } + } + } + + _jxr_frequency_mode_render(image); + } + +RET: + free(image->tile_quant); + return rc; +} + +void _jxr_r_TILE_HEADER_DC(jxr_image_t image, struct rbitstream*str, + int alpha_flag, unsigned tx, unsigned ty) +{ + DEBUG(" TILE_HEADER_DC START bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + if (image->dc_frame_uniform == 0) { + DEBUG(" TILE_HEADER_DC: parse non-uniform DC_QP\n"); + _jxr_r_DC_QP(image, str); + memcpy(image->tile_quant[ty*(image->tile_columns) + tx ].dc_quant_ch, image->dc_quant_ch, MAX_CHANNELS); + } +} + +void _jxr_r_TILE_HEADER_LOWPASS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty) +{ + DEBUG(" TILE_HEADER_LOWPASS START bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + if (image->lp_frame_uniform == 0) { + image->lp_use_dc_qp = _jxr_rbitstream_uint1(str); + DEBUG(" TILE_HEADER_LP: parse non-uniform LP_QP: USE_DC_QP=%u\n", + image->lp_use_dc_qp); + if (image->lp_use_dc_qp == 0) { + image->num_lp_qps = _jxr_rbitstream_uint4(str) + 1; + DEBUG(" TILE_HEADER_LP: NUM_LP_QPS = %d\n", image->num_lp_qps); + _jxr_r_LP_QP(image, str); + memcpy(image->tile_quant[ty*(image->tile_columns) + tx].lp_quant_ch, image->lp_quant_ch, MAX_CHANNELS*MAX_LP_QPS); + } + else + { + /* Use the same quantization index as the dc band (the dc quantization step size could be different for each tile, so store it */ + int ch; + for(ch = 0; ch < image->num_channels; ch++) + image->tile_quant[ty*(image->tile_columns) + tx].lp_quant_ch[ch][0] = image->dc_quant_ch[ch]; + } + } +} + + +void _jxr_r_TILE_HEADER_HIGHPASS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty) +{ + if (image->hp_frame_uniform == 0) { + image->hp_use_lp_qp = _jxr_rbitstream_uint1(str); + DEBUG(" TILE_HEADER_HP: parse non-uniform HP_QP: USE_LP_QP=%u\n", + image->hp_use_lp_qp); + + if (image->hp_use_lp_qp == 0) { + image->num_hp_qps = _jxr_rbitstream_uint4(str) + 1; + DEBUG(" TILE_HEADER_HIGHPASS: NUM_HP_QPS = %d\n", image->num_hp_qps); + r_HP_QP(image, str); + memcpy(image->tile_quant[ty*(image->tile_columns) + tx].hp_quant_ch, image->lp_quant_ch, MAX_CHANNELS*MAX_HP_QPS); + } + else + { + /* Use the same quantization index as the lp band (the lp quantization step size could be different for each tile, so store it */ + int ch; + image->num_hp_qps = image->num_lp_qps; + for(ch = 0; ch < image->num_channels; ch++) { + memcpy(image->hp_quant_ch[ch], image->lp_quant_ch[ch], MAX_LP_QPS); + memcpy(image->tile_quant[ty*(image->tile_columns) + tx].hp_quant_ch[ch], image->lp_quant_ch[ch], MAX_LP_QPS); + } + } + } +} + +unsigned _jxr_DECODE_QP_INDEX(struct rbitstream*str, unsigned index_count) +{ + static const int bits_per_qp_index[] = {0,0,1,1,2,2,3,3, 3,3,4,4,4,4,4,4,4}; + + int nonzero_flag = _jxr_rbitstream_uint1(str); + int bits_count; + + assert(index_count <= 16); + if (nonzero_flag == 0) + return 0; + + bits_count = bits_per_qp_index[index_count]; + /* DECODE_QP_INDEX is onny called if the index count is + greater then 1. Therefore, the bits_count here must be more + then zero. */ + assert(bits_count > 0); + + return _jxr_rbitstream_uintN(str, bits_count)+1; +} + +/* +* Decode the single DC component for the macroblock. +*/ +void _jxr_r_MB_DC(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int lap_mean[2]; + lap_mean[0] = 0; + lap_mean[1] = 0; + + DEBUG(" MB_DC tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_rbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_DC: Initialize Context\n"); + _jxr_InitVLCTable(image, AbsLevelIndDCLum); + _jxr_InitVLCTable(image, AbsLevelIndDCChr); + _jxr_InitializeModelMB(&image->model_dc, 0/*DC*/); + } + + if (image->use_clr_fmt==0 || image->use_clr_fmt==4 || image->use_clr_fmt==6) { + /* clr_fmt == YONLY, YUVK or NCOMPONENT */ + unsigned idx; + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + int m = (idx == 0)? 0 : 1; + int model_bits = image->model_dc.bits[m]; + unsigned is_dc_ch = _jxr_rbitstream_uint1(str); + uint32_t dc_val; + DEBUG(" MB_DC: IS_DC_CH=%u, model_bits=%d\n", + is_dc_ch, model_bits); + if (is_dc_ch) { + lap_mean[m] += 1; + } + dc_val = r_DEC_DC(image, str, tx, ty, mx, my, + model_bits, 0/*chroma_flag==FALSE*/, + is_dc_ch); + + MACROBLK_CUR_DC(image,idx,tx, mx) = dc_val; + DEBUG(" dc_val at t=[%u %u], m=[%u %u] == %d (0x%08x)\n", + tx, ty, mx, my, (int32_t)dc_val, dc_val); + } + } else { + int is_dc_yuv = get_is_dc_yuv(str); + int model_bits_y = image->model_dc.bits[0]; + int model_bits_uv = image->model_dc.bits[1]; + uint32_t dc_val_v; + uint32_t dc_val_u; + uint32_t dc_val_y; + + assert(image->num_channels == 3); + DEBUG(" MB_DC: IS_DC_YUV=0x%x, model_bits[0]=%d, model_bits[1]=%d\n", + is_dc_yuv, model_bits_y, model_bits_uv); + + if (is_dc_yuv&4) + lap_mean[0] += 1; + dc_val_y = r_DEC_DC(image, str, tx, ty, mx, my, + model_bits_y, 0/*chroma_flag==FALSE*/, + is_dc_yuv&4); + + if (is_dc_yuv&2) + lap_mean[1] += 1; + dc_val_u = r_DEC_DC(image, str, tx, ty, mx, my, + model_bits_uv, 1/*chroma_flag==TRUE*/, + is_dc_yuv&2); + + if (is_dc_yuv&1) + lap_mean[1] += 1; + dc_val_v = r_DEC_DC(image, str, tx, ty, mx, my, + model_bits_uv, 1/*chroma_flag==TRUE*/, + is_dc_yuv&1); + + MACROBLK_CUR_DC(image,0,tx, mx) = dc_val_y; + MACROBLK_CUR_DC(image,1,tx, mx) = dc_val_u; + MACROBLK_CUR_DC(image,2,tx, mx) = dc_val_v; + DEBUG(" dc_val at t=[%u %u], m=[%u %u] == %d (0x%08x), %d (0x%08x), %d (0x%08x)\n", + tx, ty, mx, my, (int)dc_val_y, dc_val_y, (int)dc_val_u, dc_val_u, (int)dc_val_v, dc_val_v); + } + + /* */ + DEBUG(" MB_DC: UpdateModelMB: lap_mean={%u %u}\n", lap_mean[0], lap_mean[1]); + _jxr_UpdateModelMB(image, lap_mean, &image->model_dc, 0/*DC*/); + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" MB_DC: Reset Context\n"); + /* AdaptDC */ + _jxr_AdaptVLCTable(image, AbsLevelIndDCLum); + _jxr_AdaptVLCTable(image, AbsLevelIndDCChr); + } + DEBUG(" MB_DC DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); +} + +/* +* When the LP value is input from the stream, it is delivered into +* the target array based on a scan order. The "lopass_scanorder" +* array maps the list of LP values (actually the position in the +* list) to the location in the scan. Thus the scan order places the +* value into the lpinput array. +* +* A property of the lpinput is that it is sparse. The adpative scan +* order tries to adapt the scan order so that the most frequent value +* is pressed to the beginning of the input stream. It does this by +* counting the arrival of each value, and bubbling frequent values +* forward. +* +* Note in the code below that the "i" value ranges from 1-16 but the +* tables are numbered from 0-15. Thus "i-1" is used to index tables. +* +* Note that the scanorder is adapted while we go, but the only +* adjustment is to swap the current position with the previous. Thus, +* it is not possible to effect the current pass with the adaptation. +*/ +static void AdaptiveLPScan(jxr_image_t image, int lpinput_n[], int i, int value) +{ + int k; + assert(i > 0); + k = image->lopass_scanorder[i-1]; + lpinput_n[k] = value; + image->lopass_scantotals[i-1] += 1; + if (i>1 && image->lopass_scantotals[i-1] > image->lopass_scantotals[i-2]) { + SWAP(image->lopass_scantotals[i-1], image->lopass_scantotals[i-2]); + SWAP(image->lopass_scanorder[i-1], image->lopass_scanorder[i-2]); + } +} + +void _jxr_r_MB_LP(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + static const int transpose420[4] = {0, 2, + 1, 3 }; + static const int transpose422[8] = {0, 2, 1, 3, 4, 6, 5, 7}; + int LPInput[8][16]; + int idx; + int model_bits; + int lap_mean[2]; + int ndx; + int full_planes; + int cbplp; + + for (idx = 0 ; idx < 8 ; idx += 1) { + int k; + for (k = 0 ; k < 16 ; k += 1) + LPInput[idx][k] = 0; + } + + lap_mean[0] = 0; + lap_mean[1] = 0; + + DEBUG(" MB_LP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_rbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" Init contexts\n"); + _jxr_InitializeCountCBPLP(image); + _jxr_InitLPVLC(image); + _jxr_InitializeAdaptiveScanLP(image); + _jxr_InitializeModelMB(&image->model_lp, 1/*LP*/); + } + + if (_jxr_ResetTotals(image, mx)) { + _jxr_ResetTotalsAdaptiveScanLP(image); + } + + full_planes = image->num_channels; + if (image->use_clr_fmt==2 || image->use_clr_fmt==1) + full_planes = 2; + + /* The CBPLP signals whether any non-zero coefficients are + present in the LP band for this macroblock. It is a bitmask + with a bit for each channel. So for example, YONLY, which + has 1 channel, has a 1-bit cbplp. */ + + cbplp = 0; + /* if CLR_FMT is YUV420, YUV422 or YUV444... */ + if (image->use_clr_fmt==1 || image->use_clr_fmt==2 || image->use_clr_fmt==3) { + int max = full_planes * 4 - 5; + + DEBUG(" MB_LP: Calculate YUV CBP using CountZeroCBPLP=%d, CountMaxCBPLP=%d bitpos=%zu\n", + image->count_zero_CBPLP, image->count_max_CBPLP, _jxr_rbitstream_bitpos(str)); + + if (image->count_zero_CBPLP <= 0 || image->count_max_CBPLP < 0) { + int cbp_yuv_lp1 = dec_cbp_yuv_lp1(image, str); + if (image->count_max_CBPLP < image->count_zero_CBPLP) + cbplp = max - cbp_yuv_lp1; + else + cbplp = cbp_yuv_lp1; + } else { + uint32_t cbp_yuv_lp2 = _jxr_rbitstream_uintN(str, full_planes); + cbplp = cbp_yuv_lp2; + } + _jxr_UpdateCountCBPLP(image, cbplp, max); + + } else { + int idx; + cbplp = 0; + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + int cbp_ch_lp = _jxr_rbitstream_uint1(str); + cbplp |= cbp_ch_lp << idx; + } + } + + DEBUG(" MB_LP: cbplp = 0x%x (full_planes=%u)\n", cbplp, full_planes); + + for (ndx = 0 ; ndx < full_planes ; ndx += 1) { + int idx; + const int chroma_flag = ndx>0? 1 : 0; + int num_nonzero = 0; + + DEBUG(" MB_LP: process full_plane %u, CBPLP for plane=%d, bitpos=%zu\n", + ndx, (cbplp>>ndx)&1, _jxr_rbitstream_bitpos(str)); + if ((cbplp>>ndx) & 1) { + /* If the CBPLP bit is set for this plane, then we + have parsing to do. Decode the (15) coeffs and + arrange them for use in the MB. */ + int RLCoeffs[32] = {0}; + int location = 1; + for (idx = 0 ; idx < 32 ; idx += 1) + RLCoeffs[idx] = 0; + + /* if CLR_FMT is YUV420 or YUV422 */ + if (image->use_clr_fmt==1/*YUV420*/ && chroma_flag) + location = 10; + if (image->use_clr_fmt==2/*YUV422*/ && chroma_flag) + location = 2; + + num_nonzero = r_DECODE_BLOCK(image, str, + chroma_flag, RLCoeffs, 1/*LP*/, location); + DEBUG(" : num_nonzero = %d\n", num_nonzero); + assert(num_nonzero <= 16); + + if ((image->use_clr_fmt==1 || image->use_clr_fmt==2) && chroma_flag) { + static const int remap_arr[] = {4, 1, 2, 3, 5, 6, 7}; + int temp[14]; + int idx; + int k, i; + int count_chr; + int remap_off; + for (idx = 0 ; idx < 14 ; idx += 1) + temp[idx] = 0; + + remap_off = 0; + if (image->use_clr_fmt==1/*YUV420*/) + remap_off = 1; + + count_chr = 14; + if (image->use_clr_fmt==1/*YUV420*/) + count_chr = 6; + + i = 0; + for (k = 0; k < num_nonzero; k+=1) { + i += RLCoeffs[k*2+0]; + temp[i] = RLCoeffs[k*2+1]; + i += 1; + } + for (k = 0; k < count_chr; k+=1) { + int remap = remap_arr[(k>>1) + remap_off]; + int plane = (k&1) + 1; + if (image->use_clr_fmt==1) + remap = transpose420[remap]; + if (image->use_clr_fmt==2) + remap = transpose422[remap]; + LPInput[plane][remap] = temp[k]; + } +#if defined(DEBUG) + { + int k; + DEBUG(" RLCoeffs[ndx=%d] ==", ndx); + for (k = 0 ; k<(num_nonzero*2); k+=2) { + DEBUG(" %d/0x%x", RLCoeffs[k+0], RLCoeffs[k+1]); + } + DEBUG("\n"); + DEBUG(" temp =="); + for (k = 0 ; k<14; k+=1) { + DEBUG(" 0x%x", temp[k]); + } + DEBUG("\n"); + } +#endif + } else { + /* "i" is the current position in the LP + array. It is adjusted based in the run + each time around. This implines that the + run value is the number of 0 elements in + the LP array between non-zero values. */ + int k, i = 1; + for (k = 0; k < num_nonzero; k+=1) { + i += RLCoeffs[k*2]; + AdaptiveLPScan(image, LPInput[ndx], i, RLCoeffs[k*2+1]); + i += 1; + } + } + } + +#if defined(DEBUG) + if (image->use_clr_fmt == 2/*YUV422*/) { + int k; + DEBUG(" lp val[ndx=%d] before refine ==", ndx); + for (k = 1 ; k<8; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + } + DEBUG("\n"); + + } else if (image->use_clr_fmt == 1/*YUV420*/) { + int k; + DEBUG(" lp val[ndx=%d] before refine ==", ndx); + for (k = 1 ; k<4; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + } + DEBUG("\n"); + + } else { + int k; + DEBUG(" lp val[ndx=%d] before refine ==", ndx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", LPInput[ndx][k]); + } + DEBUG("\n"); + DEBUG(" adapted scan order =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->lopass_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" adapted scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->lopass_scantotals[k]); + } + DEBUG("\n"); + } +#endif + + model_bits = image->model_lp.bits[chroma_flag]; + lap_mean[chroma_flag] += num_nonzero; + DEBUG(" MB_LP: start refine, model_bits=%d, bitpos=%zu\n", + model_bits, _jxr_rbitstream_bitpos(str)); + if (model_bits) { + static const int transpose444[16] = { 0, 4, 8,12, + 1, 5, 9,13, + 2, 6,10,14, + 3, 7,11,15 }; + if (chroma_flag == 0) { + int k; + for (k=1 ;k<16; k+=1) { + int k_ptr = transpose444[k]; + LPInput[ndx][k_ptr] = r_REFINE_LP(str, LPInput[ndx][k_ptr], model_bits); + } + } else { + int k; + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + for (k=1 ; k<4; k+=1) { + int k_ptr = transpose420[k]; + LPInput[1][k_ptr] = r_REFINE_LP(str, LPInput[1][k_ptr], model_bits); + LPInput[2][k_ptr] = r_REFINE_LP(str, LPInput[2][k_ptr], model_bits); + } + break; + case 2: /* YUV422 */ + for (k=1 ; k<8; k+=1) { + int k_ptr = transpose422[k]; + DEBUG(" MP_LP: Refine LP_Input[1/2][%d] = 0x%x/0x%x bitpos=%zu\n", + k_ptr, LPInput[1][k_ptr], LPInput[2][k_ptr], + _jxr_rbitstream_bitpos(str)); + LPInput[1][k_ptr] = r_REFINE_LP(str, LPInput[1][k_ptr], model_bits); + LPInput[2][k_ptr] = r_REFINE_LP(str, LPInput[2][k_ptr], model_bits); + } + break; + default: /* All others */ + for (k=1 ;k<16; k+=1) { + int k_ptr = transpose444[k]; + LPInput[ndx][k_ptr] = r_REFINE_LP(str, LPInput[ndx][k_ptr], model_bits); + } + break; + } + } + } + + /* Stash the calculated LP values into the current + MACROBLK strip */ + if (chroma_flag == 0) { + /* All luma planes are simply copied into the macroblk. */ + int k; + DEBUG(" lp val =="); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", LPInput[ndx][k]); + MACROBLK_CUR_LP(image, ndx, tx, mx, k-1) = LPInput[ndx][k]; + } + DEBUG("\n"); + } else { + int k; + DEBUG(" lp val (ch=%d) ==", ndx); + switch (image->use_clr_fmt) { + case 1:/* YUV420 */ + /* The chroma for YUV420 is interleaved. */ + for (k = 1 ; k < 4 ; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + MACROBLK_CUR_LP(image, 1, tx, mx, k-1) = LPInput[1][k]; + MACROBLK_CUR_LP(image, 2, tx, mx, k-1) = LPInput[2][k]; + } + break; + case 2:/* YUV422 */ + /* The chroma for YUV422 is interleaved. */ + for (k = 1 ; k < 8 ; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + MACROBLK_CUR_LP(image, 1, tx, mx, k-1) = LPInput[1][k]; + MACROBLK_CUR_LP(image, 2, tx, mx, k-1) = LPInput[2][k]; + } + break; + default: + for (k = 1 ; k < 16 ; k += 1) { + DEBUG(" 0x%x", LPInput[ndx][k]); + MACROBLK_CUR_LP(image, ndx, tx, mx, k-1) = LPInput[ndx][k]; + } + break; + } + DEBUG("\n"); + } + } + + DEBUG(" MB_LP: UpdateModelMB lap_mean={%d, %d}\n", lap_mean[0], lap_mean[1]); + _jxr_UpdateModelMB(image, lap_mean, &image->model_lp, 1/*band=LP*/); + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" AdaptLP at the end of mx=%d (my=%d, ndx=%u)\n", mx, my, ndx); + _jxr_AdaptLP(image); + } + + DEBUG(" MB_LP DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); +} + +/* +* This decides the MBCBP for the macroblock. This value is then used +* by the MB_HP to know how to decide the HP values for the macroblock. +*/ +int _jxr_r_MB_CBP(jxr_image_t image, struct rbitstream*str, int alpha_flag, + unsigned tx, unsigned ty, unsigned mx, unsigned my) +{ + static const int flc_table[] = {0, 2, 1, 2, 2, 0}; + static const int off_table[] = {0, 4, 2, 8, 12, 1}; + static const int out_table[] = { + 0, 15, 3, 12, + 1, 2, 4, 8, + 5, 6, 9, 10, + 7, 11, 13, 14 }; + + int diff_cbp[MAX_CHANNELS]; + int idx; + int chan; + int channels; + + for (idx = 0 ; idx < MAX_CHANNELS ; idx += 1) + diff_cbp[idx] = 0; + + DEBUG(" MB_CBP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_rbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_CBP: InitContext\n"); + /* This happens only at the top left edge of the tile. */ + _jxr_InitCBPVLC(image); + } + + /* "Channels" is not quite the same as "planes". For the + purposes of CBP parsing, a color image has 1 channel. */ + channels = 1; + if (image->use_clr_fmt==4/*YUVK*/ || image->use_clr_fmt==6/*NCOMPONENT*/) + channels = image->num_channels; + + /* This "for" loop decides not the code block pattern itself, + but the encoded difference values. These are then added to + the predicted values that are calculated later to make the + actual MBCBP values. */ + for (chan = 0 ; chan < channels ; chan += 1) { + struct adaptive_vlc_s*vlc = image->vlc_table + DecNumCBP; + int num_cbp = get_num_cbp(str, vlc); + int blk; + static const int Num_CBP_Delta[5] = {0, -1, 0, 1, 1}; + int cbp; + + DEBUG(" MB_CBP: Decode CBP for channel %d bitpos=%zu\n", chan, _jxr_rbitstream_bitpos(str)); + + assert(vlc->deltatable == 0 && num_cbp < 5); + vlc->discriminant += Num_CBP_Delta[num_cbp]; + + DEBUG(" MB_CBP: Got num_cbp=%d, start REFINE_CBP at bitpos=%zu\n", + num_cbp, _jxr_rbitstream_bitpos(str)); + + cbp = r_REFINE_CBP(str, num_cbp); + + DEBUG(" MB_CBP: Refined CBP=0x%x (num=%d)\n", cbp, num_cbp); + + /* The cbp is a "block present" bit hask for a group of + 4 blocks. This is used to inform the loop below that + then tries to fill discern the 4 bits for the range + enabled by this first level cbp. For example, if + cbp=0x5, then the 16 diff_cbp values are 0x0?0? where + the ? nibbles are yet to be resolved by the loop + below. */ + + for (blk = 0 ; blk < 4 ; blk += 1) { + int code; + int val; + int blkcbp; + int num_blkcbp; + + if ( (cbp & (1<<blk)) == 0 ) + continue; + + vlc = image->vlc_table + DecNumBlkCBP; + DEBUG(" MB_CBP: block=%d Use DecNumBlkCBP table=%d, discriminant=%d, bitpos=%zu\n", + blk, vlc->table, vlc->discriminant, _jxr_rbitstream_bitpos(str)); + + num_blkcbp = get_num_blkcbp(image, str, vlc); + + assert(vlc->deltatable == 0); + + if (image->use_clr_fmt==0 || image->use_clr_fmt==4 || image->use_clr_fmt==6) { + static const int Num_BLKCBP_Delta5[5] = {0, -1, 0, 1, 1}; + assert(num_blkcbp < 5); + vlc->discriminant += Num_BLKCBP_Delta5[num_blkcbp]; + } else { + static const int Num_BLKCBP_Delta9[9] = {2, 2, 1, 1, -1, -2, -2, -2, -3}; + assert(num_blkcbp < 9); + vlc->discriminant += Num_BLKCBP_Delta9[num_blkcbp]; + } + + DEBUG(" MB_CBP: NUM_BLKCBP=%d, discriminant becomes=%d, \n", + num_blkcbp, vlc->discriminant); + + val = num_blkcbp + 1; + + blkcbp = 0; + + /* Should only be true if this is chroma data. */ + if (val >= 6) { + int chr_cbp = get_value_012(str); + blkcbp = 0x10 * (chr_cbp+1); + if (val >= 9) { + int val_inc = get_value_012(str); + val += val_inc; + } + DEBUG(" MB_CBP: iVal=%d, CHR_CBP=%x\n", val, chr_cbp); + val -= 6; + } + assert(val < 6); + + code = off_table[val]; + if (flc_table[val]) { + code += _jxr_rbitstream_uintN(str, flc_table[val]); + } + + assert(code < 16); + blkcbp += out_table[code]; + + DEBUG(" MB_CBP: NUM_BLKCBP=%d, iCode=%d\n", num_blkcbp, code); + DEBUG(" MB_CBP: blkcbp=0x%x for chunk blk=%d\n", blkcbp, blk); + + /* blkcbp is done. Now calculate the + diff_cbp. How this is done (and how many + there are) depend on the color format. */ + + switch (image->use_clr_fmt) { + case 3: /*YUV444*/ + diff_cbp[0] |= (blkcbp&0xf) << (blk * 4); + if (blkcbp & 0x10) { + int num_ch_blk = get_num_ch_blk(str); + int cbp_chr = r_REFINE_CBP(str, num_ch_blk+1); + DEBUG(" MB_CBP: Refined CBP_U=0x%x (num=%d)\n", cbp_chr, num_ch_blk); + diff_cbp[1] |= cbp_chr << (blk*4); + } + if (blkcbp & 0x20) { + int num_ch_blk = get_num_ch_blk(str); + int cbp_chr = r_REFINE_CBP(str, num_ch_blk+1); + DEBUG(" MB_CBP: Refined CBP_V=0x%x (num=%d)\n", cbp_chr, num_ch_blk); + diff_cbp[2] |= cbp_chr << (blk*4); + } + break; + + case 2: /*YUV422*/ + diff_cbp[0] |= (blkcbp&0xf) << (blk*4); + if (blkcbp & 0x10) { + const int shift[4] = {0, 1, 4, 5}; + int cbp_ch_blk = get_value_012(str); + int cbp_chr = shift[cbp_ch_blk+1]; + diff_cbp[1] |= cbp_chr << shift[blk]; + DEBUG(" MB_CBP: Refined CBP_U=0x%x (cbp_ch_blk=%d, blk=%d)\n", + diff_cbp[1], cbp_ch_blk, blk); + } + if (blkcbp & 0x20) { + const int shift[4] = {0, 1, 4, 5}; + int cbp_ch_blk = get_value_012(str); + int cbp_chr = shift[cbp_ch_blk+1]; + diff_cbp[2] |= cbp_chr << shift[blk]; + DEBUG(" MB_CBP: Refined CBP_V=0x%x (cbp_ch_blk=%d, blk=%d)\n", + diff_cbp[2], cbp_ch_blk, blk); + } + break; + + case 1: /*YUV420*/ + diff_cbp[0] |= (blkcbp & 0xf) << (blk*4); + diff_cbp[1] |= ((blkcbp >> 4) & 1) << blk; + diff_cbp[2] += ((blkcbp >> 5) & 1) << blk; + break; + + default: + diff_cbp[chan] |= blkcbp << (blk*4); + break; + } + } + DEBUG(" MB_CBP: chan=%d, num_cbp=%d, cbp=0x%1x\n", chan, num_cbp, cbp); + } + +#if defined(DETAILED_DEBUG) + for (chan = 0 ; chan < image->num_channels ; chan += 1) { + DEBUG(" MB_CBP: diff_cbp[%d]=0x%04x\n", chan, diff_cbp[chan]); + } +#endif + + r_PredCBP(image, diff_cbp, tx, ty, mx, my); + + DEBUG(" MB_CBP done tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); + return 0; +} + +static int r_REFINE_CBP(struct rbitstream*str, int num) +{ + switch (num) { + case 1: + return 1 << _jxr_rbitstream_uint2(str); + + case 2: + /* + * table value + * 00 3 + * 01 5 + * 100 6 + * 101 9 + * 110 10 + * 111 12 + */ + if (_jxr_rbitstream_uint1(str) == 0) { + if (_jxr_rbitstream_uint1(str) == 0) + return 3; + else + return 5; + } else { /* 1xx */ + if (_jxr_rbitstream_uint1(str) == 0) { /* 10x */ + if (_jxr_rbitstream_uint1(str) == 0) + return 6; + else + return 9; + } else { /* 11x */ + if (_jxr_rbitstream_uint1(str) == 0) + return 10; + else + return 12; + } + } + + case 3: + return 0x0f ^ (1 << _jxr_rbitstream_uint2(str)); + + case 4: + return 0x0f; + + default: + return 0x00; + } +} + + +int _jxr_r_MB_HP(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int use_num_channels; + int idx; + int lap_mean[2]; + int flex_flag; + int mbhp_pred_mode; + + DEBUG(" MB_HP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_rbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_HP: InitContext\n"); + /* This happens only at the top left edge of the tile. */ + _jxr_InitHPVLC(image); + _jxr_InitializeAdaptiveScanHP(image); + _jxr_InitializeModelMB(&image->model_hp, 2/*band=HP*/); + } + + if (_jxr_ResetTotals(image, mx)) { + _jxr_ResetTotalsAdaptiveScanHP(image); + } + + /* FLEXBITS are embedded in the HP data if there are FLEXBITS + present in the bitstream AND we are in SPATIAL (not + FREQUENCY) mode. */ + flex_flag = 1; + if (image->bands_present == 1) /* NOFLEXBITS */ + flex_flag = 0; + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) != 0) /* FREQUENCY_MODE */ + flex_flag = 0; + + lap_mean[0] = 0; + lap_mean[1] = 0; + + /* Calculate the MB HP prediction mode. This uses only local + information, namely the LP values. */ + mbhp_pred_mode = r_calculate_mbhp_mode(image, tx, mx); + assert(mbhp_pred_mode < 4); + + for (idx = 0 ; idx < image->num_channels; idx += 1) { + int chroma_flag = idx>0? 1 : 0; + int nblocks = 4; + unsigned model_bits; + int cbp; + int block; + + if (chroma_flag && image->use_clr_fmt==1/*YUV420*/) + nblocks = 1; + else if (chroma_flag && image->use_clr_fmt==2/*YUV422*/) + nblocks = 2; + + model_bits = image->model_hp.bits[chroma_flag]; + cbp = MACROBLK_CUR_HPCBP(image, idx, tx, mx); + + DEBUG(" MB_HP channel=%d, cbp=0x%x, model_bits=%u MBHPMode=%d\n", + idx, cbp, model_bits, mbhp_pred_mode); + for (block=0 ; block<(nblocks*4) ; block += 1, cbp >>= 1) { + int bpos = block; + int num_nonzero; + /* Only remap the Y plane of YUV42X data. */ + if (nblocks == 4) + bpos = _jxr_hp_scan_map[block]; + num_nonzero = r_DECODE_BLOCK_ADAPTIVE(image, str, tx, mx, + cbp&1, chroma_flag, + idx, bpos, mbhp_pred_mode, + model_bits); + if (num_nonzero < 0) { + DEBUG("ERROR: r_DECODE_BLOCK_ADAPTIVE returned rc=%d\n", num_nonzero); + return JXR_EC_ERROR; + } + if (flex_flag) + r_BLOCK_FLEXBITS(image, str, tx, ty, mx, my, + idx, bpos, model_bits); + lap_mean[chroma_flag] += num_nonzero; + } + + } + + use_num_channels = image->num_channels; + if (image->use_clr_fmt == 1/*YUV420*/ || image->use_clr_fmt == 2/*YUV422*/) + use_num_channels = 1; + + /* Propagate HP predictions only in SPATIAL MODE. If this is + FREQUENCY mode, and there is a FLEXBITS pass later, then do + *not* do the predictions, leaving them to the FLEXBITS tile. */ + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) == 0 || image->bands_present == 1) { + DEBUG(" MB_HP: propagate hp predictions within MB_HP function\n"); + for (idx = 0 ; idx < use_num_channels ; idx += 1) + _jxr_propagate_hp_predictions(image, idx, tx, mx, mbhp_pred_mode); + } + + DEBUG(" MP_HP: lap_mean={%u, %u}, model_hp.bits={%u %u}, model_hp.state={%d %d}\n", + lap_mean[0], lap_mean[1], + image->model_hp.bits[0], image->model_hp.bits[1], + image->model_hp.state[0], image->model_hp.state[1]); + + MACROBLK_CUR(image,0,tx,mx).mbhp_pred_mode = mbhp_pred_mode; + MACROBLK_CUR(image,0,tx,mx).hp_model_bits[0] = image->model_hp.bits[0]; + MACROBLK_CUR(image,0,tx,mx).hp_model_bits[1] = image->model_hp.bits[1]; + + _jxr_UpdateModelMB(image, lap_mean, &image->model_hp, 2/*band=HP*/); + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" MB_HP: Run AdaptHP\n"); + _jxr_AdaptHP(image); + } + + DEBUG(" MP_HP: Updated: lap_mean={%u, %u}, model_hp.bits={%u %u}, model_hp.state={%d %d}\n", + lap_mean[0], lap_mean[1], + image->model_hp.bits[0], image->model_hp.bits[1], + image->model_hp.state[0], image->model_hp.state[1]); + + DEBUG(" MB_HP DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); + return 0; +} + +int _jxr_r_MB_FLEXBITS(jxr_image_t image, struct rbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int idx; + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + int chroma_flag = idx>0? 1 : 0; + int nblocks = 4; + unsigned model_bits; + int block; + if (chroma_flag && image->use_clr_fmt==1/*YUV420*/) + nblocks = 1; + else if (chroma_flag && image->use_clr_fmt==2/*YUV422*/) + nblocks = 2; + + model_bits = MACROBLK_CUR(image,0,tx,mx).hp_model_bits[chroma_flag]; + + for (block=0 ; block<(nblocks*4) ; block += 1) { + int bpos = block; + /* Only remap the Y plane of YUV42X data. */ + if (nblocks == 4) + bpos = _jxr_hp_scan_map[block]; + + r_BLOCK_FLEXBITS(image, str, tx, ty, mx, my, + idx, bpos, model_bits); + } + } + + return 0; +} + +/* +* Decode a single DC component value from the input stream. +*/ +static int32_t r_DEC_DC(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + int model_bits, int chroma_flag, int is_dc_ch) +{ + int32_t dc_val = 0; + + if (is_dc_ch) { + dc_val = r_DECODE_ABS_LEVEL(image, str, 0/*DC*/, chroma_flag) -1; + DEBUG(" DEC_DC: DECODE_ABS_LEVEL = %u (0x%08x)\n", dc_val, dc_val); + } + + /* If there are model_bits, then read them literally from the + bitstream and use them as the LSB bits for the DC value. */ + if (model_bits > 0) { + int idx; + DEBUG(" DEC_DC: Collect %u model_bits\n", model_bits); + for (idx = 0 ; idx < model_bits ; idx += 1) { + dc_val <<= 1; + dc_val |= _jxr_rbitstream_uint1(str); + } + } + + /* If the dc_val is non-zero, it may have a sign so decode the + sign bit and apply it. */ + if (dc_val != 0) { + int sign_flag = _jxr_rbitstream_uint1(str); + DEBUG(" DEC_DC: sign_flag=%s\n", sign_flag? "true":"false"); + if (sign_flag) + dc_val = - dc_val; + } + + DEBUG(" DEC_DC: DC value is %d (0x%08x)\n", dc_val, dc_val); + return dc_val; +} + +/* +* This function decodes one sample from one of the bands. The code is +* the same for any of the bands. The band (and chroma_flag) is only +* used to select the vlc_table. +* +* Note that the chroma_flag is only interpreted as the "chroma_flag" +* when the band is DC. Otherwise, the chroma_flag argument is taken +* as the "context" argument described in the specification. +*/ +static uint32_t r_DECODE_ABS_LEVEL(jxr_image_t image, struct rbitstream*str, + int band, int chroma_flag) +{ + int vlc_select = _jxr_vlc_select(band, chroma_flag); + + const int remap[] = {2, 3, 4, 6, 10, 14}; + const int fixed_len[] = {0, 0, 1, 2, 2, 2}; + uint32_t level; + + int abslevel_index = dec_abslevel_index(image, str, vlc_select); + DEBUG(" Use vlc_select = %s (table=%d) to decode level index, bitpos=%zu\n", + _jxr_vlc_index_name(vlc_select), image->vlc_table[vlc_select].table, + _jxr_rbitstream_bitpos(str)); + DEBUG(" ABSLEVEL_INDEX = %d\n", abslevel_index); + + image->vlc_table[vlc_select].discriminant += _jxr_abslevel_index_delta[abslevel_index]; + + if (abslevel_index < 6) { + int fixed = fixed_len[abslevel_index]; + uint32_t level_ref = 0; + + level = remap[abslevel_index]; + if (fixed > 0) { + int idx; + assert(fixed <= 32); + for (idx = 0 ; idx < fixed ; idx += 1) { + level_ref <<= 1; + level_ref |= _jxr_rbitstream_uint1(str); + } + level += level_ref; + } + DEBUG(" ABS_LEVEL = 0x%x (fixed = %d, level_ref = %d)\n", + level, fixed, level_ref); + } else { + int fixed = 4 + _jxr_rbitstream_uint4(str); + uint32_t level_ref; + int idx; + + if (fixed == 19) { + fixed += _jxr_rbitstream_uint2(str); + if (fixed == 22) { + fixed += _jxr_rbitstream_uint3(str); + } + } + + assert(fixed <= 32); + + level_ref = 0; + for (idx = 0 ; idx < fixed ; idx += 1) { + level_ref <<= 1; + level_ref |= _jxr_rbitstream_uint1(str); + } + level = 2 + (1 << fixed) + level_ref; + DEBUG(" ABS_LEVEL = 0x%x (fixed = %d, level_ref = %d)\n", + level, fixed, level_ref); + } + + return level; +} + +/* +* The DECODE_BLOCK decodes the block as run/coefficient pairs. The +* run is the distance to the next coefficient, and is followed by the +* coefficient itself. The skipped values are implicitly zeros. A +* later process takes these pairs including adaptation of their position. +*/ +int r_DECODE_BLOCK(jxr_image_t image, struct rbitstream*str, + int chroma_flag, int coeff[32], int band, int location) +{ + int num_nz = 1; + + /* The index is a bit field that encodes three values: + * index[0] : 1 means the run to the next coeff is == 0 + * index[1] : 1 means the next coefficient is >1 + * index[3:2]: 0 This is the last coefficient + * 1 the next non-zero coefficient immediately follows + * 2 there are zero coefficients before the next. + */ + int index = r_DECODE_FIRST_INDEX(image, str, chroma_flag, band); + int sr = index & 1; + int srn = index >> 2; + int context = sr & srn; + int sign_flag; + + DEBUG(" DECODE_BLOCK chroma_flag=%d, band=%d, location=%d bitpos=%zu\n", + chroma_flag, band, location, _jxr_rbitstream_bitpos(str)); + DEBUG(" first index=0x%x\n", index); + + + /* Decode the first coefficient. Note that the chroma_flag + argument to DECODE_ABS_LEVEL really is supposed to be the + context. It is "chroma" for DC values (band==0) and context + for LP and HP values. This DECODE_BLOCK is only called for + LP and HP blocks. */ + sign_flag = _jxr_rbitstream_uint1(str); + if (index&2) + coeff[1] = r_DECODE_ABS_LEVEL(image, str, band, context); + else + coeff[1] = 1; + + if (sign_flag) + coeff[1] = -coeff[1]; + + /* Decode the run to the first coefficient. */ + if (index&1) { + coeff[0] = 0; + } else { + assert( location < 15 ); + coeff[0] = r_DECODE_RUN(image, str, 15-location); + } + + DEBUG(" coeff[0] = %d (run)\n", coeff[0]); + DEBUG(" coeff[1] = 0x%x (coeff)\n", coeff[1]); + + location += coeff[0] + 1; + + while (srn != 0) { /* While more coefficients are expected... */ + sr = srn & 1; + + /* Decode run to the next coefficient. */ + if (srn & 1) { + coeff[num_nz*2] = 0; + } else { + coeff[num_nz*2] = r_DECODE_RUN(image, str, 15-location); + } + + DEBUG(" coeff[%d*2+0] = %d (run)\n", num_nz, coeff[num_nz*2]); + + location += coeff[num_nz*2] + 1; + + /* The index is a bit field that encodes two values: + * index[0] : 1 means the run to the next coeff is == 0 + * index[2:1]: 0 This is the last coefficient + * 1 the next non-zero coefficient immediately follows + * 2 there are zero coefficients before the next. + * The location can clue the DECODE_INDEX that certain + * constraints on the possible index values may exist, + * and certain restricted tables are used. + */ + index = r_DECODE_INDEX(image, str, location, chroma_flag, band, context); + DEBUG(" next index=0x%x\n", index); + + srn = index >> 1; + context &= srn; + + /* Decode the next coefficient. */ + sign_flag = _jxr_rbitstream_uint1(str); + if (index & 1) + coeff[num_nz*2+1] = r_DECODE_ABS_LEVEL(image, str, + band, context); + else + coeff[num_nz*2+1] = 1; + + if (sign_flag) + coeff[num_nz*2+1] = -coeff[num_nz*2+1]; + + DEBUG(" coeff[%d*2+1] = 0x%x (coeff)\n", num_nz, coeff[num_nz*2+1]); + num_nz += 1; + } + + DEBUG(" DECODE_BLOCK done, num_nz=%d\n", num_nz); + return num_nz; +} + +static int r_DECODE_FIRST_INDEX(jxr_image_t image, struct rbitstream*str, + int chroma_flag, int band) +{ + /* VALUE TABLE0 + * 0 0000 1.. + * 1 0000 01. + * 2 0000 000 + * 3 0000 001 + * 4 0010 0.. + * 5 010. ... + * 6 0010 1.. + * 7 1... ... + * 8 0011 0.. + * 9 0001 ... + * 10 0011 1.. + * 11 011. ... + * (Table 59: Note that the first bit is handled as a special + * case, so the array only needs to account for the last 6 bits.) + */ + static const unsigned char c0b[64] = { + 6, 6, 5, 5, 4, 4, 4, 4, 3, 3, 3, 3, 3, 3, 3, 3, + 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, 4, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + }; + static const signed char c0v[64] = { + 2, 3, 1, 1, 0, 0, 0, 0, 9, 9, 9, 9, 9, 9, 9, 9, + 4, 4, 4, 4, 6, 6, 6, 6, 8, 8, 8, 8, 10,10,10,10, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 11,11,11,11, 11,11,11,11, 11,11,11,11, 11,11,11,11 + }; + /* VALUE TABLE1 + * 0 0010 .. + * 1 0001 0. + * 2 0000 00 + * 3 0000 01 + * 4 0011 .. + * 5 010. .. + * 6 0001 1. + * 7 11.. .. + * 8 011. .. + * 9 100. .. + * 10 0000 1. + * 11 101. .. + */ + static const unsigned char c1b[64] = { + 6, 6, 5, 5, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + }; + static const signed char c1v[64] = { + 2, 3,10,10, 1, 1, 6, 6, 0, 0, 0, 0, 4, 4, 4, 4, + 5, 5, 5, 5, 5, 5, 5, 5, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 11,11,11,11, 11,11,11,11, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7 + }; + + /* VALUE TABLE2 + * 0 11.. ... + * 1 001. ... + * 2 0000 000 + * 3 0000 001 + * 4 0000 1.. + * 5 010. ... + * 6 0000 010 + * 7 011. ... + * 8 100. ... + * 9 101. ... + * 10 0000 011 + * 11 0001 ... + */ + static const unsigned char c2b[128] = { + 7, 7, 7, 7, 5, 5, 5, 5, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + }; + static const signed char c2v[128] = { + 2, 3, 6,10, 4, 4, 4, 4, 11,11,11,11, 11,11,11,11, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + + 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, 8, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 + }; + + /* VALUE TABLE3 + * 0 001. ... + * 1 11.. ... + * 2 0000 000 + * 3 0000 1.. + * 4 0001 0.. + * 5 010. ... + * 6 0000 001 + * 7 011. ... + * 8 0001 1.. + * 9 100. ... + * 10 0000 01. + * 11 101. ... + */ + static const unsigned char c3b[128] = { + 7, 7, 6, 6, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + }; + static const signed char c3v[128] = { + 2, 6,10,10, 3, 3, 3, 3, 4, 4, 4, 4, 8, 8, 8, 8, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 11,11,11,11, 11,11,11,11, 11,11,11,11, 11,11,11,11, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 + }; + + /* VALUE TABLE4 + * 0 010. .... + * 1 1... .... + * 2 0000 001. + * 3 0001 .... + * 4 0000 010. + * 5 011. .... + * 6 0000 0000 + * 7 0010 .... + * 8 0000 011. + * 9 0011 .... + * 10 0000 0001 + * 11 0000 1... + */ + static const unsigned char c4b[128] = { + 7, 7, 6, 6, 6, 6, 6, 6, 4, 4, 4, 4, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2, 2 + }; + static const signed char c4v[128] = { + 6,10, 2, 2, 4, 4, 8, 8, 11,11,11,11, 11,11,11,11, + 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, 3, + 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, 7, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5, 5 + }; + + typedef int deltatable_t[12]; + const deltatable_t FirstIndexDelta[4] = { + { 1, 1, 1, 1, 1, 0, 0,-1, 2, 1, 0, 0 }, + { 2, 2,-1,-1,-1, 0,-2,-1, 0, 0,-2,-1 }, + {-1, 1, 0, 2, 0, 0, 0, 0,-2, 0, 1, 1 }, + { 0, 1, 0, 1,-2, 0,-1,-1,-2,-1,-2,-2 } + }; + + int delta_table; + int delta2table; + int vlc_table; + int first_index; + + abs_level_vlc_index_t vlc_select = (abs_level_vlc_index_t)0; + + switch (band) { + case 1: /* LP */ + if (chroma_flag) + vlc_select = DecFirstIndLPChr; + else + vlc_select = DecFirstIndLPLum; + break; + case 2: /* HP */ + if (chroma_flag) + vlc_select = DecFirstIndHPChr; + else + vlc_select = DecFirstIndHPLum; + break; + default: + assert(0); + break; + } + + vlc_table = image->vlc_table[vlc_select].table; + first_index = 0; + + switch (vlc_table) { + case 0: + if (_jxr_rbitstream_uint1(str)) { + first_index = 7; + } else { + first_index = _jxr_rbitstream_intE(str, 6, c0b, c0v); + } + break; + + case 1: + first_index = _jxr_rbitstream_intE(str, 6, c1b, c1v); + break; + + case 2: + first_index = _jxr_rbitstream_intE(str, 7, c2b, c2v); + break; + + case 3: + first_index = _jxr_rbitstream_intE(str, 7, c3b, c3v); + break; + + case 4: + if (_jxr_rbitstream_uint1(str)) { + first_index = 1; + } else { + first_index = _jxr_rbitstream_intE(str, 7, c4b, c4v); + } + break; + + default: + assert(0); + break; + } + + delta_table = image->vlc_table[vlc_select].deltatable; + delta2table = image->vlc_table[vlc_select].delta2table; + + assert(delta_table < 4); + assert(delta2table < 4); + assert(first_index < 12); + image->vlc_table[vlc_select].discriminant += FirstIndexDelta[delta_table][first_index]; + image->vlc_table[vlc_select].discriminant2 += FirstIndexDelta[delta2table][first_index]; + DEBUG(" DECODE_FIRST_INDEX: vlc_select = %s, vlc_table = %d, deltatable/2 = %d/%d, discriminant/2 = %d/%d, first_index=%d\n", + _jxr_vlc_index_name(vlc_select), vlc_table, + delta_table, delta2table, + image->vlc_table[vlc_select].discriminant, + image->vlc_table[vlc_select].discriminant2, first_index); + + return first_index; +} + +static int r_DECODE_INDEX(jxr_image_t image, struct rbitstream*str, + int location, int chroma_flag, int band, int context) +{ + int vlc_select = 0; + int vlc_delta; + int vlc_delta2; + int vlc_table; + int index; + + typedef int deltatable_t[6]; + const deltatable_t Index1Delta[3] = { + {-1, 1, 1, 1, 0, 1 }, + {-2, 0, 0, 2, 0, 0 }, + {-1,-1, 0, 1,-2, 0 } + }; + + + switch (band) { + case 1: /* LP */ + if (chroma_flag) + vlc_select = context? DecIndLPChr1 : DecIndLPChr0; + else + vlc_select = context? DecIndLPLum1 : DecIndLPLum0; + break; + case 2: /* HP */ + if (chroma_flag) + vlc_select = context? DecIndHPChr1 : DecIndHPChr0; + else + vlc_select = context? DecIndHPLum1 : DecIndHPLum0; + break; + default: + assert(0); + break; + } + + index = 0; + + /* If location > 15, then there can't possibly be coefficients + after the next, so the encoding will only encode the low + bit, that hints the run is zero or not. */ + if (location > 15) { + index = _jxr_rbitstream_uint1(str); + DEBUG(" DECODE_INDEX: location=%d, index=%d\n", location, index); + return index; + } + + /* If location == 15, then this is probably the last + coefficient, but there may be more. We do know that there + are no zero coefficients before the next (if there is one). + Use a fixed table to decode the index with reduced alphabet. */ + if (location == 15) { + /* Table 61 + * INDEX2 table + * 0 0 + * 2 10 + * 1 110 + * 3 111 + */ + if (_jxr_rbitstream_uint1(str) == 0) + index = 0; /* 0 */ + else if (_jxr_rbitstream_uint1(str) == 0) + index = 2; /* 10 */ + else if (_jxr_rbitstream_uint1(str) == 0) + index = 1; /* 110 */ + else + index = 3; /* 111 */ + DEBUG(" DECODE_INDEX: location=%d, index=%d\n", location, index); + return index; + } + + /* For more general cases, use adaptive table selections to + decode the full set of index possibilities. */ + vlc_table = image->vlc_table[vlc_select].table; + DEBUG(" DECODE_INDEX: vlc_select = %s, vlc_table = %d chroma_flag=%d\n", + _jxr_vlc_index_name(vlc_select), vlc_table, chroma_flag); + + /* Table 60 is implemented in this switch. */ + switch (vlc_table) { + case 0: + /* INDEX1 table0 + * 0 1 + * 1 00000 + * 2 001 + * 3 00001 + * 4 01 + * 5 0001 + */ + if (_jxr_rbitstream_uint1(str) == 1) + index = 0; /* 1 */ + else if (_jxr_rbitstream_uint1(str) == 1) + index = 4; /* 01 */ + else if (_jxr_rbitstream_uint1(str) == 1) + index = 2; /* 001 */ + else if (_jxr_rbitstream_uint1(str) == 1) + index = 5; /* 0001 */ + else if (_jxr_rbitstream_uint1(str) == 1) + index = 3; /* 00001 */ + else + index = 1; /* 00000 */ + break; + + case 1: + /* INDEX1 table1 + * 0 01 + * 1 0000 + * 2 10 + * 3 0001 + * 4 11 + * 5 001 + */ + switch (_jxr_rbitstream_uint2(str)) { + case 1: /* 01 */ + index = 0; + break; + case 2: /* 10 */ + index = 2; + break; + case 3: /* 11 */ + index = 4; + break; + case 0: /* 00... */ + if (_jxr_rbitstream_uint1(str) == 1) + index = 5; /* 001 */ + else if (_jxr_rbitstream_uint1(str) == 1) + index = 3; /* 0001 */ + else + index = 1; /* 0000 */ + break; + } + break; + + case 2: + /* INDEX1 table2 + * 0 0000 + * 1 0001 + * 2 01 + * 3 10 + * 4 11 + * 5 001 + */ + switch (_jxr_rbitstream_uint2(str)) { + case 1: /* 01 */ + index = 2; + break; + case 2: /* 10 */ + index = 3; + break; + case 3: /* 11 */ + index = 4; + break; + case 0: /* 00... */ + if (_jxr_rbitstream_uint1(str)) + index = 5; /* 001 */ + else if (_jxr_rbitstream_uint1(str)) + index = 1; /* 0001 */ + else + index = 0; /* 0000 */ + break; + } + break; + + case 3: + /* INDEX1 table3 + * 0 00000 + * 1 00001 + * 2 01 + * 3 1 + * 4 0001 + * 5 001 + */ + if (_jxr_rbitstream_uint1(str)) + index = 3; /* 1 */ + else if (_jxr_rbitstream_uint1(str)) + index = 2; /* 01 */ + else if (_jxr_rbitstream_uint1(str)) + index = 5; /* 001 */ + else if (_jxr_rbitstream_uint1(str)) + index = 4; /* 0001 */ + else if (_jxr_rbitstream_uint1(str)) + index = 1; /* 00001 */ + else + index = 0; /* 00000 */ + break; + + default: + assert(0); + } + + vlc_delta = image->vlc_table[vlc_select].deltatable; + vlc_delta2 = image->vlc_table[vlc_select].delta2table; + + image->vlc_table[vlc_select].discriminant += Index1Delta[vlc_delta][index]; + image->vlc_table[vlc_select].discriminant2+= Index1Delta[vlc_delta2][index]; + + DEBUG(" DECODE_INDEX: vlc_select = %s, deltatable/2 = %d/%d, discriminant/2 becomes %d/%d\n", + _jxr_vlc_index_name(vlc_select), vlc_delta, vlc_delta2, + image->vlc_table[vlc_select].discriminant, + image->vlc_table[vlc_select].discriminant2); + + return index; +} + +static int r_DECODE_RUN(jxr_image_t image, struct rbitstream*str, int max_run) +{ + int run; + + if (max_run < 5) { + DEBUG(" DECODE_RUN max_run=%d (<5) bitpos=%zu\n", + max_run, _jxr_rbitstream_bitpos(str)); + switch (max_run) { + case 1: + run = 1; + break; + case 2: + if (_jxr_rbitstream_uint1(str)) + run = 1; + else + run = 2; + break; + case 3: + if (_jxr_rbitstream_uint1(str)) + run = 1; + else if (_jxr_rbitstream_uint1(str)) + run = 2; + else + run = 3; + break; + case 4: + if (_jxr_rbitstream_uint1(str)) + run = 1; + else if (_jxr_rbitstream_uint1(str)) + run = 2; + else if (_jxr_rbitstream_uint1(str)) + run = 3; + else + run = 4; + break; + } + + } else { + static const int RunBin[15] = {-1,-1,-1,-1, 2,2,2, 1,1,1,1, 0,0,0,0 }; + static const int RunFixedLen[15] = {0,0,1,1,3, 0,0,1,1,2, 0,0,0,0,1 }; + static const int Remap[15] = {1,2,3,5,7, 1,2,3,5,7, 1,2,3,4,5 }; + int run_index = 0; + int fixed; + int index; + + if (_jxr_rbitstream_uint1(str)) + run_index = 0; /* 1 */ + else if (_jxr_rbitstream_uint1(str)) + run_index = 1; /* 01 */ + else if (_jxr_rbitstream_uint1(str)) + run_index = 2; /* 001 */ + else if (_jxr_rbitstream_uint1(str)) + run_index = 4; /* 0001 */ + else + run_index = 3; /* 0000 */ + + DEBUG(" DECODE_RUN max_run=%d, RUN_INDEX=%d\n", max_run, run_index); + + assert(max_run < 15); + index = run_index + 5*RunBin[max_run]; + DEBUG(" DECODE_RUN index=%d\n", index); + + assert(run_index < 15); + fixed = RunFixedLen[index]; + DEBUG(" DECODE_RUN fixed=%d (bitpos=%zu)\n", + fixed, _jxr_rbitstream_bitpos(str)); + + assert(run_index < 15); + run = Remap[index]; + if (fixed) { + run += _jxr_rbitstream_uintN(str, fixed); + } + } + + DEBUG(" DECODE_RUN max_run=%d, run=%d\n", max_run, run); + + return run; +} + + +static int r_REFINE_LP(struct rbitstream*str, int coeff, int model_bits) +{ + int coeff_refinement = _jxr_rbitstream_uintN(str, model_bits); + + if (coeff > 0) { + coeff <<= model_bits; + coeff += coeff_refinement; + } else if (coeff < 0) { + coeff <<= model_bits; + coeff -= coeff_refinement; + } else { + coeff = coeff_refinement; + if (coeff) { + int sign_flag = _jxr_rbitstream_uint1(str); + if (sign_flag) + coeff = -coeff; + } + } + + return coeff; +} + +static void r_PredCBP(jxr_image_t image, int*diff_cbp, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int idx; + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + _jxr_InitializeCBPModel(image); + } + + assert(my == image->cur_my); + switch (image->use_clr_fmt) { + case 1: /*YUV420*/ + MACROBLK_CUR_HPCBP(image, 0, tx, mx) + = _jxr_PredCBP444(image, diff_cbp, 0, tx, mx, my); + MACROBLK_CUR_HPCBP(image, 1, tx, mx) + = _jxr_PredCBP420(image, diff_cbp, 1, tx, mx, my); + MACROBLK_CUR_HPCBP(image, 2, tx, mx) + = _jxr_PredCBP420(image, diff_cbp, 2, tx, mx, my); + DEBUG(" PredCBP: Predicted HPCBP[ch=0]: 0x%04x (YUV420)\n", + MACROBLK_CUR_HPCBP(image, 0, tx, mx)); + DEBUG(" PredCBP: Predicted HPCBP[ch=1]: 0x%04x (YUV420)\n", + MACROBLK_CUR_HPCBP(image, 1, tx, mx)); + DEBUG(" PredCBP: Predicted HPCBP[ch=2]: 0x%04x (YUV420)\n", + MACROBLK_CUR_HPCBP(image, 2, tx, mx)); + break; + case 2: /*YUV422*/ + MACROBLK_CUR_HPCBP(image, 0, tx, mx) + = _jxr_PredCBP444(image, diff_cbp, 0, tx, mx, my); + MACROBLK_CUR_HPCBP(image, 1, tx, mx) + = _jxr_PredCBP422(image, diff_cbp, 1, tx, mx, my); + MACROBLK_CUR_HPCBP(image, 2, tx, mx) + = _jxr_PredCBP422(image, diff_cbp, 2, tx, mx, my); + DEBUG(" PredCBP: Predicted HPCBP[ch=0]: 0x%04x (YUV422)\n", + MACROBLK_CUR_HPCBP(image, 0, tx, mx)); + DEBUG(" PredCBP: Predicted HPCBP[ch=1]: 0x%04x (YUV422)\n", + MACROBLK_CUR_HPCBP(image, 1, tx, mx)); + DEBUG(" PredCBP: Predicted HPCBP[ch=2]: 0x%04x (YUV422)\n", + MACROBLK_CUR_HPCBP(image, 2, tx, mx)); + break; + default: + for (idx = 0; idx<image->num_channels; idx += 1) { + MACROBLK_CUR_HPCBP(image, idx, tx, mx) + = _jxr_PredCBP444(image, diff_cbp, idx, tx, mx, my); + DEBUG(" PredCBP: Predicted HPCBP[ch=%d]: 0x%04x\n", + idx, MACROBLK_CUR_HPCBP(image, idx, tx, mx)); + } + break; + } +} + +static void AdaptiveHPScan(jxr_image_t image, int hpinput_n[], + int i, int value, int MBHPMode) +{ + assert(i > 0); + + if (MBHPMode == 1) { + int k = image->hipass_ver_scanorder[i-1]; + image->hipass_ver_scantotals[i-1] += 1; + assert(k < 16); + hpinput_n[k] = value; + + if ((i>1) && (image->hipass_ver_scantotals[i-1] > image->hipass_ver_scantotals[i-2])) { + SWAP(image->hipass_ver_scantotals[i-1], image->hipass_ver_scantotals[i-2]); + SWAP(image->hipass_ver_scanorder[i-1], image->hipass_ver_scanorder[i-2]); + } + } else { + int k = image->hipass_hor_scanorder[i-1]; + image->hipass_hor_scantotals[i-1] += 1; + assert(k < 16); + hpinput_n[k] = value; + + if ((i>1) && (image->hipass_hor_scantotals[i-1] > image->hipass_hor_scantotals[i-2])) { + SWAP(image->hipass_hor_scantotals[i-1], image->hipass_hor_scantotals[i-2]); + SWAP(image->hipass_hor_scanorder[i-1], image->hipass_hor_scanorder[i-2]); + } + } +} + +/* +* For each block within the macroblk, there are 15 HP values and the +* DECODE_BLOCK_ADAPTIVE function is called to collect those values. +*/ +static int r_DECODE_BLOCK_ADAPTIVE(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned mx, + int cbp_flag, int chroma_flag, + int channel, int block, int mbhp_pred_mode, + unsigned model_bits) +{ + int RLCoeffs[32] = {0}; + + int num_nonzero = 0; + if (cbp_flag) { + int idx, k; + int hpinput[16]; + for (k = 0 ; k < 16 ; k += 1) + hpinput[k] = 0; + + num_nonzero = r_DECODE_BLOCK(image, str, chroma_flag, RLCoeffs, 2/*HP*/, 1); + + for (idx = 0, k = 1 ; idx < num_nonzero ; idx += 1) { + assert(idx < 16); + k += RLCoeffs[idx*2]; + if (k >= 16) { + DEBUG("ERROR: r_DECODE_BLOCK returned bogus RLCoeffs table. ch=%d, tx=%u, mx=%u, k=%d\n", + channel, tx, mx, k); + for (idx = 0 ; idx < num_nonzero ; idx += 1) { + DEBUG(" : RLCoeffs[%d] = %d\n", idx*2, RLCoeffs[idx*2]); + DEBUG(" : RLCoeffs[%d] = 0x%x\n", idx*2+1, RLCoeffs[idx*2+1]); + } + return JXR_EC_ERROR; + } + assert(k < 16); + AdaptiveHPScan(image, hpinput, k, RLCoeffs[idx*2+1], mbhp_pred_mode); + k += 1; + } +#if defined(DETAILED_DEBUG) + { + DEBUG(" HP val[tx=%u, mx=%d, block=%d] ==", tx, mx, block); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", hpinput[k]); + } + DEBUG("\n"); + DEBUG(" adapted hor scan order (MBHPMode=%d) ==", mbhp_pred_mode); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_hor_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" adapted hor scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_hor_scantotals[k]); + } + DEBUG("\n"); + DEBUG(" adapted ver scan order (MBHPMode=%d) ==", mbhp_pred_mode); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_ver_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" adapted ver scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_ver_scantotals[k]); + } + DEBUG("\n"); + } +#endif + if (SKIP_HP_DATA(image)) { + for (idx = 1; idx < 16; idx += 1) + MACROBLK_CUR_HP(image, channel, tx, mx, block, idx-1) = 0; + } else { + for (idx = 1; idx < 16; idx += 1) + MACROBLK_CUR_HP(image, channel, tx, mx, block, idx-1) = hpinput[idx] << model_bits; + } + } + + return num_nonzero; +} + + + +static void r_DECODE_FLEX(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned mx, + int ch, unsigned block, unsigned k, + unsigned flexbits) +{ + /* NOTE: The model_bits shift was already applied, when the HP + value was first parsed. */ + int coeff = MACROBLK_CUR_HP(image, ch, tx, mx, block, k); + + int flex_ref = _jxr_rbitstream_uintN(str, flexbits); + DEBUG(" DECODE_FLEX: coeff=0x%08x, flex_ref=0x%08x\n", coeff, flex_ref); + if (coeff > 0) { + coeff += flex_ref << image->trim_flexbits; + } else if (coeff < 0) { + coeff -= flex_ref << image->trim_flexbits; + } else { + if (flex_ref != 0 && _jxr_rbitstream_uint1(str)) + coeff = (-flex_ref) << image->trim_flexbits; + else + coeff = (+flex_ref) << image->trim_flexbits; + } + + if (! SKIP_FLEX_DATA(image)) + MACROBLK_CUR_HP(image, ch, tx, mx, block, k) = coeff; +} + +static void r_BLOCK_FLEXBITS(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + unsigned ch, unsigned bl, unsigned model_bits) +{ + const int transpose444 [16] = {0, 4, 8,12, + 1, 5, 9,13, + 2, 6,10,14, + 3, 7,11,15 }; + unsigned flexbits_left = model_bits; + if (image->trim_flexbits > flexbits_left) + flexbits_left = 0; + else + flexbits_left -= image->trim_flexbits; + + DEBUG(" BLOCK_FLEXBITS: flexbits_left=%u (model=%u, trim=%u) block=%u bitpos=%zu\n", + flexbits_left, model_bits, image->trim_flexbits, bl, _jxr_rbitstream_bitpos(str)); + if (flexbits_left > 0) { + int idx; + for (idx = 1; idx < 16; idx += 1) { + int idx_trans = transpose444[idx]; + r_DECODE_FLEX(image, str, tx, mx, ch, bl, idx_trans-1, flexbits_left); + } + } + DEBUG(" BLOCK_FLEXBITS done\n"); +} + +static int r_calculate_mbhp_mode(jxr_image_t image, int tx, int mx) +{ + long strength_hor = 0; + long strength_ver = 0; + const long orientation_weight = 4; + + /* Add up the LP magnitudes along the top edge */ + strength_hor += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 0)); + strength_hor += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 1)); + strength_hor += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 2)); + + /* Add up the LP magnitudes along the left edge */ + strength_ver += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 3)); + strength_ver += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 7)); + strength_ver += abs(MACROBLK_CUR_LP(image, 0, tx, mx, 11)); + + switch (image->use_clr_fmt) { + case 0: /*YONLY*/ + case 6: /*NCOMPONENT*/ + break; + case 3: /*YUV444*/ + case 4: /*YUVK */ + strength_hor += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 3)); + strength_ver += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 3)); + break; + case 2: /*YUV422*/ + strength_hor += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 1)); + strength_ver += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 1)); + strength_hor += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 4)); + strength_hor += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 4)); + strength_ver += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 5)); + strength_ver += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 5)); + break; + case 1: /*YUV420*/ + strength_hor += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_CUR_LP(image, 1, tx, mx, 1)); + strength_ver += abs(MACROBLK_CUR_LP(image, 2, tx, mx, 1)); + break; + default: + assert(0); + } + + if (strength_hor * orientation_weight < strength_ver) + return 0; /* predict from left */ + if (strength_ver * orientation_weight < strength_hor) + return 1; /* predict from top */ + + /* There is no strong weight from top or left, so do not + bother with prediction. */ + return 2; +} + + +/* +* This function does HP coefficient propagation within a completed +* macroblock. +*/ +void _jxr_propagate_hp_predictions(jxr_image_t image, int ch, unsigned tx, unsigned mx, + int mbhp_pred_mode) +{ + if (mbhp_pred_mode == 0) { /* Prediction left to right */ + int idx; + for (idx = 1 ; idx < 16 ; idx += 1) { + if (idx%4 == 0) + continue; + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,ch,tx,mx,idx, 3), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 7), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 11)); + MACROBLK_CUR_HP(image,ch,tx,mx,idx, 3) += MACROBLK_CUR_HP(image,ch,tx,mx,idx-1, 3); + MACROBLK_CUR_HP(image,ch,tx,mx,idx, 7) += MACROBLK_CUR_HP(image,ch,tx,mx,idx-1, 7); + MACROBLK_CUR_HP(image,ch,tx,mx,idx,11) += MACROBLK_CUR_HP(image,ch,tx,mx,idx-1,11); + +#if defined(DETAILED_DEBUG) + { + int k; + DEBUG(" HP val predicted(l)[ch=%d, tx=%u, mx=%d, block=%d] ==", ch, tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,ch,tx,mx,idx,k-1)); + } + DEBUG("\n"); + } +#endif + } + } else if (mbhp_pred_mode == 1) { /* Prediction top to bottom. */ + int idx; + for (idx = 4 ; idx < 16 ; idx += 1) { + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,ch,tx,mx,idx, 0), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 1), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 2)); + MACROBLK_CUR_HP(image,ch,tx,mx,idx,0) += MACROBLK_CUR_HP(image,ch,tx,mx, idx-4,0); + MACROBLK_CUR_HP(image,ch,tx,mx,idx,1) += MACROBLK_CUR_HP(image,ch,tx,mx, idx-4,1); + MACROBLK_CUR_HP(image,ch,tx,mx,idx,2) += MACROBLK_CUR_HP(image,ch,tx,mx, idx-4,2); +#if defined(DETAILED_DEBUG) + { + int k; + DEBUG(" HP val predicted(t)[ch=%d, tx=%u, mx=%d, block=%d] ==", ch, tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,ch,tx,mx,idx,k-1)); + } + DEBUG("\n"); + } +#endif + } + } + + switch (image->use_clr_fmt) { + case 1:/*YUV420*/ + assert(ch == 0); + if (mbhp_pred_mode == 0) { + int idx; + for (idx = 1 ; idx <= 3 ; idx += 2) { + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 3), MACROBLK_CUR_HP(image,1,tx,mx,idx, 7), MACROBLK_CUR_HP(image,1,tx,mx,idx, 11)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 3), MACROBLK_CUR_HP(image,2,tx,mx,idx, 7), MACROBLK_CUR_HP(image,2,tx,mx,idx, 11)); + MACROBLK_CUR_HP(image,1,tx,mx,idx,3) += MACROBLK_CUR_HP(image,1,tx,mx,idx-1,3); + MACROBLK_CUR_HP(image,2,tx,mx,idx,3) += MACROBLK_CUR_HP(image,2,tx,mx,idx-1,3); + MACROBLK_CUR_HP(image,1,tx,mx,idx,7) += MACROBLK_CUR_HP(image,1,tx,mx,idx-1,7); + MACROBLK_CUR_HP(image,2,tx,mx,idx,7) += MACROBLK_CUR_HP(image,2,tx,mx,idx-1,7); + MACROBLK_CUR_HP(image,1,tx,mx,idx,11)+= MACROBLK_CUR_HP(image,1,tx,mx,idx-1,11); + MACROBLK_CUR_HP(image,2,tx,mx,idx,11)+= MACROBLK_CUR_HP(image,2,tx,mx,idx-1,11); +#if defined(DETAILED_DEBUG) + int k; + DEBUG(" HP val predicted(l)[ch=1, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,1,tx,mx,idx,k-1)); + } + DEBUG("\n"); + DEBUG(" HP val predicted(l)[ch=2, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,2,tx,mx,idx,k-1)); + } + DEBUG("\n"); +#endif + } + } else if (mbhp_pred_mode == 1) { + int idx; + for (idx = 2; idx <= 3 ; idx += 1) { + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 0), MACROBLK_CUR_HP(image,1,tx,mx,idx, 1), MACROBLK_CUR_HP(image,1,tx,mx,idx, 2)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 0), MACROBLK_CUR_HP(image,2,tx,mx,idx, 1), MACROBLK_CUR_HP(image,2,tx,mx,idx, 2)); + MACROBLK_CUR_HP(image,1,tx,mx,idx,0) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,0); + MACROBLK_CUR_HP(image,2,tx,mx,idx,0) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,0); + MACROBLK_CUR_HP(image,1,tx,mx,idx,1) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,1); + MACROBLK_CUR_HP(image,2,tx,mx,idx,1) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,1); + MACROBLK_CUR_HP(image,1,tx,mx,idx,2) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,2); + MACROBLK_CUR_HP(image,2,tx,mx,idx,2) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,2); +#if defined(DETAILED_DEBUG) + int k; + DEBUG(" HP val predicted(t)[ch=1, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,1,tx,mx,idx,k-1)); + } + DEBUG("\n"); + DEBUG(" HP val predicted(t)[ch=2, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,2,tx,mx,idx,k-1)); + } + DEBUG("\n"); +#endif + } + } + break; + + case 2:/*YUV422*/ + assert(ch == 0); + if (mbhp_pred_mode == 0) { + int idx; + for (idx = 1 ; idx <= 7 ; idx += 2) { + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 3), MACROBLK_CUR_HP(image,1,tx,mx,idx, 7), MACROBLK_CUR_HP(image,1,tx,mx,idx, 11)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 3), MACROBLK_CUR_HP(image,2,tx,mx,idx, 7), MACROBLK_CUR_HP(image,2,tx,mx,idx, 11)); + MACROBLK_CUR_HP(image,1,tx,mx,idx,3) += MACROBLK_CUR_HP(image,1,tx,mx,idx-1,3); + MACROBLK_CUR_HP(image,2,tx,mx,idx,3) += MACROBLK_CUR_HP(image,2,tx,mx,idx-1,3); + MACROBLK_CUR_HP(image,1,tx,mx,idx,7) += MACROBLK_CUR_HP(image,1,tx,mx,idx-1,7); + MACROBLK_CUR_HP(image,2,tx,mx,idx,7) += MACROBLK_CUR_HP(image,2,tx,mx,idx-1,7); + MACROBLK_CUR_HP(image,1,tx,mx,idx,11)+= MACROBLK_CUR_HP(image,1,tx,mx,idx-1,11); + MACROBLK_CUR_HP(image,2,tx,mx,idx,11)+= MACROBLK_CUR_HP(image,2,tx,mx,idx-1,11); +#if defined(DETAILED_DEBUG) + int k; + DEBUG(" HP val predicted(l)[ch=1, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,1,tx,mx,idx,k-1)); + } + DEBUG("\n"); + DEBUG(" HP val predicted(l)[ch=2, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,2,tx,mx,idx,k-1)); + } + DEBUG("\n"); +#endif + } + } else if (mbhp_pred_mode == 1) { + int idx; + for (idx = 2; idx <= 7 ; idx += 1) { + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 0), MACROBLK_CUR_HP(image,1,tx,mx,idx, 1), MACROBLK_CUR_HP(image,1,tx,mx,idx, 2)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 0), MACROBLK_CUR_HP(image,2,tx,mx,idx, 1), MACROBLK_CUR_HP(image,2,tx,mx,idx, 2)); + MACROBLK_CUR_HP(image,1,tx,mx,idx,0) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,0); + MACROBLK_CUR_HP(image,2,tx,mx,idx,0) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,0); + MACROBLK_CUR_HP(image,1,tx,mx,idx,1) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,1); + MACROBLK_CUR_HP(image,2,tx,mx,idx,1) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,1); + MACROBLK_CUR_HP(image,1,tx,mx,idx,2) += MACROBLK_CUR_HP(image,1,tx,mx,idx-2,2); + MACROBLK_CUR_HP(image,2,tx,mx,idx,2) += MACROBLK_CUR_HP(image,2,tx,mx,idx-2,2); +#if defined(DETAILED_DEBUG) + int k; + DEBUG(" HP val predicted(t)[ch=1, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,1,tx,mx,idx,k-1)); + } + DEBUG("\n"); + DEBUG(" HP val predicted(t)[ch=2, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_HP(image,2,tx,mx,idx,k-1)); + } + DEBUG("\n"); +#endif + } + } + break; + + default: + break; + } +} + + +/* +* Code IS_DC_YUV +* 10 0 +* 001 1 +* 00001 2 +* 0001 3 +* 11 4 +* 010 5 +* 00000 6 +* 011 7 +*/ +static int get_is_dc_yuv(struct rbitstream*str) +{ + if (_jxr_rbitstream_uint1(str) == 1) { /* 1... */ + if (_jxr_rbitstream_uint1(str) == 1) /* 11 */ + return 4; + else /* 10 */ + return 0; + } + else { + switch (_jxr_rbitstream_uint2(str)) { /* 1... */ + case 0: /* 000... */ + if (_jxr_rbitstream_uint1(str) == 1) /* 0001 */ + return 3; + else if (_jxr_rbitstream_uint1(str) == 1) /* 00001 */ + return 2; + else /* 00000 */ + return 6; + case 1: /* 001 */ + return 1; + + case 2: /* 010 */ + return 5; + + case 3: /* 011 */ + return 7; + } + } + + assert(0); /* Should not get here. */ + return -1; +} + +/* +* table0 table1 value +* 1 1 0 +* 01 000 1 +* 001 001 2 +* 0000 010 3 +* 0001 011 4 +*/ +static int get_num_cbp(struct rbitstream*str, struct adaptive_vlc_s*vlc) +{ + assert(vlc->table < 2); + + if (_jxr_rbitstream_uint1(str) == 1) + return 0; + + if (vlc->table == 0) { + if (_jxr_rbitstream_uint1(str) == 1) + return 1; + if (_jxr_rbitstream_uint1(str) == 1) + return 2; + if (_jxr_rbitstream_uint1(str) == 1) + return 4; + else + return 3; + } else { + uint8_t tmp = _jxr_rbitstream_uint2(str); + return tmp + 1; + } +} + +static int get_num_blkcbp(jxr_image_t image, struct rbitstream*str, +struct adaptive_vlc_s*vlc) +{ + switch (image->use_clr_fmt) { + case 0: /*YONLY*/ + case 4: /*YUVK*/ + case 6: /*NCOMPONENT*/ + /* + * table0 table1 value + * 1 1 0 + * 01 000 1 + * 001 001 2 + * 0000 010 3 + * 0001 011 4 + * + * NOTE that this is exactly the same table as for + * NUM_CBP above. + */ + return get_num_cbp(str, vlc); + + default: + /* + * table0 table1 value + * 010 1 0 + * 00000 001 1 + * 0010 010 2 + * 00001 0001 3 + * 00010 000001 4 + * 1 011 5 + * 011 00001 6 + * 00011 0000000 7 + * 0011 0000001 8 + */ + if (vlc->table == 0) { + static const unsigned char codeb[32] = { + 5, 5, 5, 5, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, /* 1xxxx */ + 1, 1, 1, 1, 1, 1, 1, 1 + }; + static const signed char codev[32] = { + 1, 3, 4, 7, 2, 2, 8, 8, + 0, 0, 0, 0, 6, 6, 6, 6, + 5, 5, 5, 5, 5, 5, 5, 5, + 5, 5, 5, 5, 5, 5, 5, 5 + }; + return _jxr_rbitstream_intE(str, 5, codeb, codev); + } else { + static const unsigned char codeb[64] = { + 6, 6, 5, 5, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 3, 3, 3, 3, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 + }; + static const signed char codev[64] = { + 7, 4, 6, 6, 3, 3, 3, 3, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 5, 5, 5, 5, 5, 5, 5, 5, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 + }; + int tmp = _jxr_rbitstream_intE(str, 6, codeb, codev); + if (tmp == 7) tmp += _jxr_rbitstream_uint1(str); + return tmp; + } + } +} + + + +/* +* value table0 table1 +* 0 01 1 +* 1 10 01 +* 2 11 001 +* 3 001 0001 +* 4 0001 00001 +* 5 00000 000000 +* 6 00001 000001 +*/ +static const unsigned char abslevel_code0b[64] = { + 5, 5, 5, 5, 4, 4, 4, 4, /* 00000x, 00001x, 0001xx */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 001xxx */ + 2, 2, 2, 2, 2, 2, 2, 2, /* 01xxxx */ + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, /* 10xxxx */ + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2, /* 11xxxx */ + 2, 2, 2, 2, 2, 2, 2, 2 +}; +static const signed char abslevel_code0v[64] = { + 5, 5, 6, 6, 4, 4, 4, 4, + 3, 3, 3, 3, 3, 3, 3, 3, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 2, 2, 2, 2, 2, 2, 2, 2, + 2, 2, 2, 2, 2, 2, 2, 2 +}; + +static const unsigned char abslevel_code1b[64] = { + 6, 6, 5, 5, 4, 4, 4, 4, /* 000000, 000001, 00001x, 0001xx */ + 3, 3, 3, 3, 3, 3, 3, 3, /* 001xxx */ + 2, 2, 2, 2, 2, 2, 2, 2, /* 01xxxx */ + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, /* 1xxxxx */ + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1 +}; +static const signed char abslevel_code1v[64] = { + 5, 6, 4, 4, 3, 3, 3, 3, + 2, 2, 2, 2, 2, 2, 2, 2, + 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0, + 0, 0, 0, 0, 0, 0, 0, 0 +}; + +static int dec_abslevel_index(jxr_image_t image, struct rbitstream*str, int vlc_select) +{ + const unsigned char*codeb = image->vlc_table[vlc_select].table? abslevel_code1b :abslevel_code0b; + const signed char*codev = image->vlc_table[vlc_select].table? abslevel_code1v : abslevel_code0v; + + return _jxr_rbitstream_intE(str, 6, codeb, codev); +} + +static int dec_cbp_yuv_lp1(jxr_image_t image, struct rbitstream*str) +{ + static const unsigned char codeb[16] = { + 1, 1, 1, 1, + 1, 1, 1, 1, + 3, 3, 4, 4, + 4, 4, 4, 4 }; + static const signed char codev[16] = { + 0, 0, 0, 0, + 0, 0, 0, 0, + 1, 1, 2, 3, + 4, 5, 6, 7 }; + + switch (image->use_clr_fmt) { + case 3: /* YUV444 */ + return _jxr_rbitstream_intE(str, 4, codeb, codev); + case 1: /* YUV420 */ + case 2: /* YUV422 */ + if (_jxr_rbitstream_uint1(str) == 0) { + return 0; + + } else if (_jxr_rbitstream_uint1(str) == 0) { + return 1; + + } else if (_jxr_rbitstream_uint1(str) == 0) { + return 2; + + } else { + return 3; + } + default: + assert(0); + return 0; + } +} + +/* +* Bits Value +* 1 0 +* 01 1 +* 00 2 +*/ +static int get_value_012(struct rbitstream*str) +{ + if (_jxr_rbitstream_uint1(str) == 1) + return 0; + else if ( _jxr_rbitstream_uint1(str) == 1) + return 1; + else + return 2; +} + +/* +* Bits Value +* 1 0 +* 01 1 +* 000 2 +* 001 3 +*/ +static int get_num_ch_blk(struct rbitstream*str) +{ + if (_jxr_rbitstream_uint1(str) == 1) + return 0; + if (_jxr_rbitstream_uint1(str) == 1) + return 1; + if (_jxr_rbitstream_uint1(str) == 1) + return 3; + else + return 2; +} + +/* +* $Log: r_parse.c,v $ +* Revision 1.41 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.40 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.39 2008/03/24 18:06:56 steve +* Imrpove DEBUG messages around quantization. +* +* Revision 1.38 2008/03/21 18:30:21 steve +* Get HP Prediction right for YUVK (CMYK) +* +* Revision 1.37 2008/03/20 22:39:41 steve +* Fix various debug prints of QP data. +* +* Revision 1.36 2008/03/17 21:48:55 steve +* CMYK decode support +* +* Revision 1.35 2008/03/13 21:23:27 steve +* Add pipeline step for YUV420. +* +* Revision 1.34 2008/03/13 00:07:22 steve +* Encode HP of YUV422 +* +* Revision 1.33 2008/03/06 22:47:39 steve +* Clean up parsing/encoding of QP counts +* +* Revision 1.32 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.31 2008/03/05 04:04:30 steve +* Clarify constraints on USE_DC_QP in image plane header. +* +* Revision 1.30 2008/03/05 00:31:17 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.29 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.28 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.27 2008/02/23 01:55:51 steve +* CBP REFINE is more complex when CHR is involved. +* +* Revision 1.26 2008/02/22 23:01:33 steve +* Compress macroblock HP CBP packets. +* +* Revision 1.25 2008/01/01 01:07:26 steve +* Add missing HP prediction. +* +* Revision 1.24 2007/12/30 00:16:00 steve +* Add encoding of HP values. +* +* Revision 1.23 2007/12/13 18:01:09 steve +* Stubs for HP encoding. +* +* Revision 1.22 2007/12/12 00:37:33 steve +* Cleanup some debug messages. +* +* Revision 1.21 2007/12/06 23:12:41 steve +* Stubs for LP encode operations. +* +* Revision 1.20 2007/12/06 17:54:09 steve +* UpdateModelMB dump details. +* +* Revision 1.19 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.18 2007/11/21 00:34:30 steve +* Rework spatial mode tile macroblock shuffling. +* +* Revision 1.17 2007/11/20 00:05:47 steve +* Complex handling of mbhp_pred_mode in frequency dmoe. +* +* Revision 1.16 2007/11/19 18:22:34 steve +* Skip ESCaped FLEXBITS tiles. +* +* Revision 1.15 2007/11/16 20:03:57 steve +* Store MB Quant, not qp_index. +* +* Revision 1.14 2007/11/16 17:33:24 steve +* Do HP prediction after FLEXBITS frequency tiles. +* +* Revision 1.13 2007/11/16 00:29:05 steve +* Support FREQUENCY mode HP and FLEXBITS +* +* Revision 1.12 2007/11/14 23:56:17 steve +* Fix TILE ordering, using seeks, for FREQUENCY mode. +* +* Revision 1.11 2007/11/14 00:17:26 steve +* Fix parsing of QP indices. +* +* Revision 1.10 2007/11/13 03:27:23 steve +* Add Frequency mode LP support. +* +* Revision 1.9 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +* Revision 1.8 2007/11/08 19:38:38 steve +* Get stub DCONLY compression to work. +* +* Revision 1.7 2007/11/01 21:09:40 steve +* Multiple rows of tiles. +* +* Revision 1.6 2007/10/30 21:32:46 steve +* Support for multiple tile columns. +* +* Revision 1.5 2007/09/08 01:01:43 steve +* YUV444 color parses properly. +* +* Revision 1.4 2007/07/30 23:09:57 steve +* Interleave FLEXBITS within HP block. +* +* Revision 1.3 2007/07/24 20:56:28 steve +* Fix HP prediction and model bits calculations. +* +* Revision 1.2 2007/06/07 18:53:06 steve +* Parse HP coeffs that are all 0. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/r_strip.c b/jpegxr/r_strip.c new file mode 100644 index 000000000..856c41ea8 --- /dev/null +++ b/jpegxr/r_strip.c @@ -0,0 +1,2774 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: r_strip.c,v 1.51 2008/03/24 18:06:56 steve Exp $") +#else +#ident "$Id: r_strip.c,v 1.51 2008/03/24 18:06:56 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <limits.h> +# include <assert.h> +# include <math.h> +# include <memory.h> + +static void dclphp_shuffle(int*data, int dclp_count); +static void unblock_shuffle444(int*data); +static void unblock_shuffle422(int*data); +static void unblock_shuffle420(int*data); + +static void dequantize_up_dclp(jxr_image_t image, int use_my, int ch) +{ + int tx, ty = 0; + int dc_quant = 0; + unsigned int strip; + unsigned int i; + + int lp_coeff_count = 16; + if (ch > 0) { + if (image->use_clr_fmt == 2/*YUV422*/) + lp_coeff_count = 8; + else if (image->use_clr_fmt == 1/*YUV420*/) + lp_coeff_count = 4; + } + + strip = use_my -1; + for(i=0; i < image->tile_rows; i++) + { + /* Figure out what ty is */ + if(strip >= image->tile_row_position[i] && strip <image->tile_row_position[i] + image->tile_row_height[i]) + { + ty = i; + break; + } + } + + /* The current "cur" is now made up into DC coefficients, so + we no longer need the strip_up levels. Dequantize them, + inverse tranform then and deliver them to output. */ + for (tx = 0 ; tx < (int) image->tile_columns ; tx += 1) { + int mx; + if(image->dc_frame_uniform) + dc_quant = image->dc_quant_ch[ch]; + else + dc_quant = image->tile_quant[ty *(image->tile_columns) + tx].dc_quant_ch[ch]; + dc_quant = _jxr_quant_map(image, dc_quant, ch==0? 1 : 0/* iShift for YONLY */); + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int lp_quant_idx = MACROBLK_UP1_LP_QUANT(image,ch,tx,mx); + int k; + int lp_quant_use; + + int lp_quant_raw = 0; + if(image->lp_frame_uniform) + lp_quant_raw = image->lp_quant_ch[ch][lp_quant_idx]; + else + lp_quant_raw = image->tile_quant[ty *(image->tile_columns) + tx].lp_quant_ch[ch][lp_quant_idx]; + + lp_quant_use = _jxr_quant_map(image, lp_quant_raw, ch==0? 1 : 0/* iShift for YONLY */); + MACROBLK_UP_DC(image,ch,tx,mx) *= dc_quant; + CHECK1(image->lwf_test, MACROBLK_CUR_DC(image,ch,tx,mx)); + + DEBUG(" Dequantize strip=%d tx=%d MBx=%d ch=%d with lp_quant=%d lp_quant_use=%d\n", + use_my-1, tx, mx, ch, lp_quant_raw, lp_quant_use); + for (k = 1 ; k < lp_coeff_count ; k += 1) + { + MACROBLK_UP_LP(image,ch,tx,mx,k-1) *= lp_quant_use; + CHECK1(image->lwf_test, MACROBLK_UP_LP(image,ch,tx,mx,k-1)); + } + } + } + +#if defined(DETAILED_DEBUG) + for (tx = 0 ; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int jdx; + DEBUG(" DC/LP (strip=%3d, tx=%d mbx=%4d, ch=%d) Dequant:", use_my-1, tx, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < lp_coeff_count-1 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != (lp_coeff_count-2)) + DEBUG("\n%*s:", 48, ""); + } + DEBUG("\n"); + } + } +#endif +} + + +static void IPCT_level1_up1(jxr_image_t image, int use_my, int ch) +{ + int idx; + + dequantize_up_dclp(image, use_my, ch); + + DEBUG(" DC-LP IPCT transforms (first level) for strip %d channel %d\n", use_my-1, ch); + + /* Reverse transform the DC/LP to 16 DC values. */ + + for (idx = 0 ; idx < (int) EXTENDED_WIDTH_BLOCKS(image); idx += 1) { + DEBUG(" DC-LP IPCT transforms for mb[%d %d]\n", idx, use_my-1); + + if (ch > 0 && image->use_clr_fmt == 1/*YUV420*/) { + + _jxr_2x2IPCT(image->strip[ch].up1[idx].data+0); + _jxr_InvPermute2pt(image->strip[ch].up1[idx].data+1, + image->strip[ch].up1[idx].data+2); + + /* Scale up the chroma channel */ + if (image->scaled_flag) { + int jdx; + for (jdx = 0 ; jdx < 4 ; jdx += 1) + image->strip[ch].up1[idx].data[jdx] *= 2; + } + +#if defined(DETAILED_DEBUG) + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) IPCT:", use_my-1, idx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,idx)); + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,0)); + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,1)); + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,2)); + DEBUG("\n"); +#endif + } else if (ch > 0 && image->use_clr_fmt == 2/*YUV422*/) { +#if defined(DETAILED_DEBUG) + int jdx; + DEBUG(" DC/LP scaled_flag=%d\n", image->scaled_flag); + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Pre-IPCT:", use_my-1, idx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,idx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 44, ""); + } + DEBUG("\n"); +#endif + + _jxr_2ptT(image->strip[ch].up1[idx].data+0, + image->strip[ch].up1[idx].data+4); + _jxr_2x2IPCT(image->strip[ch].up1[idx].data+0); + _jxr_2x2IPCT(image->strip[ch].up1[idx].data+4); + + _jxr_InvPermute2pt(image->strip[ch].up1[idx].data+1, + image->strip[ch].up1[idx].data+2); + _jxr_InvPermute2pt(image->strip[ch].up1[idx].data+5, + image->strip[ch].up1[idx].data+6); + +#if defined(DETAILED_DEBUG) + DEBUG(" DC/LP scaled_flag=%d\n", image->scaled_flag); + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) scaled:", use_my-1, idx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,idx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 42, ""); + } + DEBUG("\n"); +#endif + /* Scale up the chroma channel */ + if (image->scaled_flag) { + int jdx; + for (jdx = 0 ; jdx < 8 ; jdx += 1) + image->strip[ch].up1[idx].data[jdx] *= 2; + } + +#if defined(DETAILED_DEBUG) + DEBUG(" DC/LP scaled_flag=%d\n", image->scaled_flag); + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) IPCT:", use_my-1, idx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,idx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 40, ""); + } + DEBUG("\n"); +#endif + } else { + + /* Channel 0 of everything, and Channel-N of full + resolution colors, are processed here. */ + _jxr_4x4IPCT(image->strip[ch].up1[idx].data); + + /* Scale up the chroma channel */ + if (ch > 0 && image->scaled_flag) { + int jdx; + for (jdx = 0 ; jdx < 16 ; jdx += 1) + image->strip[ch].up1[idx].data[jdx] *= 2; + } + +#if defined(DETAILED_DEBUG) + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) IPCT:", use_my-1, idx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,idx)); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,0,idx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 40, ""); + } + DEBUG("\n"); +#endif + } + + } + +} + +static void IPCT_level2_up2(jxr_image_t image, int use_my, int ch) +{ + int idx; + + for (idx = 0 ; idx < (int) EXTENDED_WIDTH_BLOCKS(image); idx += 1) { + int jdx; + /* Reshuffle the DCLP with the HP data to get + DC-LP stretches in the data stream. */ + int dclp_count = 16; + int hp_quant_raw; + int hp_quant; + + if (ch>0 && image->use_clr_fmt == 2/*YUV422*/) + dclp_count = 8; + else if (ch>0 && image->use_clr_fmt == 1/*YUV420*/) + dclp_count = 4; + + dclphp_shuffle(image->strip[ch].up2[idx].data, dclp_count); + + DEBUG(" DC-LP-HP IPCT transforms for (second level) strip %d MBx=%d ch=%d\n", + use_my-2, idx, ch); + + hp_quant_raw = MACROBLK_UP2_HP_QUANT(image,ch,0,idx); + hp_quant = _jxr_quant_map(image, hp_quant_raw, 1); + + /* IPCT transform to absorb HP band data. */ + for (jdx = 0 ; jdx < 16*dclp_count ; jdx += 16) { + int k; +#if defined(DETAILED_DEBUG) + { + int pix; + DEBUG(" DC-LP-HP (strip=%3d, mbx=%4d ch=%d, block=%2d) pre-IPCT:", + use_my-2, idx, ch, jdx/16); + for (pix = 0; pix < 16 ; pix += 1) { + DEBUG(" 0x%08x", image->strip[ch].up2[idx].data[jdx+pix]); + if (pix%4 == 3 && pix != 15) + DEBUG("\n%*s:", 56, ""); + } + DEBUG("\n"); + } +#endif + DEBUG(" Dequantize strip=%d MBx=%d ch=%d block=%d with hp_quant=%d (raw=%d)\n", + use_my-2, idx, ch, jdx/16, hp_quant, hp_quant_raw); + for (k = 1 ; k < 16 ; k += 1) + { + image->strip[ch].up2[idx].data[jdx+k] *= hp_quant; + CHECK1(image->lwf_test, image->strip[ch].up2[idx].data[jdx+k]); + } + + _jxr_4x4IPCT(image->strip[ch].up2[idx].data+jdx); +#if defined(DETAILED_DEBUG) + { + int pix; + DEBUG(" DC-LP-HP (strip=%3d, mbx=%4d ch=%d block=%2d) IPCT:", + use_my-2, idx, ch, jdx/16); + for (pix = 0; pix < 16 ; pix += 1) { + DEBUG(" 0x%08x", image->strip[ch].up2[idx].data[jdx+pix]); + if (pix%4 == 3 && pix != 15) + DEBUG("\n%*s:", 51, ""); + } + DEBUG("\n"); + } +#endif + } + + } +} + +#define TOP_Y(y) ( y == image->tile_row_position[ty]) +#define BOTTOM_Y(y) ( y == image->tile_row_position[ty] + image->tile_row_height[ty] - 1) +#define LEFT_X(idx) ( idx == 0) +#define RIGHT_X(idx) ( idx == image->tile_column_width[tx] -1 ) + + +static void overlap_level1_up2_444(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 2; + int idx; + + int ty = 0; + /* 16 Coeffs per MB */ + assert(ch == 0 || (image->use_clr_fmt != 2/*YUV422*/ && image->use_clr_fmt !=1/* YUV420*/)); + assert(use_my >= 2); + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Overlap filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx-1).data; /* Macroblock to the right */ + + _jxr_4OverlapFilter(tp1+2, tp1+3, tp0+0, tp0+1); + _jxr_4OverlapFilter(tp1+6, tp1+7, tp0+4, tp0+5); + } + } + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4OverlapFilter(tp0+0, tp0+1, tp0+4, tp0+5); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4OverlapFilter(tp0+2, tp0+3, tp0+6, tp0+7); + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(tp1+10, tp1+11, tp0+8, tp0+9); + _jxr_4OverlapFilter(tp1+14, tp1+15, tp0+12, tp0+13); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4OverlapFilter(tp0+8, tp0+9, tp0+12, tp0+13); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4OverlapFilter(tp0+10, tp0+11, tp0+14, tp0+15); + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + int*up0 = MACROBLK_UP1(image,ch,tx,0).data; + + /* Left edge Across Vertical MBs */ + _jxr_4OverlapFilter(tp0+8, tp0+12, up0+0, up0+4); + _jxr_4OverlapFilter(tp0+9, tp0+13, up0+1, up0+5); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*up1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + + /* MB below, right, right-below */ + _jxr_4x4OverlapFilter(tp0+10, tp0+11, tp1+ 8, tp1+ 9, + tp0+14, tp0+15, tp1+12, tp1+13, + up0+ 2, up0+ 3, up1+ 0, up1+ 1, + up0+ 6, up0+ 7, up1+ 4, up1+ 5); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + + /* Right edge Across Vertical MBs */ + _jxr_4OverlapFilter(tp0+10, tp0+14, up0+2, up0+6); + _jxr_4OverlapFilter(tp0+11, tp0+15, up0+3, up0+7); + } + } + } + } +} + +/* +*/ + +static void overlap_level1_up2_422(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 2; + int idx; + + int ty = 0; + assert(ch > 0 && image->use_clr_fmt == 2/*YUV422*/); + assert(use_my >= 2); + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Difference */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[0] = tp0[0] -tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Difference */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] - tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Difference */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[6] = tp0[6] -tp0[7]; + CHECK1(image->lwf_test, tp0[6]); + } + /* Bottom Right Corner Difference */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[7] = tp0[7] - tp0[6]; + CHECK1(image->lwf_test, tp0[7]); + } + } + } + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + /* Interior left edge */ + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_2OverlapFilter(tp0+2, tp0+4); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + /* Interior Right edge */ + _jxr_2OverlapFilter(tp0+3, tp0+5); + } + + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Overlap filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx-1).data; /* The macroblock to the right */ + + _jxr_2OverlapFilter(tp1+1, tp0+0); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx - 1).data; + _jxr_2OverlapFilter(tp1+7, tp0+6); + } + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + if(top_my< EXTENDED_HEIGHT_BLOCKS(image) -1) + { + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + int*up0 = MACROBLK_UP1(image,ch,tx,0).data; + + /* Left edge across vertical MBs */ + _jxr_2OverlapFilter(tp0+6, up0+0); + } + + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + + /* Right edge across MBs */ + _jxr_2OverlapFilter(tp0+7, up0+1); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*up1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + + /* MB below, right, right-below */ + _jxr_2x2OverlapFilter(tp0+7, tp1+6, up0+1, up1+0); + } + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx+1).data; + + /* MB to the right */ + _jxr_2x2OverlapFilter(tp0+3, tp1+2, tp0+5, tp1+4); + } + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[0] = tp0[0] + tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] + tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[6] = tp0[6] + tp0[7]; + CHECK1(image->lwf_test, tp0[6]); + } + /* Bottom Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[7] = tp0[7] + tp0[6]; + CHECK1(image->lwf_test, tp0[7]); + } + } + } +} + +static void overlap_level1_up2_420(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 2; + + int idx; + int ty = 0; + /* 4 coeffs*/ + assert(ch > 0 && image->use_clr_fmt == 1/*YUV420*/); + assert(use_my >= 2); + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Difference*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[0] = tp0[0] -tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Difference*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] - tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Difference*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[2] = tp0[2] -tp0[3]; + CHECK1(image->lwf_test, tp0[2]); + } + /* Bottom Right Corner Difference*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[3] = tp0[3] - tp0[2]; + CHECK1(image->lwf_test, tp0[3]); + } + } + } + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_2OverlapFilter(tp1+1, tp0+0); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_2OverlapFilter(tp1+3, tp0+2); + } + } + } + else + { + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Left edge across vertical MBs */ + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + int*up0 = MACROBLK_UP1(image,ch,tx,0).data; + + _jxr_2OverlapFilter(tp0+2, up0+0); + } + + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Right edge across vertical MBs */ + int*tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + + _jxr_2OverlapFilter(tp0+3, up0+1); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + /* MB below, right, right-below */ + int*tp0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*up1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + + _jxr_2x2OverlapFilter(tp0+3, tp1+2, + up0+1, up1+0); + } + } + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[0] = tp0[0] + tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] + tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Addition*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP2(image,ch,tx,0).data; + tp0[2] = tp0[2] + tp0[3]; + CHECK1(image->lwf_test, tp0[2]); + } + /* Bottom Right Corner Addition*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[3] = tp0[3] + tp0[2]; + CHECK1(image->lwf_test, tp0[3]); + } + } + } +} + + +static void overlap_level1_up2(jxr_image_t image, int use_my, int ch) +{ + if (ch == 0) { + overlap_level1_up2_444(image, use_my, ch); + + } + else { + switch (image->use_clr_fmt) { + case 1: /*YUV420*/ + overlap_level1_up2_420(image, use_my, ch); + break; + case 2: /*YUV422*/ + overlap_level1_up2_422(image, use_my, ch); + break; + default: + overlap_level1_up2_444(image, use_my, ch); + break; + } + } +} + +static int*R2B(int*data, int x, int y) +{ + int bx = x/4; + int by = y/4; + int bl = by*4 + bx; + return data + bl*16 + 4*(y%4) + x%4; +} + +static int*R2B42(int*data, int x, int y) +{ + int bx = x/4; + int by = y/4; + int bl = by*2 + bx; + return data + bl*16 + 4*(y%4) + x%4; +} + +static void overlap_level2_up3_444(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 3; + int idx; + int ty = 0; + + assert(ch == 0 || (image->use_clr_fmt != 2/*YUV422*/ && image->use_clr_fmt !=1/* YUV420*/)); + assert(use_my >= 3); + DEBUG("Overlap Level2 for row %d\n", top_my); + + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + for(tx = 0; tx < image->tile_columns; tx++) + { + int jdx; + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP3(image,ch,tx,0).data; + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + _jxr_4OverlapFilter(R2B(dp,0,jdx+0),R2B(dp,0,jdx+1),R2B(dp,0,jdx+2),R2B(dp,0,jdx+3)); + _jxr_4OverlapFilter(R2B(dp,1,jdx+0),R2B(dp,1,jdx+1),R2B(dp,1,jdx+2),R2B(dp,1,jdx+3)); + } + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + int*dp = MACROBLK_UP3(image,ch,tx,image->tile_column_width[tx]-1).data; + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + _jxr_4OverlapFilter(R2B(dp,14,jdx+0),R2B(dp,14,jdx+1),R2B(dp,14,jdx+2),R2B(dp,14,jdx+3)); + _jxr_4OverlapFilter(R2B(dp,15,jdx+0),R2B(dp,15,jdx+1),R2B(dp,15,jdx+2),R2B(dp,15,jdx+3)); + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Overlap filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + _jxr_4OverlapFilter(R2B(dp, 2,0),R2B(dp, 3,0),R2B(dp, 4,0),R2B(dp, 5,0)); + _jxr_4OverlapFilter(R2B(dp, 6,0),R2B(dp, 7,0),R2B(dp, 8,0),R2B(dp, 9,0)); + _jxr_4OverlapFilter(R2B(dp,10,0),R2B(dp,11,0),R2B(dp,12,0),R2B(dp,13,0)); + + _jxr_4OverlapFilter(R2B(dp, 2,1),R2B(dp, 3,1),R2B(dp, 4,1),R2B(dp, 5,1)); + _jxr_4OverlapFilter(R2B(dp, 6,1),R2B(dp, 7,1),R2B(dp, 8,1),R2B(dp, 9,1)); + _jxr_4OverlapFilter(R2B(dp,10,1),R2B(dp,11,1),R2B(dp,12,1),R2B(dp,13,1)); + + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B(pp,14,0),R2B(pp,15,0),R2B(dp,0,0),R2B(dp,1,0)); + _jxr_4OverlapFilter(R2B(pp,14,1),R2B(pp,15,1),R2B(dp,0,1),R2B(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch, tx, 0).data; + _jxr_4OverlapFilter(R2B(dp, 0,0),R2B(dp, 1,0),R2B(dp, 0,1),R2B(dp, 1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B(dp, 14,0),R2B(dp, 15,0),R2B(dp, 14,1),R2B(dp, 15,1)); + } + + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP3(image,ch,tx,idx).data; + + _jxr_4OverlapFilter(R2B(tp, 2,14),R2B(tp, 3,14),R2B(tp, 4,14),R2B(tp, 5,14)); + _jxr_4OverlapFilter(R2B(tp, 6,14),R2B(tp, 7,14),R2B(tp, 8,14),R2B(tp, 9,14)); + _jxr_4OverlapFilter(R2B(tp,10,14),R2B(tp,11,14),R2B(tp,12,14),R2B(tp,13,14)); + + _jxr_4OverlapFilter(R2B(tp, 2,15),R2B(tp, 3,15),R2B(tp, 4,15),R2B(tp, 5,15)); + _jxr_4OverlapFilter(R2B(tp, 6,15),R2B(tp, 7,15),R2B(tp, 8,15),R2B(tp, 9,15)); + _jxr_4OverlapFilter(R2B(tp,10,15),R2B(tp,11,15),R2B(tp,12,15),R2B(tp,13,15)); + + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tn = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B(tn,14,14),R2B(tn,15,14),R2B(tp, 0,14),R2B(tp, 1,14)); + _jxr_4OverlapFilter(R2B(tn,14,15),R2B(tn,15,15),R2B(tp, 0,15),R2B(tp, 1,15)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B(dp, 0,14),R2B(dp, 1, 14),R2B(dp, 0,15),R2B(dp, 1, 15)); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B(dp, 14, 14),R2B(dp, 15, 14),R2B(dp, 14,15),R2B(dp, 15, 15)); + } + + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + int jdx; + + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4OverlapFilter(R2B(dp, 2,jdx+0),R2B(dp, 3,jdx+0),R2B(dp, 4,jdx+0),R2B(dp, 5,jdx+0), + R2B(dp, 2,jdx+1),R2B(dp, 3,jdx+1),R2B(dp, 4,jdx+1),R2B(dp, 5,jdx+1), + R2B(dp, 2,jdx+2),R2B(dp, 3,jdx+2),R2B(dp, 4,jdx+2),R2B(dp, 5,jdx+2), + R2B(dp, 2,jdx+3),R2B(dp, 3,jdx+3),R2B(dp, 4,jdx+3),R2B(dp, 5,jdx+3)); + _jxr_4x4OverlapFilter(R2B(dp, 6,jdx+0),R2B(dp, 7,jdx+0),R2B(dp, 8,jdx+0),R2B(dp, 9,jdx+0), + R2B(dp, 6,jdx+1),R2B(dp, 7,jdx+1),R2B(dp, 8,jdx+1),R2B(dp, 9,jdx+1), + R2B(dp, 6,jdx+2),R2B(dp, 7,jdx+2),R2B(dp, 8,jdx+2),R2B(dp, 9,jdx+2), + R2B(dp, 6,jdx+3),R2B(dp, 7,jdx+3),R2B(dp, 8,jdx+3),R2B(dp, 9,jdx+3)); + _jxr_4x4OverlapFilter(R2B(dp,10,jdx+0),R2B(dp,11,jdx+0),R2B(dp,12,jdx+0),R2B(dp,13,jdx+0), + R2B(dp,10,jdx+1),R2B(dp,11,jdx+1),R2B(dp,12,jdx+1),R2B(dp,13,jdx+1), + R2B(dp,10,jdx+2),R2B(dp,11,jdx+2),R2B(dp,12,jdx+2),R2B(dp,13,jdx+2), + R2B(dp,10,jdx+3),R2B(dp,11,jdx+3),R2B(dp,12,jdx+3),R2B(dp,13,jdx+3)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) { + /* 4x4 at the right */ + int*np = MACROBLK_UP3(image,ch,tx,idx+1).data; + + _jxr_4x4OverlapFilter(R2B(dp,14,jdx+0),R2B(dp,15,jdx+0),R2B(np, 0,jdx+0),R2B(np, 1,jdx+0), + R2B(dp,14,jdx+1),R2B(dp,15,jdx+1),R2B(np, 0,jdx+1),R2B(np, 1,jdx+1), + R2B(dp,14,jdx+2),R2B(dp,15,jdx+2),R2B(np, 0,jdx+2),R2B(np, 1,jdx+2), + R2B(dp,14,jdx+3),R2B(dp,15,jdx+3),R2B(np, 0,jdx+3),R2B(np, 1,jdx+3)); + } + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + int*up = MACROBLK_UP2(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + _jxr_4OverlapFilter(R2B(dp,0,14),R2B(dp,0,15),R2B(up,0,0),R2B(up,0,1)); + _jxr_4OverlapFilter(R2B(dp,1,14),R2B(dp,1,15),R2B(up,1,0),R2B(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + /* 4x4 bottom */ + _jxr_4x4OverlapFilter(R2B(dp, 2,14),R2B(dp, 3,14),R2B(dp, 4,14),R2B(dp, 5,14), + R2B(dp, 2,15),R2B(dp, 3,15),R2B(dp, 4,15),R2B(dp, 5,15), + R2B(up, 2, 0),R2B(up, 3, 0),R2B(up, 4, 0),R2B(up, 5, 0), + R2B(up, 2, 1),R2B(up, 3, 1),R2B(up, 4, 1),R2B(up, 5, 1)); + _jxr_4x4OverlapFilter(R2B(dp, 6,14),R2B(dp, 7,14),R2B(dp, 8,14),R2B(dp, 9,14), + R2B(dp, 6,15),R2B(dp, 7,15),R2B(dp, 8,15),R2B(dp, 9,15), + R2B(up, 6, 0),R2B(up, 7, 0),R2B(up, 8, 0),R2B(up, 9, 0), + R2B(up, 6, 1),R2B(up, 7, 1),R2B(up, 8, 1),R2B(up, 9, 1)); + _jxr_4x4OverlapFilter(R2B(dp,10,14),R2B(dp,11,14),R2B(dp,12,14),R2B(dp,13,14), + R2B(dp,10,15),R2B(dp,11,15),R2B(dp,12,15),R2B(dp,13,15), + R2B(up,10, 0),R2B(up,11, 0),R2B(up,12, 0),R2B(up,13, 0), + R2B(up,10, 1),R2B(up,11, 1),R2B(up,12, 1),R2B(up,13, 1)); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right */ + int*dn = MACROBLK_UP3(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP2(image,ch,tx,idx+1).data; + + /* 4x4 on right, below, below-right */ + _jxr_4x4OverlapFilter(R2B(dp,14,14),R2B(dp,15,14),R2B(dn, 0,14),R2B(dn, 1,14), + R2B(dp,14,15),R2B(dp,15,15),R2B(dn, 0,15),R2B(dn, 1,15), + R2B(up,14, 0),R2B(up,15, 0),R2B(un, 0, 0),R2B(un, 1, 0), + R2B(up,14, 1),R2B(up,15, 1),R2B(un, 0, 1),R2B(un, 1, 1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Across vertical blocks, right edge */ + _jxr_4OverlapFilter(R2B(dp,14,14),R2B(dp,14,15),R2B(up,14,0),R2B(up,14,1)); + _jxr_4OverlapFilter(R2B(dp,15,14),R2B(dp,15,15),R2B(up,15,0),R2B(up,15,1)); + } + } + } + } +} + +static void overlap_level2_up3_422(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 3; + int idx; + int ty = 0; + + + assert(ch > 0 && image->use_clr_fmt == 2/*YUV422*/); + assert(use_my >= 3); + DEBUG("Overlap Level2 for row %d\n", top_my); + + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp,0, 2),R2B42(dp,0, 3),R2B42(dp,0, 4),R2B42(dp,0, 5)); + _jxr_4OverlapFilter(R2B42(dp,0, 6),R2B42(dp,0, 7),R2B42(dp,0, 8),R2B42(dp,0, 9)); + _jxr_4OverlapFilter(R2B42(dp,0,10),R2B42(dp,0,11),R2B42(dp,0,12),R2B42(dp,0,13)); + + _jxr_4OverlapFilter(R2B42(dp,1, 2),R2B42(dp,1, 3),R2B42(dp,1, 4),R2B42(dp,1, 5)); + _jxr_4OverlapFilter(R2B42(dp,1, 6),R2B42(dp,1, 7),R2B42(dp,1, 8),R2B42(dp,1, 9)); + _jxr_4OverlapFilter(R2B42(dp,1,10),R2B42(dp,1,11),R2B42(dp,1,12),R2B42(dp,1,13)); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + + int*dp = MACROBLK_UP3(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4OverlapFilter(R2B42(dp,6,2),R2B42(dp,6,3),R2B42(dp,6,4),R2B42(dp,6,5)); + _jxr_4OverlapFilter(R2B42(dp,7,2),R2B42(dp,7,3),R2B42(dp,7,4),R2B42(dp,7,5)); + + _jxr_4OverlapFilter(R2B42(dp,6,6),R2B42(dp,6,7),R2B42(dp,6,8),R2B42(dp,6,9)); + _jxr_4OverlapFilter(R2B42(dp,7,6),R2B42(dp,7,7),R2B42(dp,7,8),R2B42(dp,7,9)); + + _jxr_4OverlapFilter(R2B42(dp,6,10),R2B42(dp,6,11),R2B42(dp,6,12),R2B42(dp,6,13)); + _jxr_4OverlapFilter(R2B42(dp,7,10),R2B42(dp,7,11),R2B42(dp,7,12),R2B42(dp,7,13)); + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + + _jxr_4OverlapFilter(R2B42(dp, 2,0),R2B42(dp, 3,0),R2B42(dp, 4,0),R2B42(dp, 5,0)); + _jxr_4OverlapFilter(R2B42(dp, 2,1),R2B42(dp, 3,1),R2B42(dp, 4,1),R2B42(dp, 5,1)); + + /* Top across for soft tiles */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B42(pp,6,0),R2B42(pp,7,0),R2B(dp,0,0),R2B42(dp,1,0)); + _jxr_4OverlapFilter(R2B42(pp,6,1),R2B42(pp,7,1),R2B(dp,0,1),R2B42(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch, tx, 0).data; + _jxr_4OverlapFilter(R2B42(dp,0,0),R2B42(dp,1,0),R2B42(dp,0,1),R2B42(dp,1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B42(dp,6,0),R2B42(dp,7,0),R2B42(dp,6,1),R2B42(dp,7,1)); + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP3(image,ch,tx,idx).data; + + _jxr_4OverlapFilter(R2B42(tp,2,14),R2B42(tp,3,14),R2B42(tp,4,14),R2B42(tp,5,14)); + _jxr_4OverlapFilter(R2B42(tp,2,15),R2B42(tp,3,15),R2B42(tp,4,15),R2B42(tp,5,15)); + + /* Bottom across for soft tiles */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + /* Blocks that span the MB to the right */ + int*tn = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B42(tn,6,14),R2B42(tn,7,14),R2B42(tp,0,14),R2B42(tp,1,14)); + _jxr_4OverlapFilter(R2B42(tn,6,15),R2B42(tn,7,15),R2B42(tp,0,15),R2B42(tp,1,15)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp,0,14),R2B42(dp,1,14),R2B42(dp,0,15),R2B42(dp,1,15)); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B42(dp,6,14),R2B42(dp,7,14),R2B42(dp,6,15),R2B42(dp,7,15)); + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4OverlapFilter(R2B42(dp,2,2),R2B42(dp,3,2),R2B42(dp,4,2),R2B42(dp,5,2), + R2B42(dp,2,3),R2B42(dp,3,3),R2B42(dp,4,3),R2B42(dp,5,3), + R2B42(dp,2,4),R2B42(dp,3,4),R2B42(dp,4,4),R2B42(dp,5,4), + R2B42(dp,2,5),R2B42(dp,3,5),R2B42(dp,4,5),R2B42(dp,5,5)); + + _jxr_4x4OverlapFilter(R2B42(dp,2,6),R2B42(dp,3,6),R2B42(dp,4,6),R2B42(dp,5,6), + R2B42(dp,2,7),R2B42(dp,3,7),R2B42(dp,4,7),R2B42(dp,5,7), + R2B42(dp,2,8),R2B42(dp,3,8),R2B42(dp,4,8),R2B42(dp,5,8), + R2B42(dp,2,9),R2B42(dp,3,9),R2B42(dp,4,9),R2B42(dp,5,9)); + + _jxr_4x4OverlapFilter(R2B42(dp,2,10),R2B42(dp,3,10),R2B42(dp,4,10),R2B42(dp,5,10), + R2B42(dp,2,11),R2B42(dp,3,11),R2B42(dp,4,11),R2B42(dp,5,11), + R2B42(dp,2,12),R2B42(dp,3,12),R2B42(dp,4,12),R2B42(dp,5,12), + R2B42(dp,2,13),R2B42(dp,3,13),R2B42(dp,4,13),R2B42(dp,5,13)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) { + /* Blocks that span the MB to the right */ + int*np = MACROBLK_UP3(image,ch,tx,idx+1).data; + _jxr_4x4OverlapFilter(R2B42(dp,6,2),R2B42(dp,7,2),R2B42(np,0,2),R2B42(np,1,2), + R2B42(dp,6,3),R2B42(dp,7,3),R2B42(np,0,3),R2B42(np,1,3), + R2B42(dp,6,4),R2B42(dp,7,4),R2B42(np,0,4),R2B42(np,1,4), + R2B42(dp,6,5),R2B42(dp,7,5),R2B42(np,0,5),R2B42(np,1,5)); + + _jxr_4x4OverlapFilter(R2B42(dp,6,6),R2B42(dp,7,6),R2B42(np,0,6),R2B42(np,1,6), + R2B42(dp,6,7),R2B42(dp,7,7),R2B42(np,0,7),R2B42(np,1,7), + R2B42(dp,6,8),R2B42(dp,7,8),R2B42(np,0,8),R2B42(np,1,8), + R2B42(dp,6,9),R2B42(dp,7,9),R2B42(np,0,9),R2B42(np,1,9)); + + _jxr_4x4OverlapFilter(R2B42(dp,6,10),R2B42(dp,7,10),R2B42(np,0,10),R2B42(np,1,10), + R2B42(dp,6,11),R2B42(dp,7,11),R2B42(np,0,11),R2B42(np,1,11), + R2B42(dp,6,12),R2B42(dp,7,12),R2B42(np,0,12),R2B42(np,1,12), + R2B42(dp,6,13),R2B42(dp,7,13),R2B42(np,0,13),R2B42(np,1,13)); + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + /* Blocks that MB below */ + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + int*up = MACROBLK_UP2(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + _jxr_4OverlapFilter(R2B42(dp,0,14),R2B42(dp,0,15),R2B42(up,0,0),R2B42(up,0,1)); + _jxr_4OverlapFilter(R2B42(dp,1,14),R2B42(dp,1,15),R2B42(up,1,0),R2B42(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + _jxr_4x4OverlapFilter(R2B42(dp,2,14),R2B42(dp,3,14),R2B42(dp,4,14),R2B42(dp,5,14), + R2B42(dp,2,15),R2B42(dp,3,15),R2B42(dp,4,15),R2B42(dp,5,15), + R2B42(up,2, 0),R2B42(up,3, 0),R2B42(up,4, 0),R2B42(up,5, 0), + R2B42(up,2, 1),R2B42(up,3, 1),R2B42(up,4, 1),R2B42(up,5, 1)); + + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right, below, below-right */ + int*dn = MACROBLK_UP3(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP2(image,ch,tx,idx+1).data; + + _jxr_4x4OverlapFilter(R2B42(dp,6,14),R2B42(dp,7,14),R2B42(dn,0,14),R2B42(dn,1,14), + R2B42(dp,6,15),R2B42(dp,7,15),R2B42(dn,0,15),R2B42(dn,1,15), + R2B42(up,6, 0),R2B42(up,7, 0),R2B42(un,0, 0),R2B42(un,1, 0), + R2B42(up,6, 1),R2B42(up,7, 1),R2B42(un,0, 1),R2B42(un,1, 1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + _jxr_4OverlapFilter(R2B42(dp,6,14),R2B42(dp,6,15),R2B42(up,6,0),R2B42(up,6,1)); + _jxr_4OverlapFilter(R2B42(dp,7,14),R2B42(dp,7,15),R2B42(up,7,0),R2B42(up,7,1)); + } + } + } + } +} +/* +*/ + +static void overlap_level2_up3_420(jxr_image_t image, int use_my, int ch) +{ + int tx = 0; /* XXXX */ + int top_my = use_my - 3; + int idx; + int ty = 0; + + assert(ch > 0 && image->use_clr_fmt == 1/*YUV420*/); + assert(use_my >= 3); + + DEBUG("Overlap Level2 (YUV420) for row %d\n", top_my); + + + /* Figure out which tile row the current strip of macroblocks belongs to. */ + while(top_my > image->tile_row_position[ty]+image->tile_row_height[ty] - 1) + ty++; + + for(tx = 0; tx < image->tile_columns; tx++) + { + + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp,0,2),R2B42(dp,0,3),R2B42(dp,0,4),R2B42(dp,0,5)); + _jxr_4OverlapFilter(R2B42(dp,1,2),R2B42(dp,1,3),R2B42(dp,1,4),R2B42(dp,1,5)); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + int*dp = MACROBLK_UP3(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4OverlapFilter(R2B42(dp,6,2),R2B42(dp,6,3),R2B42(dp,6,4),R2B42(dp,6,5)); + _jxr_4OverlapFilter(R2B42(dp,7,2),R2B42(dp,7,3),R2B42(dp,7,4),R2B42(dp,7,5)); + } + + /* Top edge */ + if(top_my == 0 )/* || (image->disableTileOverlapFlag && TOP_Y(top_my) )) */ + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Overlap filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + _jxr_4OverlapFilter(R2B42(dp, 2,0),R2B42(dp, 3,0),R2B42(dp, 4,0),R2B42(dp, 5,0)); + _jxr_4OverlapFilter(R2B42(dp, 2,1),R2B42(dp, 3,1),R2B42(dp, 4,1),R2B42(dp, 5,1)); + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B42(pp,6,0),R2B42(pp,7,0),R2B(dp,0,0),R2B42(dp,1,0)); + _jxr_4OverlapFilter(R2B42(pp,6,1),R2B42(pp,7,1),R2B(dp,0,1),R2B42(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp, 0,0),R2B42(dp, 1, 0),R2B42(dp, 0 ,1),R2B42(dp, 1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B42(dp, 6,0),R2B42(dp, 7,0),R2B42(dp, 6,1),R2B42(dp, 7,1));; + } + + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Overlap filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP3(image,ch,tx,idx).data; + + _jxr_4OverlapFilter(R2B42(tp,2,6),R2B42(tp,3,6),R2B42(tp,4,6),R2B42(tp,5,6)); + _jxr_4OverlapFilter(R2B42(tp,2,7),R2B42(tp,3,7),R2B42(tp,4,7),R2B42(tp,5,7)); + + + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tn = MACROBLK_UP3(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B42(tn,6,6),R2B42(tn,7,6),R2B42(tp,0,6),R2B42(tp,1,6)); + _jxr_4OverlapFilter(R2B42(tn,6,7),R2B42(tn,7,7),R2B42(tp,0,7),R2B42(tp,1,7)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp, 0,6),R2B42(dp, 1, 6),R2B42(dp, 0,7),R2B42(dp, 1, 7)); + } + + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP3(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B42(dp, 6, 6),R2B42(dp, 7, 6),R2B42(dp, 6, 7),R2B42(dp, 7, 7)); + } + + if(image->disableTileOverlapFlag && BOTTOM_Y(top_my) && top_my <EXTENDED_HEIGHT_BLOCKS(image)-1) + { + /* Also process Top edge of next macroblock row */ + /* In the case of YUV 420, the next row of macroblocks needs to be transformed */ + /* before yuv420_to_yuv422 is called */ + /* In the soft tile case the top 2 lines of the MB below are processed by the 2x2 operators spanning the MB below*/ + /* In the case of hard tiles, if this is the bottom most row of MBs in the Hard Tile */ + /* we need to process the top edge of the next hard tile */ + /* Also see HARDTILE_NOTE in yuv420_to_yuv422() */ + + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + _jxr_4OverlapFilter(R2B42(dp, 2,0),R2B42(dp, 3,0),R2B42(dp, 4,0),R2B42(dp, 5,0)); + _jxr_4OverlapFilter(R2B42(dp, 2,1),R2B42(dp, 3,1),R2B42(dp, 4,1),R2B42(dp, 5,1)); + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4OverlapFilter(R2B42(pp,6,0),R2B42(pp,7,0),R2B(dp,0,0),R2B42(dp,1,0)); + _jxr_4OverlapFilter(R2B42(pp,6,1),R2B42(pp,7,1),R2B(dp,0,1),R2B42(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4OverlapFilter(R2B42(dp, 0,0),R2B42(dp, 1, 0),R2B42(dp, 0 ,1),R2B42(dp, 1,1)); + } + + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4OverlapFilter(R2B42(dp, 6,0),R2B42(dp, 7,0),R2B42(dp, 6,1),R2B42(dp, 7,1));; + } + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + int*up = MACROBLK_UP2(image,ch,tx,idx).data; + + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4OverlapFilter(R2B42(dp,2,2),R2B42(dp,3,2),R2B42(dp,4,2),R2B42(dp,5,2), + R2B42(dp,2,3),R2B42(dp,3,3),R2B42(dp,4,3),R2B42(dp,5,3), + R2B42(dp,2,4),R2B42(dp,3,4),R2B42(dp,4,4),R2B42(dp,5,4), + R2B42(dp,2,5),R2B42(dp,3,5),R2B42(dp,4,5),R2B42(dp,5,5)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) + { + /* 4x4 at the right */ + int*np = MACROBLK_UP3(image,ch,tx,idx+1).data; + + _jxr_4x4OverlapFilter(R2B42(dp,6,2),R2B42(dp,7,2),R2B42(np,0,2),R2B42(np,1,2), + R2B42(dp,6,3),R2B42(dp,7,3),R2B42(np,0,3),R2B42(np,1,3), + R2B42(dp,6,4),R2B42(dp,7,4),R2B42(np,0,4),R2B42(np,1,4), + R2B42(dp,6,5),R2B42(dp,7,5),R2B42(np,0,5),R2B42(np,1,5)); + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + int*dp = MACROBLK_UP3(image,ch,tx,idx).data; + int*up = MACROBLK_UP2(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + _jxr_4OverlapFilter(R2B42(dp,0,6),R2B42(dp,0,7),R2B42(up,0,0),R2B42(up,0,1)); + _jxr_4OverlapFilter(R2B42(dp,1,6),R2B42(dp,1,7),R2B42(up,1,0),R2B42(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + /* 4x4 straddling lower MB */ + _jxr_4x4OverlapFilter(R2B42(dp,2,6),R2B42(dp,3,6),R2B42(dp,4,6),R2B42(dp,5,6), + R2B42(dp,2,7),R2B42(dp,3,7),R2B42(dp,4,7),R2B42(dp,5,7), + R2B42(up,2,0),R2B42(up,3,0),R2B42(up,4,0),R2B42(up,5,0), + R2B42(up,2,1),R2B42(up,3,1),R2B42(up,4,1),R2B42(up,5,1)); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right */ + int*dn = MACROBLK_UP3(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP2(image,ch,tx,idx+1).data; + + /* 4x4 right, below, below-right */ + _jxr_4x4OverlapFilter(R2B42(dp,6,6),R2B42(dp,7,6),R2B42(dn,0,6),R2B42(dn,1,6), + R2B42(dp,6,7),R2B42(dp,7,7),R2B42(dn,0,7),R2B42(dn,1,7), + R2B42(up,6,0),R2B42(up,7,0),R2B42(un,0,0),R2B42(un,1,0), + R2B42(up,6,1),R2B42(up,7,1),R2B42(un,0,1),R2B42(un,1,1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Across vertical blocks, right edge */ + _jxr_4OverlapFilter(R2B42(dp,6,6),R2B42(dp,6,7),R2B42(up,6,0),R2B42(up,6,1)); + _jxr_4OverlapFilter(R2B42(dp,7,6),R2B42(dp,7,7),R2B42(up,7,0),R2B42(up,7,1)); + } + } + } + } +} + + +static void overlap_level2_up3(jxr_image_t image, int use_my, int ch) +{ + if (ch == 0) { + overlap_level2_up3_444(image, use_my, ch); + } + else { + switch (image->use_clr_fmt) { + case 1: /*YUV420*/ + overlap_level2_up3_420(image, use_my, ch); + break; + case 2: /*YUV422*/ + overlap_level2_up3_422(image, use_my, ch); + break; + default: + overlap_level2_up3_444(image, use_my, ch); + break; + } + } +} + + +static void yuv444_to_rgb(jxr_image_t image, int mx) +{ + int px; + for (px = 0 ; px < 256 ; px += 1) { + int Y = image->strip[0].up3[mx].data[px]; + int U = image->strip[1].up3[mx].data[px]; + int V = image->strip[2].up3[mx].data[px]; + int G = Y - _jxr_floor_div2(-U); + int R = G - U - _jxr_ceil_div2(V); + int B = V + R; + + image->strip[0].up3[mx].data[px] = R; + image->strip[1].up3[mx].data[px] = G; + image->strip[2].up3[mx].data[px] = B; + } +} + +static const int iH[5][4] = {{4, 4 , 0, 8}, {5, 3, 1, 7}, {6, 2, 2, 6}, {7, 1, 3, 5}, {8, 0, 4, 4}}; + +static void upsample(int inbuf[], int outbuf[], int upsamplelen, int chroma_center) +{ + int k; + if(chroma_center == 5 || chroma_center == 6 || chroma_center == 7) + { + chroma_center = 0; + DEBUG("Treating chroma_center as 0 in upsample\n"); + } + + for (k = 0; k <= (upsamplelen - 2) / 2; k++) + outbuf[2*k+1] = (( iH[chroma_center][0]*inbuf[k+1] + iH[chroma_center][1]*inbuf[k+2] + 4) >> 3); + for (k = -1; k <= (upsamplelen - 4) / 2; k++) + outbuf[2*k+2] = ((iH[chroma_center][2] * inbuf[k+1] + iH[chroma_center][3] * inbuf[k+2] + 4) >> 3); +} + +static void yuv422_to_yuv444(jxr_image_t image, int mx) +{ + int buf[256]; + + int ch; + int px, py, idx; + + for(ch =1; ch < 3; ch ++) { + + for (py = 0 ; py < 16 ; py += 1) + { + int inbuf [10]; + + if(mx == 0) /* Repeat to the left */ + image->strip[ch].upsample_memory_x[py] = image->strip[ch].up3[mx].data[8*py]; + + /* Prep input array */ + for(px =0; px <=7; px++) + { + inbuf[px+1] = image->strip[ch].up3[mx].data[8*py+ px]; + + } + inbuf[0] = image->strip[ch].upsample_memory_x[py]; + if(mx+1 < (int) EXTENDED_WIDTH_BLOCKS(image)) + inbuf[9] = image->strip[ch].up3[mx+1].data[8*py]; + else + inbuf[9] = inbuf[8]; /* Repeat to the right */ + + /* Call upsample */ + upsample(inbuf, buf + 16*py, 16, image->chroma_centering_x); + + /* Remember right most vals */ + image->strip[ch].upsample_memory_x[py] = image->strip[ch].up3[mx].data[8*py+7]; + } + + for (idx = 0 ; idx < 256 ; idx += 1) + image->strip[ch].up3[mx].data[idx] = buf[idx]; + + } +} + +static void yuv420_to_yuv444(jxr_image_t image, int use_my, int mx) +{ + int buf[256]; + int intermediatebuf[2][16 * 8]; + + int ch; + int inbuf [10]; + int px, py, idx; + + /* Upsample in the y direction */ + for (ch = 1 ; ch < 3 ; ch += 1) { + for(px = 0; px < 8; px ++) + { + if(use_my-2 == 1) /* Repeat to the top */ + image->strip[ch].upsample_memory_y[8*mx+ px] = image->strip[ch].up3[mx].data[px];/* Store the top most values */ + + /* Prep input buffer */ + for(py =0; py < 8 ; py++) + inbuf[py+1] = image->strip[ch].up3[mx].data[8*py+ px]; + inbuf[0] = image->strip[ch].upsample_memory_y[8*mx + px]; + if((use_my-2) < (int) EXTENDED_HEIGHT_BLOCKS(image)) + { + if(px <= 3) + inbuf[9] = image->strip[ch].up2[mx].data[px]; /* Get the lower MB sample */ + else + inbuf[9] = image->strip[ch].up2[mx].data[px + 12]; /* Since unblock_shuffle420 has not been called on up2 */ + } + else + inbuf[9] = inbuf[8]; /* Repeat to the right */ + + /* Call upsample */ + upsample(inbuf, buf, 16, image->chroma_centering_y); + + for(py =0; py < 16; py ++) + intermediatebuf[ch-1][8*py + px] = buf[py]; + + image->strip[ch].upsample_memory_y[8*mx + px] = image->strip[ch].up3[mx].data[8*7+px];/* Store the bottom most values */ + } + } + + /* Upsample in the X direction */ + for (ch = 1 ; ch < 3 ; ch += 1) { + int nextmbrow[16]; + + /* To upsample in the X direction, we need the Y-direction upsampled values from the left most row of the next MB */ + /* Prep input buffer */ + for(py = 0; py < 8; py ++) + { + if(mx + 1 < (int) EXTENDED_WIDTH_BLOCKS(image)) + inbuf[py + 1] = image->strip[ch].up3[mx+1].data[8*py]; + else + inbuf[py + 1] = image->strip[ch].up3[mx].data[8*py]; + } + if(use_my - 2 < (int) EXTENDED_HEIGHT_BLOCKS(image) && mx + 1 < (int) EXTENDED_WIDTH_BLOCKS(image)) + inbuf[9] = image->strip[ch].up2[mx+1].data[0]; + else + inbuf[9] = inbuf[8];/* Repeat to the right */ + if(use_my -2 != 1 && mx + 1 < (int) EXTENDED_WIDTH_BLOCKS(image)) + inbuf[0] = image->strip[ch].upsample_memory_y[8*(mx+1)]; + else + inbuf[0] = inbuf[1]; + + /*Call upsample */ + upsample(inbuf, nextmbrow, 16, image->chroma_centering_y); + + for(py = 0; py < 16; py ++) + { + if(mx == 0) /* Repeat to the left */ + image->strip[ch].upsample_memory_x[py] = intermediatebuf[ch-1][8*py]; + + /* Prepare the input buffer */ + for(px =0; px <=7; px++) + inbuf[px+1] = intermediatebuf[ch-1][8*py+ px]; + + inbuf[0] = image->strip[ch].upsample_memory_x[py]; + if(mx + 1 < (int) EXTENDED_WIDTH_BLOCKS(image)) + { + inbuf[9] = nextmbrow[py]; + } + else + inbuf[9] = inbuf[8]; /* Repeat to the right */ + + /* Call upsample */ + upsample(inbuf, buf + 16*py, 16, image->chroma_centering_x); + image->strip[ch].upsample_memory_x[py] = intermediatebuf[ch-1][8*py + 7];/* Store the right most values */ + } + + for(idx =0; idx < 256; idx ++) + image->strip[ch].up3[mx].data[idx] = buf[idx]; + } +} + +static void yuvk_to_cmyk(jxr_image_t image, int mx) +{ + int px; + for (px = 0 ; px < 256 ; px += 1) { + int Y = image->strip[0].up3[mx].data[px]; + int U = image->strip[1].up3[mx].data[px]; + int V = image->strip[2].up3[mx].data[px]; + int K = image->strip[3].up3[mx].data[px]; + int k = K + _jxr_floor_div2(Y); + int m = k - Y - _jxr_floor_div2(U); + int c = U + m + _jxr_floor_div2(V); + int y = c - V; + + image->strip[0].up3[mx].data[px] = c; + image->strip[1].up3[mx].data[px] = m; + image->strip[2].up3[mx].data[px] = y; + image->strip[3].up3[mx].data[px] = k; + } +} + +static int PostScalingFloat(int iPixVal, unsigned int expBias, unsigned char lenMantissa, int bitdepth) +{ + int convVal = 0; + if (bitdepth == JXR_BD16F) + { + uint8_t iS = 0; + unsigned int fV = 0; + unsigned int iEM = abs(iPixVal); + if(iPixVal < 0) + iS = 1; + if (iEM > 0x7FFF) + iEM = 0x7FFF; + convVal = ((iS << 15) | iEM); /* Concatenate these fields*/ + } + else + { + int sign, iTempH, mantissa, exp, lmshift = (1 << lenMantissa); + + assert (expBias <= 127); + + iTempH = (int) iPixVal ; + sign = (iTempH >> 31); + iTempH = (iTempH ^ sign) - sign; /* abs(iTempH) */ + + exp = (unsigned int) iTempH >> lenMantissa;/* & ((1 << (31 - lenMantissa)) - 1); */ + mantissa = (iTempH & (lmshift - 1)) | lmshift; /* actual mantissa, with normalizer */ + if (exp == 0) { /* denormal land */ + mantissa ^= lmshift; /* normalizer removed */ + exp = 1; /* actual exponent */ + } + + exp += (127 - expBias); + while (mantissa < lmshift && exp > 1 && mantissa > 0) { /* denormal originally, see if normal is possible */ + exp--; + mantissa <<= 1; + } + if (mantissa < lmshift) /* truly denormal */ + exp = 0; + else + mantissa ^= lmshift; + mantissa <<= (23 - lenMantissa); + + convVal = (sign & 0x80000000) | (exp << 23) | mantissa; + } + return convVal; +} + +static void PostScalingFl2(int arrayOut[], int arrayIn[]) { + /* arrayIn[ ]= {R, G, B} */ + /* arrayOut[ ]= {Rrgbe, Grgbe, Brgbe, Ergbe} */ + int iEr, iEg, iEb; + int iShift; + + if (arrayIn[0] <= 0) { + arrayOut[0] = 0; + iEr = 0; + } + else if ((arrayIn[0] >> 7) > 1) { + arrayOut[0] = (arrayIn[0] & 0x7F) + 0x80; + iEr = (arrayIn[0] >> 7); + } + else { + arrayOut[0] = arrayIn[0]; + iEr = 1; + } + if (arrayIn[1] <= 0) { + arrayOut[1] = 0; + iEg = 0; + } + else if ((arrayIn[1] >> 7) > 1) { + arrayOut[1] = (arrayIn[1] & 0x7F) + 0x80; + iEg = (arrayIn[1] >> 7); + } + else { + arrayOut[1] = arrayIn[1]; + iEg = 1; + } + if (arrayIn[2] <= 0) { + arrayOut[2] = 0; + iEb = 0; + } + else if ((arrayIn[2] >> 7) > 1) { + arrayOut[2] = (arrayIn[2] & 0x7F) + 0x80; + iEb = (arrayIn[2] >> 7); + } + else { + arrayOut[2] = arrayIn[2]; + iEb = 1; + } + + /* Max(iEr, iEg, iEb) */ + arrayOut[3] = iEr> iEg? (iEr>iEb?iEr:iEb):(iEg>iEb?iEg:iEb); + + if( arrayOut[3] > iEr){ + iShift = ( arrayOut[3] - iEr); + arrayOut[0] = (unsigned char)((((int) arrayOut[0]) * 2 + 1) >> (iShift + 1)); + } + if( arrayOut[3] > iEg){ + iShift = ( arrayOut[3]- iEg); + arrayOut[1] = (unsigned char)((((int) arrayOut[1]) * 2 + 1) >> (iShift + 1)); + } + if( arrayOut[3] > iEb){ + iShift = ( arrayOut[3]- iEb); + arrayOut[2] = (unsigned char)((((int) arrayOut[2]) * 2 + 1) >> (iShift + 1)); + } +} + +static void scale_and_emit_top(jxr_image_t image, int tx, int use_my) +{ + int scale = image->scaled_flag? 3 : 0; + int bias; + int round; + int shift_bits = image->shift_bits; + /* Clipping based on 8bit values. */ + int clip_low = 0; + int clip_hig = 255; + int idx; + int buffer[(MAX_CHANNELS + 1)*256]; + unsigned int bSkipColorTransform = 0; + memset(buffer, 0,(MAX_CHANNELS + 1)*256); + + + switch (SOURCE_BITDEPTH(image)) { + case 0: /* BD1WHITE1*/ + + case 15: /* BD1BLACK1 */ + bias = 0; + round = image->scaled_flag? 4 : 0; + clip_low = 0; + clip_hig = 1; + break; + case 1: /* BD8 */ + bias = 1 << 7; + round = image->scaled_flag? 3 : 0; + clip_low = 0; + clip_hig = 255; + break; + case 2: /* BD16 */ + bias = 1 << 15; + round = image->scaled_flag? 4 : 0; + clip_low = 0; + clip_hig = 65535; + break; + case 3: /* BD16S */ + bias = 0; + round = image->scaled_flag? 3 : 0; + clip_low = -32768; + clip_hig = 32767; + break; + + case 6: /*BD32S */ + bias = 0; + round = image->scaled_flag? 3 : 0; + clip_hig = 0x7fffffff; + clip_low = -(clip_hig + 1); + break; + + case 4: /* BD16F */ + + case 7: /* BD32F */ + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + + case 8: /* BD5 */ + bias = 16; + round = image->scaled_flag? 3 : 0; + clip_hig = 31; + clip_low = 0; + break; + + case 9: /* BD10 */ + bias = 512; + round = image->scaled_flag? 3 : 0; + clip_hig = 1023; + clip_low = 0; + break; + + case 10: /* BD565 */ + bias = 32; + round = image->scaled_flag? 3 : 0; + clip_hig = 31; + clip_low = 0; + break; + + case 5: /* Reserved */ + + default: + fprintf(stderr, "XXXX Don't know how to scale bit depth %d?\n", SOURCE_BITDEPTH(image)); + bias = 0; + round = image->scaled_flag? 3 : 0; + clip_low = 0; + clip_hig = 255; + break; + } + + DEBUG("scale_and_emit_top: scale=%d, bias=%d, round=%d, shift_bits=%d, clip_low=%d, clip_hig=%d\n", + scale, bias, round, shift_bits, clip_low, clip_hig); + + /* Up 'til this point, the MB contains 4x4 sub-blocks. We are + now ready for the MB to contain only raster data within, so + this loop rasterizes all the MBs in this strip. */ + for (idx = 0 ; idx < (int) EXTENDED_WIDTH_BLOCKS(image); idx += 1) { + + int ch; + int*dp = image->strip[0].up3[idx].data; + unblock_shuffle444(dp); + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + dp = image->strip[ch].up3[idx].data; + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + unblock_shuffle420(dp); + break; + case 2: /* YUV422 */ + unblock_shuffle422(dp); + break; + default: + unblock_shuffle444(dp); + break; + } + } + } + + for (idx = 0 ; idx < (int) EXTENDED_WIDTH_BLOCKS(image); idx += 1) { + + int ch; +#if defined(DETAILED_DEBUG) && 1 + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int count = 256; + if (ch > 0 && image->use_clr_fmt==2/*YUV422*/) + count = 128; + if (ch > 0 && image->use_clr_fmt==1/*YUV420*/) + count = 64; + + DEBUG("image yuv mx=%3d my=%3d ch=%d:", idx, use_my-3, ch); + int jdx; + for (jdx = 0 ; jdx < count ; jdx += 1) { + if (jdx%8 == 0 && jdx != 0) + DEBUG("\n%*s", 29, ""); + DEBUG(" %08x", image->strip[ch].up3[idx].data[jdx]); + } + DEBUG("\n"); + } +#endif + + if(SOURCE_CLR_FMT(image) == JXR_OCF_YUV420 || SOURCE_CLR_FMT(image) == JXR_OCF_YUV422 || SOURCE_CLR_FMT(image) == JXR_OCF_YUV444 || SOURCE_CLR_FMT(image) == JXR_OCF_CMYKDIRECT) + { + bSkipColorTransform = 1; + } + + /* Perform transform in place, if needed. */ + /* For YCC output, no color transform is needed */ + if(!bSkipColorTransform) + { + switch (image->use_clr_fmt ) { + + case 1: /* YUV420 */ + yuv420_to_yuv444(image, use_my, idx); + yuv444_to_rgb(image, idx); + break; + + case 2: /* YUV422 */ + yuv422_to_yuv444(image, idx); + yuv444_to_rgb(image, idx); + break; + + case 3: /* YUV444 */ + yuv444_to_rgb(image, idx); + break; + + case 4: /* CMYK */ + yuvk_to_cmyk(image, idx); + break; + } + } + + /* The strip data is now in the output color space. */ + + /* AddBias and ComputeScaling */ + if (image->use_clr_fmt == 4 && SOURCE_CLR_FMT(image) != JXR_OCF_CMYKDIRECT/*CMYK*/) { + /* The CMYK format has a different and unique set + of bias/rounding calculations. Treat it as a + special case. And treat the K plane even more + special. */ + int*dp; + int jdx; + for (ch = 0 ; ch < 3 ; ch += 1) { + dp = image->strip[ch].up3[idx].data; + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + dp[jdx] = (dp[jdx] + ((bias>>(shift_bits+1))<<scale) + round) >> scale; + dp[jdx] <<= shift_bits; + if (dp[jdx] > clip_hig) + dp[jdx] = clip_hig; + if (dp[jdx] < clip_low) + dp[jdx] = clip_low; + } + } + dp = image->strip[3].up3[idx].data; + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + dp[jdx] = (dp[jdx] - ((bias>>(shift_bits+1))<<scale) + round) >> scale; + dp[jdx] <<= shift_bits; + if (dp[jdx] > clip_hig) + dp[jdx] = clip_hig; + if (dp[jdx] < clip_low) + dp[jdx] = clip_low; + } + } + else + { + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + /* PostScalingInt and clip, 16s and 32s */ + if( SOURCE_BITDEPTH(image)!= JXR_BD565 && SOURCE_BITDEPTH(image) != JXR_BD16F && SOURCE_BITDEPTH(image) != JXR_BD32F && SOURCE_CLR_FMT(image) != JXR_OCF_RGBE) + { + int*dp = image->strip[ch].up3[idx].data; + int jdx; + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + dp[jdx] = (dp[jdx] + ((bias>>shift_bits)<<scale) + round) >> scale; + dp[jdx] <<= shift_bits; + if (dp[jdx] > clip_hig) + dp[jdx] = clip_hig; + if (dp[jdx] < clip_low) + dp[jdx] = clip_low; + } +#if defined(DETAILED_DEBUG) && 0 + DEBUG("scale_and_emit: block at mx=%d, my=%d, ch=%d:", idx, use_my-3, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%8 == 0 && jdx > 0) + DEBUG("\n%*s:", 41, ""); + DEBUG(" %04x", dp[jdx]); + } + DEBUG("\n"); +#endif + } + else if(SOURCE_BITDEPTH(image) == JXR_BD565) + { + /* Special case where R and B have different clip thresholds from G */ + int*dp = image->strip[ch].up3[idx].data; + int jdx; + assert(image->num_channels == 3); + if(ch != 1) + { + clip_hig = 31; + clip_low = 0; + } + else + { + clip_hig = 63; + clip_low = 0; + } + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if(ch == 1) + dp[jdx] = (dp[jdx] + ((bias)<<scale) + round) >> scale; + else + dp[jdx] = (dp[jdx] + ((bias)<<scale) + round) >> (scale + 1); + if (dp[jdx] > clip_hig) + dp[jdx] = clip_hig; + if (dp[jdx] < clip_low) + dp[jdx] = clip_low; + } + } + + /* PostScalingFl */ + else + { + int* dp = image->strip[ch].up3[idx].data; + int jdx; + if(SOURCE_BITDEPTH(image) == JXR_BD16F || SOURCE_BITDEPTH(image) == JXR_BD32F) + { + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + dp[jdx] = (dp[jdx] + round) >> scale; + dp[jdx] = PostScalingFloat(dp[jdx], image->exp_bias, image->len_mantissa, SOURCE_BITDEPTH(image)); + } + } + else /* RGBE : PostScalingFl2 requires one extra sample per pixel - Write directly into buffer */ + { + int *dp0 = image->strip[0].up3[idx].data; + int *dp1 = image->strip[1].up3[idx].data; + int *dp2 = image->strip[2].up3[idx].data; + assert(image->num_channels == 3); + assert(ch == 0); + + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + /* There is no bias in this case */ + int idp0 = (dp0[jdx] + round) >> scale; + int idp1 = (dp1[jdx] + round) >> scale; + int idp2 = (dp2[jdx] + round) >> scale; + + int arrIn[3] = {idp0, idp1, idp2}; + + PostScalingFl2(buffer + (image->num_channels + 1) * jdx, arrIn); + ch = 3;/* We have taken care of all channels in one go */ + } + + } + + + +#if defined(DETAILED_DEBUG) && 0 + DEBUG("scale_and_emit: block at mx=%d, my=%d, ch=%d:", idx, use_my-3, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%8 == 0 && jdx > 0) + DEBUG("\n%*s:", 41, ""); + DEBUG(" %04x", dp[jdx]); + } + DEBUG("\n"); +#endif + } + } + } + + if ( image->primary == 1 ) { /* alpha channel output is combined with primary channel */ + int px; + int channels = image->num_channels; + + if(!bSkipColorTransform) /* Interleave channels in buffer */ + { + if (ALPHACHANNEL_FLAG(image)) + channels ++; + + for (px = 0 ; px < 256 && (SOURCE_CLR_FMT(image) != JXR_OCF_RGBE) ; px += 1) /*RGBE is a special case that is already taken care of */ + for (ch = 0 ; ch < image->num_channels ; ch += 1) + buffer[channels*px + ch] = image->strip[ch].up3[idx].data[px]; + + if (ALPHACHANNEL_FLAG(image)) + for (px = 0 ; px < 256 ; px += 1) + buffer[channels*px + image->num_channels] = image->alpha->strip[0].up3[idx].data[px]; + } + else + { + int size = 256*sizeof(uint32_t); + int i = 0; + for(i = 0; i < image->num_channels; i ++) + { + memcpy(((uint8_t *)buffer + i*size), image->strip[i].up3[idx].data, size); + + } + if(ALPHACHANNEL_FLAG(image)) + memcpy(((uint8_t *)buffer) + image->num_channels*size, image->alpha->strip[0].up3[idx].data, size); + } + + + _jxr_send_mb_to_output(image, idx, use_my-3, buffer); + } + } +} + +/* +* The tile_row_buffer holds flushed mb data in image raster order, +* along with other per-mb data. This is in support of SPATIAL processing. +*/ +static void rflush_to_tile_buffer(jxr_image_t image, int tx, int my) +{ + int format_scale = 256; + int mx; + DEBUG("rflush_mb_strip: rflush_to_tile_buffer tx=%d, my=%d\n", tx, my); + + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int off; + int ch; + DEBUG("rflush_mb_strip: rflush_to_tile_buffer tx=%d, mx=%d, CUR=0x%08x UP1=0x%08x, UP2=0x%08x, UP3=0x%08x, LP_QUANT=%d\n", + tx, mx, MACROBLK_CUR(image,0,tx,mx).data[0], + MACROBLK_UP1(image,0,tx,mx).data[0], + MACROBLK_UP2(image,0,tx,mx).data[0], + MACROBLK_UP3(image,0,tx,mx).data[0], + MACROBLK_CUR_LP_QUANT(image,0,tx,mx)); + + off = my * EXTENDED_WIDTH_BLOCKS(image) + image->tile_column_position[tx] + mx; + for (ch = 0; ch < image->num_channels; ch += 1) { + int count; + int idx; + struct macroblock_s*mb = image->mb_row_buffer[ch] + off; + mb->lp_quant = MACROBLK_CUR_LP_QUANT(image,ch,tx,mx); + mb->hp_quant = MACROBLK_CUR(image,ch,tx,mx).hp_quant; + count = (ch==0)? 256 : format_scale; + for (idx = 0 ; idx < count ; idx += 1) + mb->data[idx] = MACROBLK_CUR(image,ch,tx,mx).data[idx]; + } + } +} + +/* +* Recover a strip of data from all but the last column of data. Skip +* the last column because this function is called while the last +* column is being processed. +*/ +static void rflush_collect_mb_strip_data(jxr_image_t image, int my) +{ + int format_scale = 256; + int tx; + + DEBUG("rflush_mb_strip: rflush_collect_mb_strip_data my=%d\n", my); + + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (tx = 0; tx < (int) image->tile_columns-1 ; tx += 1) { + int mx; + for (mx = 0; mx < (int) image->tile_column_width[tx]; mx += 1) { + int off = my * EXTENDED_WIDTH_BLOCKS(image) + image->tile_column_position[tx] + mx; + int ch; + for (ch = 0; ch < image->num_channels; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + off; + int count; + int idx; + MACROBLK_CUR_LP_QUANT(image,ch,tx,mx) = mb->lp_quant; + MACROBLK_CUR(image,ch,tx,mx).hp_quant = mb->hp_quant; + count = (ch==0)? 256 : format_scale; + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_CUR(image,ch,tx,mx).data[idx] = mb->data[idx]; + } + DEBUG("rflush_mb_strip: rflush_collect_mb_strip_data tx=%d, mx=%d, CUR=0x%08x UP1=0x%08x, UP2=0x%08x, UP3=0x%08x lp_quant=%d\n", + tx, mx, MACROBLK_CUR(image,0,tx,mx).data[0], + MACROBLK_UP1(image,0,tx,mx).data[0], + MACROBLK_UP2(image,0,tx,mx).data[0], + MACROBLK_UP3(image,0,tx,mx).data[0], + MACROBLK_CUR_LP_QUANT(image,0,tx,mx)); + } + } +} + +/* +* The save_ and recover_context functions save the 3 strips of data +* currently in the strip buffer. This is used at the end of a tile +* row and beginning of the next tile row to save context while +* columns of tiles are collected, and restore it when processing the +* last tile column. +*/ +static void rflush_save_context(jxr_image_t image) +{ + int format_scale = 256; + int tx; + DEBUG("rflush_mb_strip: rflush_save_context\n"); + + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0; mx < (int) image->tile_column_width[tx]; mx += 1) { + int off0 = image->tile_column_position[tx] + mx; + int off1 = off0 + EXTENDED_WIDTH_BLOCKS(image); + int off2 = off1 + EXTENDED_WIDTH_BLOCKS(image); + int off3 = off2 + EXTENDED_WIDTH_BLOCKS(image); + int ch; + DEBUG("rflush_mb_strip: rflush_save_context tx=%d, mx=%d, CUR=0x%08x UP1=0x%08x, UP2=0x%08x, UP3=0x%08x\n", + tx, mx, MACROBLK_CUR(image,0,tx,mx).data[0], + MACROBLK_UP1(image,0,tx,mx).data[0], + MACROBLK_UP2(image,0,tx,mx).data[0], + MACROBLK_UP3(image,0,tx,mx).data[0]); + for (ch = 0; ch < image->num_channels; ch += 1) { + int count; + int idx; + + image->mb_row_context[ch][off0].lp_quant = MACROBLK_CUR_LP_QUANT(image,ch,tx,mx); + image->mb_row_context[ch][off1].lp_quant = MACROBLK_UP1_LP_QUANT(image,ch,tx,mx); + image->mb_row_context[ch][off2].lp_quant = MACROBLK_UP2(image,ch,tx,mx).lp_quant; + image->mb_row_context[ch][off3].lp_quant = MACROBLK_UP3(image,ch,tx,mx).lp_quant; + image->mb_row_context[ch][off0].hp_quant = MACROBLK_CUR(image,ch,tx,mx).hp_quant; + image->mb_row_context[ch][off1].hp_quant = MACROBLK_UP1(image,ch,tx,mx).hp_quant; + image->mb_row_context[ch][off2].hp_quant = MACROBLK_UP2(image,ch,tx,mx).hp_quant; + image->mb_row_context[ch][off3].hp_quant = MACROBLK_UP3(image,ch,tx,mx).hp_quant; + count = (ch==0)? 256 : format_scale; + for (idx = 0 ; idx < count; idx += 1) + image->mb_row_context[ch][off0].data[idx] = MACROBLK_CUR(image,ch,tx,mx).data[idx]; + for (idx = 0 ; idx < count; idx += 1) + image->mb_row_context[ch][off1].data[idx] = MACROBLK_UP1(image,ch,tx,mx).data[idx]; + for (idx = 0 ; idx < count; idx += 1) + image->mb_row_context[ch][off2].data[idx] = MACROBLK_UP2(image,ch,tx,mx).data[idx]; + for (idx = 0 ; idx < count; idx += 1) + image->mb_row_context[ch][off3].data[idx] = MACROBLK_UP3(image,ch,tx,mx).data[idx]; + } + } + } +} + +static void rflush_recover_context(jxr_image_t image) +{ + + int format_scale = 256; + int tx; + DEBUG("rflush_mb_strip: recover contex\n"); + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0; mx < (int) image->tile_column_width[tx]; mx += 1) { + int off0 = image->tile_column_position[tx] + mx; + int off1 = off0 + EXTENDED_WIDTH_BLOCKS(image); + int off2 = off1 + EXTENDED_WIDTH_BLOCKS(image); + int off3 = off2 + EXTENDED_WIDTH_BLOCKS(image); + int ch; + for (ch = 0; ch < image->num_channels; ch += 1) { + int count; + int idx; + MACROBLK_CUR_LP_QUANT(image,ch,tx,mx) = image->mb_row_context[ch][off0].lp_quant; + MACROBLK_UP1_LP_QUANT(image,ch,tx,mx) = image->mb_row_context[ch][off1].lp_quant; + MACROBLK_UP2(image,ch,tx,mx).lp_quant = image->mb_row_context[ch][off2].lp_quant; + MACROBLK_UP3(image,ch,tx,mx).lp_quant = image->mb_row_context[ch][off3].lp_quant; + MACROBLK_CUR(image,ch,tx,mx).hp_quant = image->mb_row_context[ch][off0].hp_quant; + MACROBLK_UP1(image,ch,tx,mx).hp_quant = image->mb_row_context[ch][off1].hp_quant; + MACROBLK_UP2(image,ch,tx,mx).hp_quant = image->mb_row_context[ch][off2].hp_quant; + MACROBLK_UP3(image,ch,tx,mx).hp_quant = image->mb_row_context[ch][off3].hp_quant; + + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_CUR(image,ch,tx,mx).data[idx] = image->mb_row_context[ch][off0].data[idx]; + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_UP1(image,ch,tx,mx).data[idx] = image->mb_row_context[ch][off1].data[idx]; + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_UP2(image,ch,tx,mx).data[idx] = image->mb_row_context[ch][off2].data[idx]; + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_UP3(image,ch,tx,mx).data[idx] = image->mb_row_context[ch][off3].data[idx]; + } + } + } +} + + +/* +* When the parser calls this function, the current strip is done +* being parsed, so it no longer needs the previous strip. Complete +* the processing of the previous ("up") strip and arrange for it to +* be delivered to the applications. Then shuffle the current strip to +* the "up" position for the next round. +* +* cur_my is the number of the current line. If this is -1, then there +* are no lines complete yet and this function is being called to get +* things started. +*/ +void _jxr_rflush_mb_strip(jxr_image_t image, int tx, int ty, int my) +{ + /* This is the position within the image of the current + line. It accounts for the current tile row. */ + const int use_my = my + (ty>=0? image->tile_row_position[ty] : 0) - 1; + + DEBUG("rflush_mb_strip: cur_my=%d, tile-x/y=%d/%d, my=%d, use_my=%d\n", image->cur_my, tx, ty, my, use_my); + + if (image->tile_columns > 1 && tx >= 0) { + if (tx+1 < (int) image->tile_columns) { + /* We're actually working on a tile, and this is + not the last tile in the row. Deliver the data + to the correct tile buffer and return. */ + + if (my == 0 && image->cur_my >= 0) { + /* starting a new tile, dump previous */ + + if (tx == 0 && ty > 0) { + /* First column of a row */ + /* Complete last line of previous row */ + rflush_collect_mb_strip_data(image, image->cur_my); + /* Save previous strip context */ + rflush_save_context(image); + /* Flush last column of previous row. */ + rflush_to_tile_buffer(image, image->tile_columns-1, image->cur_my); + } else if (tx > 0) { + /* Column within a row, dump previous column */ + rflush_to_tile_buffer(image, tx-1, image->cur_my); + } + + } else if (image->cur_my >= 0) { + rflush_to_tile_buffer(image, tx, image->cur_my); + } + image->cur_my = my; + _jxr_r_rotate_mb_strip(image); + return; + + } else { + /* We are tiling, and this is the last tile of the + row, so collect rows from the left tiles to + finish the row, and proceed to processing. */ + if (my == 0) { + /* Starting last tile of row */ + /* Flush end of previous tile */ + rflush_to_tile_buffer(image, tx-1, image->cur_my); + image->cur_my = -1; + /* Recover previous strip context */ + if (ty > 0) { + rflush_recover_context(image); + } + } else if (my <= (int) image->tile_row_height[ty]) { + rflush_collect_mb_strip_data(image, image->cur_my); + } + } + } + + + if (use_my >= 1) { + int ch; + + /* Dequantize the PREVIOUS strip of macroblocks DC and LP. */ + + /* Reverse transform the DC/LP to 16 DC values. */ + + for (ch = 0 ; ch < image->num_channels ; ch += 1) + IPCT_level1_up1(image, use_my, ch); + + if (use_my >= 2) { + if (OVERLAP_INFO(image) >= 2) + for (ch = 0 ; ch < image->num_channels ; ch += 1) + overlap_level1_up2(image, use_my, ch); + + /* Do the second level IPCT transform to include HP values. */ + for (ch = 0 ; ch < image->num_channels ; ch += 1) + IPCT_level2_up2(image,use_my, ch); + + if (use_my >= 3) { + + /* Do the second level post filter */ + if (OVERLAP_INFO(image) >= 1) + for (ch = 0 ; ch < image->num_channels ; ch += 1) + overlap_level2_up3(image, use_my, ch); + + /* The reverse transformation is complete for the + PREVIOUS strip, so perform the "Output Formatting" + and deliver the data for the application. */ + + scale_and_emit_top(image, tx, use_my); + } + } + + /* read lwf test flag into image container */ + if (image->lwf_test == 0) + image->lwf_test = _jxr_read_lwf_test_flag(); + + } + + /* Now completely done with strip_up. Rotate the storage to + strip_down. */ + image->cur_my = my; + + _jxr_r_rotate_mb_strip(image); +} + +/* +* The input to this function is 256 samples arranged like this: +* +* DC..DC (16 DC values) HP..HP (240 HP values) +* +* Shuffle the values so that there is 1 DC, then 15 HP, and so on 16 +* times. This prepares the array for 16 calls to the 4x4IPCT transform. +*/ +static void dclphp_shuffle(int*data, int dclp_count) +{ + int tmp[256]; + int dc, hp, dst; + assert(dclp_count <= 16); + + for (dc=0, hp=16, dst=0; dc<dclp_count ; ) { + int idx; + tmp[dst++] = data[dc++]; + for (idx = 0 ; idx < 15 ; idx += 1) + tmp[dst++] = data[hp++]; + } + + assert(dst == 16*dclp_count); + assert(dc == dclp_count); + assert(hp == 16+15*dclp_count); + + for (dst = 0 ; dst<256 ; dst+=1) + data[dst] = tmp[dst]; +} + +/* +* The input to this function is 256 intensities arranged as blocks, +* with each 4x4 block in raster order is together, i.e. +* +* 00..0011..1122..22... +* +* It reorders the values into a raster order that is not blocked: +* +* 0000111122223333 +* 0000111122223333 +* 0000111122223333, etc. +*/ +static void unblock_shuffle444(int*data) +{ + int tmp[256]; + + int idx; + for (idx = 0 ; idx < 256 ; idx += 4) { + int blk = idx/16; + int mbx = blk%4; + int mby = blk/4; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*4*mby + 4*mbx + 16*py; + tmp[ptr+0] = data[idx+0]; + tmp[ptr+1] = data[idx+1]; + tmp[ptr+2] = data[idx+2]; + tmp[ptr+3] = data[idx+3]; + } + + for (idx = 0 ; idx < 256 ; idx += 1) + data[idx] = tmp[idx]; +} + +/* +* 0 1 2 3 16 17 18 19 +* 4 5 6 7 20 21 22 23 +* 8 9 10 11 24 25 26 27 +* 12 13 14 15 28 29 30 31 +* 32 33 34 35 48 49 50 51 +* 36 37 38 39 52 53 54 55 +* 40 41 42 43 56 57 58 59 +* 44 45 46 47 60 61 62 63 ... +*/ +static void unblock_shuffle422(int*data) +{ + int tmp[128]; + + int idx; + for (idx = 0 ; idx < 128 ; idx += 4) { + int blk = idx/16; + int mbx = blk%2; + int mby = blk/2; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*2*mby + 4*mbx + 8*py; + tmp[ptr+0] = data[idx+0]; + tmp[ptr+1] = data[idx+1]; + tmp[ptr+2] = data[idx+2]; + tmp[ptr+3] = data[idx+3]; + } + + for (idx = 0 ; idx < 128 ; idx += 1) + data[idx] = tmp[idx]; +} + +/* +* 0 1 2 3 16 17 18 19 +* 4 5 6 7 20 21 22 23 +* 8 9 10 11 24 25 26 27 +* 12 13 14 15 28 29 30 31 +* 32 33 34 35 48 49 50 51 +* 36 37 38 39 52 53 54 55 +* 40 41 42 43 56 57 58 59 +* 44 45 46 47 60 61 62 63 +*/ +static void unblock_shuffle420(int*data) +{ + int tmp[64]; + + int idx; + for (idx = 0 ; idx < 64 ; idx += 4) { + int blk = idx/16; + int mbx = blk%2; + int mby = blk/2; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*2*mby + 4*mbx + 8*py; + tmp[ptr+0] = data[idx+0]; + tmp[ptr+1] = data[idx+1]; + tmp[ptr+2] = data[idx+2]; + tmp[ptr+3] = data[idx+3]; + } + + for (idx = 0 ; idx < 64 ; idx += 1) + data[idx] = tmp[idx]; +} + +void _jxr_r_rotate_mb_strip(jxr_image_t image) +{ + if(image->primary) { + int ch; + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*tmp = image->strip[ch].up3; + image->strip[ch].up3 = image->strip[ch].up2; + image->strip[ch].up2 = image->strip[ch].up1; + image->strip[ch].up1 = image->strip[ch].cur; + image->strip[ch].cur = tmp; + } + + _jxr_clear_strip_cur(image); + + if (ALPHACHANNEL_FLAG(image)) { + struct macroblock_s*tmp = image->alpha->strip[0].up3; + image->alpha->strip[0].up3 = image->alpha->strip[0].up2; + image->alpha->strip[0].up2 = image->alpha->strip[0].up1; + image->alpha->strip[0].up1 = image->alpha->strip[0].cur; + image->alpha->strip[0].cur = tmp; + _jxr_clear_strip_cur(image->alpha); + } + } +} + + +/* +* $Log: r_strip.c,v $ +* Revision 1.53 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.52 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.51 2008/03/24 18:06:56 steve +* Imrpove DEBUG messages around quantization. +* +* Revision 1.50 2008/03/20 22:38:53 steve +* Use MB HPQP instead of first HPQP in decode. +* +* Revision 1.49 2008/03/18 21:09:11 steve +* Fix distributed color prediction. +* +* Revision 1.48 2008/03/17 23:48:12 steve +* Bias and Scaling for CMYK +* +* Revision 1.47 2008/03/17 21:48:56 steve +* CMYK decode support +* +* Revision 1.46 2008/03/14 17:08:51 gus +* *** empty log message *** +* +* Revision 1.45 2008/03/13 17:49:31 steve +* Fix problem with YUV422 CBP prediction for UV planes +* +* Add support for YUV420 encoding. +* +* Revision 1.44 2008/03/11 22:12:49 steve +* Encode YUV422 through DC. +* +* Revision 1.43 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.42 2008/03/03 23:33:53 steve +* Implement SHIFT_BITS functionality. +* +* Revision 1.41 2008/03/02 18:35:27 steve +* Add support for BD16 +* +* Revision 1.40 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.39 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.38 2008/01/08 23:23:18 steve +* Clean up some DEBUG messages. +* +* Revision 1.37 2008/01/04 17:07:35 steve +* API interface for setting QP values. +* +* Revision 1.36 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.35 2007/11/22 19:02:05 steve +* More fixes of color plane buffer sizes. +* +* Revision 1.34 2007/11/22 02:51:04 steve +* Fix YUV422 strip save byte count - buffer overrun +* +* Revision 1.33 2007/11/21 23:26:14 steve +* make all strip buffers store MB data. +* +* Revision 1.32 2007/11/21 00:34:30 steve +* Rework spatial mode tile macroblock shuffling. +* +* Revision 1.31 2007/11/20 17:08:02 steve +* Fix SPATIAL processing of QUANT values for color. +* +* Revision 1.30 2007/11/16 21:33:48 steve +* Store MB Quant, not qp_index. +* +* Revision 1.29 2007/11/16 20:03:57 steve +* Store MB Quant, not qp_index. +* +* Revision 1.28 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +* Revision 1.27 2007/11/09 01:18:58 steve +* Stub strip input processing. +* +* Revision 1.26 2007/11/06 21:45:04 steve +* Fix MB of previous tile in row. +* +* Revision 1.25 2007/11/06 01:39:22 steve +* Do not collect strip data for pad strips. +* +* Revision 1.24 2007/11/05 02:01:12 steve +* Add support for mixed row/column tiles. +* +* Revision 1.23 2007/11/02 21:06:07 steve +* Filtering when tile rows are present. +* +* Revision 1.22 2007/11/02 00:19:06 steve +* Fix Multiple rows of tiles strip flush. +* +* Revision 1.21 2007/11/01 21:09:40 steve +* Multiple rows of tiles. +* +* Revision 1.20 2007/10/30 21:32:46 steve +* Support for multiple tile columns. +* +* Revision 1.19 2007/10/23 00:34:12 steve +* Level1 filtering for YUV422 and YUV420 +* +* Revision 1.18 2007/10/22 22:33:12 steve +* Level2 filtering for YUV422 +* +* Revision 1.17 2007/10/22 21:52:37 steve +* Level2 filtering for YUV420 +* +* Revision 1.16 2007/10/19 22:07:36 steve +* Clean up YUV420 to YUV444 conversion corner cases. +* +* Revision 1.15 2007/10/19 20:48:53 steve +* Convert YUV420 to YUV444 works. +* +* Revision 1.14 2007/10/17 23:43:20 steve +* Add support for YUV420 +* +* Revision 1.13 2007/10/01 20:39:34 steve +* Add support for YUV422 LP bands. +* +* Revision 1.12 2007/09/20 18:04:11 steve +* support render of YUV422 images. +* +* Revision 1.11 2007/09/12 01:10:22 steve +* Fix rounding/floor/ceil of YUV to RGB transform. +* +* Revision 1.10 2007/09/11 00:40:06 steve +* Fix rendering of chroma to add the missing *2. +* Fix handling of the chroma LP samples +* Parse some of the HP CBP data in chroma. +* +* Revision 1.9 2007/09/10 23:02:48 steve +* Scale chroma channels? +* +* Revision 1.8 2007/09/08 01:01:44 steve +* YUV444 color parses properly. +* +* Revision 1.7 2007/09/04 19:10:46 steve +* Finish level1 overlap filtering. +* +* Revision 1.6 2007/08/15 01:54:11 steve +* Add level2 filter to decoder. +* +* Revision 1.5 2007/08/13 22:55:12 steve +* Cleanup rflush_md_strip function. +* +* Revision 1.4 2007/08/02 22:48:27 steve +* Add missing clip of calculated values. +* +* Revision 1.3 2007/07/21 00:25:48 steve +* snapshot 2007 07 20 +* +* Revision 1.2 2007/07/11 00:53:36 steve +* HP adaptation and precition corrections. +* +* Revision 1.1 2007/06/28 20:03:11 steve +* LP processing seems to be OK now. +* +*/ + diff --git a/jpegxr/r_tile_frequency.c b/jpegxr/r_tile_frequency.c new file mode 100644 index 000000000..5b70e3db1 --- /dev/null +++ b/jpegxr/r_tile_frequency.c @@ -0,0 +1,699 @@ +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: r_tile_frequency.c,v 1.14 2008/03/18 21:34:04 steve Exp $") +#else +#ident "$Id: r_tile_frequency.c,v 1.14 2008/03/18 21:34:04 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + +static void backup_dc_strip(jxr_image_t image, int tx, int ty, int my); +static void backup_dclp_strip(jxr_image_t image, int tx, int ty, int my); +static void backup_hp_strip(jxr_image_t image, int tx, int ty, int my); +static void recover_dc_strip(jxr_image_t image, int tx, int ty, int my); +static void recover_dclp_strip(jxr_image_t image, int tx, int ty, int my); +static void recover_dclphp_strip(jxr_image_t image, int tx, int ty, int my); + +int _jxr_r_TILE_DC(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned mx, my; + unsigned mb_height; + unsigned mb_width; + unsigned char s0, s1, s2, s3; + DEBUG("START TILE_DC at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + s0 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s1 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s2 = _jxr_rbitstream_uint8(str); /* 0x01 */ + s3 = _jxr_rbitstream_uint8(str); /* reserved */ + DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3); + + _jxr_r_TILE_HEADER_DC(image, str, 0 /* alpha */, tx, ty); + if (ALPHACHANNEL_FLAG(image)) + _jxr_r_TILE_HEADER_DC(image->alpha, str, 1, tx, ty); + + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + for (my = 0 ; my < mb_height ; my += 1) { + _jxr_r_rotate_mb_strip(image); + image->cur_my = my; + for (mx = 0 ; mx < mb_width ; mx += 1) { + _jxr_r_MB_DC(image, str, 0, tx, ty, mx, my); + if (image->bands_present == 3 /* DCONLY */) + _jxr_complete_cur_dclp(image, tx, mx, my); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_r_MB_DC(image->alpha, str, 1, tx, ty, mx, my); + if (image->alpha->bands_present == 3 /* DCONLY */) + _jxr_complete_cur_dclp(image->alpha, tx, mx, my); + } + } + + if (ALPHACHANNEL_FLAG(image)) + backup_dc_strip(image->alpha, tx, ty, my); + + backup_dc_strip(image, tx, ty, my); + } + + _jxr_rbitstream_syncbyte(str); + DEBUG("END TILE_DC\n"); + + return 0; +} + +int _jxr_r_TILE_LP(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned mx, my; + unsigned plane_idx, num_planes; + unsigned mb_height; + unsigned mb_width; + unsigned char s0, s1, s2, s3; + DEBUG("START TILE_LOWPASS at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + s0 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s1 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s2 = _jxr_rbitstream_uint8(str); /* 0x01 */ + s3 = _jxr_rbitstream_uint8(str); /* reserved */ + DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3); + if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) { + DEBUG(" TILE_LOWPASS ERROR: Invalid marker.\n"); + return JXR_EC_ERROR; + } + + _jxr_r_TILE_HEADER_LOWPASS(image, str, 0 /* alpha */, tx, ty); + if (ALPHACHANNEL_FLAG(image)) + _jxr_r_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty); + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1); + for (my = 0 ; my < mb_height ; my += 1) { + _jxr_r_rotate_mb_strip(image); + if (ALPHACHANNEL_FLAG(image)) { + image->alpha->cur_my = my; + recover_dc_strip(image->alpha, tx, ty, my); + } + image->cur_my = my; + recover_dc_strip(image, tx, ty, my); + + for (mx = 0 ; mx < mb_width ; mx += 1) + for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) { + /* The qp_index_lp table goes only into channel 0 */ + int qp_index_lp = 0; + int ch; + jxr_image_t plane = (plane_idx == 0 ? image : image->alpha); + + if (!plane->lp_use_dc_qp && plane->num_lp_qps>1) { + qp_index_lp = _jxr_DECODE_QP_INDEX(str, plane->num_lp_qps); + DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", plane->num_lp_qps, qp_index_lp); + } + for (ch = 0 ; ch < plane->num_channels ; ch += 1) { + MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx) = qp_index_lp; + DEBUG(" LP_QUANT for MBx=%d ch=%d is %d\n", mx, ch, MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx)); + } + _jxr_r_MB_LP(plane, str, 0, tx, ty, mx, my); + if (plane->bands_present != 3 /* !DCONLY */) + _jxr_complete_cur_dclp(plane, tx, mx, my); + + } + if (ALPHACHANNEL_FLAG(image)) + backup_dclp_strip(image->alpha, tx, ty, my); + backup_dclp_strip(image, tx, ty, my); + } + + _jxr_rbitstream_syncbyte(str); + DEBUG("END TILE_LOWPASS\n"); + return 0; +} + +int _jxr_r_TILE_HP(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned mx, my; + unsigned plane_idx, num_planes; + unsigned mb_height; + unsigned mb_width; + unsigned char s0, s1, s2, s3; + DEBUG("START TILE_HIGHPASS at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + s0 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s1 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s2 = _jxr_rbitstream_uint8(str); /* 0x01 */ + s3 = _jxr_rbitstream_uint8(str); /* reserved */ + DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3); + if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) { + DEBUG(" TILE_HIGHPASS ERROR: Invalid marker.\n"); + return JXR_EC_ERROR; + } + + _jxr_r_TILE_HEADER_HIGHPASS(image, str, 0 /* alpha */, tx, ty); + if (ALPHACHANNEL_FLAG(image)) + _jxr_r_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty); + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1); + for (my = 0 ; my < mb_height ; my += 1) { + _jxr_r_rotate_mb_strip(image); + + if (ALPHACHANNEL_FLAG(image)) { + image->alpha->cur_my = my; + recover_dclp_strip(image->alpha, tx, ty, my); + } + image->cur_my = my; + recover_dclp_strip(image, tx, ty, my); + + for (mx = 0 ; mx < mb_width ; mx += 1) + for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) { + /* The qp_index_hp table goes only into channel 0 */ + int qp_index_hp = 0; + int ch; + int rc; + jxr_image_t plane = (plane_idx == 0 ? image : image->alpha); + if (plane->num_hp_qps>1) { + if (!plane->hp_use_lp_qp) + qp_index_hp = _jxr_DECODE_QP_INDEX(str, plane->num_hp_qps); + else + qp_index_hp = MACROBLK_CUR_LP_QUANT(plane,0,tx,mx); + } + DEBUG(" HP_QP_INDEX for MBx=%d is %d\n", mx, qp_index_hp); + for (ch = 0 ; ch < plane->num_channels ; ch += 1) { + MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx) = plane->hp_quant_ch[ch][qp_index_hp]; + DEBUG(" HP_QUANT for MBx=%d ch=%d is %d\n", mx, ch, MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx)); + } + + rc = _jxr_r_MB_CBP(plane, str, 0, tx, ty, mx, my); + if (rc < 0) { + DEBUG("r_MB_CBP returned ERROR rc=%d\n", rc); + return rc; + } + rc = _jxr_r_MB_HP(plane, str, 0, tx, ty, mx, my); + if (rc < 0) { + DEBUG("r_MB_HP returned ERROR rc=%d\n", rc); + return rc; + } + } + if (ALPHACHANNEL_FLAG(image)) + backup_hp_strip(image->alpha, tx, ty, my); + backup_hp_strip(image, tx, ty, my); + } + + _jxr_rbitstream_syncbyte(str); + DEBUG("END TILE_HIGHPASS\n"); + return 0; +} + +int _jxr_r_TILE_FLEXBITS(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty) +{ + int mx, my; + int plane_idx, num_planes; + unsigned mb_height; + unsigned mb_width; + int use_num_channels; + unsigned char s0, s1, s2, s3; + + DEBUG("START TILE_FLEXBITS at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + s0 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s1 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s2 = _jxr_rbitstream_uint8(str); /* 0x01 */ + s3 = _jxr_rbitstream_uint8(str); /* reserved */ + DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3); + if (s0 != 0x00 || s1 != 0x00 || s2 != 0x01) { + DEBUG(" TILE_FLEXBITS ERROR: Invalid marker.\n"); + return JXR_EC_ERROR; + } + + image->trim_flexbits = 0; + if (TRIM_FLEXBITS_FLAG(image)) { + image->trim_flexbits =_jxr_rbitstream_uint4(str); + DEBUG(" TRIM_FLEXBITS = %u\n", image->trim_flexbits); + } + + use_num_channels = image->num_channels; + if (image->use_clr_fmt == 1/*YUV420*/ || image->use_clr_fmt == 2/*YUV422*/) + use_num_channels = 1; + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1); + for (my = 0 ; my < (int) mb_height ; my += 1) { + _jxr_r_rotate_mb_strip(image); + if (ALPHACHANNEL_FLAG(image)) { + image->alpha->cur_my = my; + recover_dclphp_strip(image->alpha, tx, ty, my); + } + image->cur_my = my; + recover_dclphp_strip(image, tx, ty, my); + + for (mx = 0 ; mx < (int) mb_width ; mx += 1) + for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) { + jxr_image_t plane = (plane_idx == 0 ? image : image->alpha); + int channels = (plane_idx == 0 ? use_num_channels : 1); + int rc = _jxr_r_MB_FLEXBITS(plane, str, 0, tx, ty, mx, my); + int mbhp_pred_mode; + int idx; + if (rc < 0) { + DEBUG("r_MB_FLEXBITS returned ERROR rc=%d\n", rc); + return rc; + } + + /* Now the HP values are complete, so run the propagation + process. This involves recovering some bits of data saved + by the HP tile. */ + mbhp_pred_mode = MACROBLK_CUR(plane,0,tx,mx).mbhp_pred_mode; + for (idx = 0 ; idx < channels ; idx += 1) { + DEBUG(" MB_FLEXBITS: propagate HP predictions in MB_FLEXBITS\n"); + _jxr_propagate_hp_predictions(plane, idx, tx, mx, mbhp_pred_mode); + } + } + if (ALPHACHANNEL_FLAG(image)) + backup_hp_strip(image->alpha, tx, ty, my); + backup_hp_strip(image, tx, ty, my); + } + + _jxr_rbitstream_syncbyte(str); + DEBUG("END TILE_FLEXBITS bitpos=%zu\n", _jxr_rbitstream_bitpos(str)); + return 0; +} + +/* +* This function handles the special case that the FLEXBITS tile is +* escaped away. Do all the soft processing that is otherwise needed. +*/ +int _jxr_r_TILE_FLEXBITS_ESCAPE(jxr_image_t image, unsigned tx, unsigned ty) +{ + int use_num_channels = image->num_channels; + unsigned mb_height = EXTENDED_HEIGHT_BLOCKS(image); + unsigned mb_width = EXTENDED_WIDTH_BLOCKS(image); + int mx, my; + + DEBUG("START TILE_FLEXBITS_ESCAPE at tile=[%u %u]\n", tx, ty); + + if (image->use_clr_fmt == 1/*YUV420*/ || image->use_clr_fmt == 2/*YUV422*/) + use_num_channels = 1; + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + for (my = 0 ; my < (int) mb_height ; my += 1) { + _jxr_r_rotate_mb_strip(image); + image->cur_my = my; + recover_dclphp_strip(image, tx, ty, my); + + for (mx = 0 ; mx < (int) mb_width ; mx += 1) { + /* */ + int mbhp_pred_mode = MACROBLK_CUR(image,0,tx,mx).mbhp_pred_mode; + int idx; + for (idx = 0 ; idx < use_num_channels ; idx += 1) { + DEBUG(" MB_FLEXBITS_ESCAPE: propagate HP predictions in MB_FLEXBITS\n"); + _jxr_propagate_hp_predictions(image, idx, tx, mx, mbhp_pred_mode); + } + } + backup_hp_strip(image, tx, ty, my); + } + + DEBUG("END TILE_FLEXBIT_ESCAPE\n"); + return 0; +} + +static void backup_dc_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + + int ch; + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + mb[mx].data[0] = MACROBLK_CUR_DC(image,ch,tx,mx); + DEBUG(" backup_dc_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d, DC=0x%0x8\n", + tx, ty, mx, my, ch, mb[mx].data[0]); + } + } +} + +static void backup_dclp_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + + + int format_scale = 15; + int ch; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 7; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 3; + } + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + int count = ch==0? 15 : format_scale; + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int idx; + mb[mx].data[0] = MACROBLK_CUR_DC(image,ch,tx,mx); + DEBUG(" backup_dclp_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d, DC=0x%x, LP=", + tx, ty, mx, my, ch, mb[mx].data[0]); + for (idx = 0 ; idx < count ; idx += 1) { + mb[mx].data[idx+1] = MACROBLK_CUR_LP(image,ch,tx,mx,idx); + DEBUG(" 0x%x", mb[mx].data[idx+1]); + } + DEBUG("\n"); + mb[mx].lp_quant = MACROBLK_CUR_LP_QUANT(image,ch,tx,mx); + } + } +} + +static void backup_hp_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + + + int format_scale = 16; + int ch; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 8; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 4; + } + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + int count = ch==0? 16 : format_scale; + + if (ch == 0) { + /* Backup also the hp_model_bits, which are + stored only in the channel-0 blocks. */ + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + mb[mx].hp_model_bits[0] = MACROBLK_CUR(image,0,tx,mx).hp_model_bits[0]; + mb[mx].hp_model_bits[1] = MACROBLK_CUR(image,0,tx,mx).hp_model_bits[1]; + mb[mx].mbhp_pred_mode = MACROBLK_CUR(image,0,tx,mx).mbhp_pred_mode; + } + } + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int blk; + mb[mx].data[0] = MACROBLK_CUR_DC(image,ch,tx,mx); + DEBUG(" backup_hp_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d\n", + tx, ty, mx, my, ch); + for (blk = 0 ; blk < count ; blk += 1) { + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) + mb[mx].data[count+15*blk+idx] = MACROBLK_CUR_HP(image,ch,tx,mx,blk,idx); + } + mb[mx].hp_quant = MACROBLK_CUR_HP_QUANT(image,ch,tx,mx); + } + } +} + +static void recover_dc_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + + int ch; + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + MACROBLK_CUR_DC(image,ch,tx,mx) = mb[mx].data[0]; + DEBUG(" recover_dc_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d, DC=0x%0x8\n", + tx, ty, mx, my, ch, mb[mx].data[0]); + } + } +} + +static void recover_dclp_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + int ch; + + int format_scale = 15; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 7; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 3; + } + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + int count = ch==0? 15 : format_scale; + + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int idx; + MACROBLK_CUR_DC(image,ch,tx,mx) = mb[mx].data[0]; + DEBUG(" recover_dclp_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d, DC=0x%0x8, LP=\n", + tx, ty, mx, my, ch, mb[mx].data[0]); + for (idx = 0 ; idx < count ; idx += 1) { + MACROBLK_CUR_LP(image,ch,tx,mx,idx) = mb[mx].data[idx+1]; + DEBUG(" 0x%x", mb[mx].data[idx+1]); + } + DEBUG("\n"); + MACROBLK_CUR_LP_QUANT(image,ch,tx,mx) = mb[mx].lp_quant; + } + } +} + +static void recover_dclphp_strip(jxr_image_t image, int tx, int ty, int my) +{ + int mx; + int use_my = my + image->tile_row_position[ty]; + int use_mx = image->tile_column_position[tx]; + int ptr = use_my*EXTENDED_WIDTH_BLOCKS(image) + use_mx; + + int format_scale = 16; + int ch; + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 8; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 4; + } + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + ptr; + int count = ch==0? 16 : format_scale; + + if (ch == 0) { + /* Recover also the hp_model_bits, which are + stored only in the channel-0 blocks. */ + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + MACROBLK_CUR(image,0,tx,mx).hp_model_bits[0] = mb[mx].hp_model_bits[0]; + MACROBLK_CUR(image,0,tx,mx).hp_model_bits[1] = mb[mx].hp_model_bits[1]; + MACROBLK_CUR(image,0,tx,mx).mbhp_pred_mode = mb[mx].mbhp_pred_mode; + } + } + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int blk; + MACROBLK_CUR_DC(image,ch,tx,mx) = mb[mx].data[0]; + DEBUG(" recover_dclphp_strip: tx=%d, ty=%d, mx=%d, my=%d, ch=%d, DC=0x%0x8, LP=\n", + tx, ty, mx, my, ch, mb[mx].data[0]); + for (blk = 1 ; blk < count ; blk += 1) { + MACROBLK_CUR_LP(image,ch,tx,mx,blk-1) = mb[mx].data[blk]; + DEBUG(" 0x%x", mb[mx].data[blk]); + } + + for (blk = 0 ; blk < count ; blk += 1) { + int idx; + for (idx = 0 ; idx < 15 ; idx += 1) { + int data_ptr = count+15*blk+idx; + MACROBLK_CUR_HP(image,ch,tx,mx,blk,idx) = mb[mx].data[data_ptr]; + } + } + DEBUG("\n"); + MACROBLK_CUR_LP_QUANT(image,ch,tx,mx) = mb[mx].lp_quant; + MACROBLK_CUR_HP_QUANT(image,ch,tx,mx) = mb[mx].hp_quant; + } + } +} + +void _jxr_frequency_mode_render(jxr_image_t image) +{ + + int ty; + for (ty = 0 ; ty < (int) image->tile_rows ; ty += 1) { + int my; + for (my = 0 ; my < (int) image->tile_row_height[ty] ; my += 1) { + int tx; + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, -1, -1, my + image->alpha->tile_row_position[ty]); + _jxr_rflush_mb_strip(image, -1, -1, my + image->tile_row_position[ty]); + for (tx = 0 ; tx < (int) image->tile_columns ; tx += 1) { + if (ALPHACHANNEL_FLAG(image)) + recover_dclphp_strip(image->alpha, tx, ty, my); + recover_dclphp_strip(image, tx, ty, my); + } + } + } + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, -1, -1, EXTENDED_HEIGHT_BLOCKS(image->alpha)+0); + _jxr_rflush_mb_strip(image, -1, -1, EXTENDED_HEIGHT_BLOCKS(image)+0); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, -1, -1, EXTENDED_HEIGHT_BLOCKS(image->alpha)+1); + _jxr_rflush_mb_strip(image, -1, -1, EXTENDED_HEIGHT_BLOCKS(image)+1); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, -1, -1, EXTENDED_HEIGHT_BLOCKS(image->alpha)+2); + _jxr_rflush_mb_strip(image, -1, -1, EXTENDED_HEIGHT_BLOCKS(image)+2); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, -1, -1, EXTENDED_HEIGHT_BLOCKS(image->alpha)+3); + _jxr_rflush_mb_strip(image, -1, -1, EXTENDED_HEIGHT_BLOCKS(image)+3); +} + +/* +* $Log: r_tile_frequency.c,v $ +* Revision 1.16 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.15 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.14 2008/03/18 21:34:04 steve +* Fix distributed color prediction. +* +* Revision 1.13 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.12 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.11 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.10 2007/11/21 00:34:30 steve +* Rework spatial mode tile macroblock shuffling. +* +* Revision 1.9 2007/11/20 00:05:47 steve +* Complex handling of mbhp_pred_mode in frequency dmoe. +* +* Revision 1.8 2007/11/16 21:33:48 steve +* Store MB Quant, not qp_index. +* +* Revision 1.7 2007/11/16 20:03:57 steve +* Store MB Quant, not qp_index. +* +* Revision 1.6 2007/11/16 17:33:24 steve +* Do HP prediction after FLEXBITS frequency tiles. +* +* Revision 1.5 2007/11/16 00:29:06 steve +* Support FREQUENCY mode HP and FLEXBITS +* +* Revision 1.4 2007/11/15 17:44:13 steve +* Frequency mode color support. +* +* Revision 1.3 2007/11/14 23:56:17 steve +* Fix TILE ordering, using seeks, for FREQUENCY mode. +* +* Revision 1.2 2007/11/13 03:27:23 steve +* Add Frequency mode LP support. +* +* Revision 1.1 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +*/ + diff --git a/jpegxr/r_tile_spatial.c b/jpegxr/r_tile_spatial.c new file mode 100644 index 000000000..4f43c0518 --- /dev/null +++ b/jpegxr/r_tile_spatial.c @@ -0,0 +1,380 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: r_tile_spatial.c,v 1.53 2008/03/20 22:39:41 steve Exp $") +#else +#ident "$Id: r_tile_spatial.c,v 1.53 2008/03/20 22:39:41 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + + + +/* +* Process a single spatial time. The tx/ty is the coordintes of the +* tile in units of tiles. tx=0 for the first time, tx=1 for the +* second, and so forth. +*/ +int _jxr_r_TILE_SPATIAL(jxr_image_t image, struct rbitstream*str, + unsigned tx, unsigned ty) +{ + int rc = 0; + unsigned mx, my, plane_idx; + unsigned char s0, s1, s2, s3; + unsigned mb_height; + unsigned mb_width; + + DEBUG("START TILE_SPATIAL at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_rbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + s0 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s1 = _jxr_rbitstream_uint8(str); /* 0x00 */ + s2 = _jxr_rbitstream_uint8(str); /* 0x01 */ + s3 = _jxr_rbitstream_uint8(str); /* reserved */ + DEBUG(" TILE_STARTCODE == %02x %02x %02x (reserved: %02x)\n", s0, s1, s2, s3); + + image->trim_flexbits = 0; + if (TRIM_FLEXBITS_FLAG(image)) { + image->trim_flexbits =_jxr_rbitstream_uint4(str); + DEBUG(" TRIM_FLEXBITS = %u\n", image->trim_flexbits); + } + + /* Read the tile header (which includes sub-headers for + all the major passes). */ + + _jxr_r_TILE_HEADER_DC(image, str, 0, tx, ty); + if (image->bands_present != 3 /* DCONLY */) { + _jxr_r_TILE_HEADER_LOWPASS(image, str, 0, tx, ty); + + if (image->bands_present != 2 /* NO_HIGHPASS */) { + _jxr_r_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty); + } + } + + /* If the alpha channel is present, then run another set of + headers for the alpha channel. */ + if (ALPHACHANNEL_FLAG(image)) { + _jxr_r_TILE_HEADER_DC(image->alpha, str, 1, tx, ty); + if (image->bands_present != 3 /* DCONLY */) { + _jxr_r_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty); + + if (image->bands_present != 2 /* NO_HIGHPASS */) { + _jxr_r_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty); + } + } + } + + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + for (my = 0 ; my < mb_height ; my += 1) { + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, tx, ty, my); + _jxr_rflush_mb_strip(image, tx, ty, my); + + for (mx = 0 ; mx < mb_width ; mx += 1) { + for(plane_idx = 0U; plane_idx < (ALPHACHANNEL_FLAG(image) ? 2U : 1U); plane_idx ++){ + int ch; + + /* There is one LP_QP_INDEX per macroblock (if any) + and that value applies to all the channels. + Same for HP_QP_INDEX. There is no DC_QP_INDEX + because DC QP values are per-tile, not per MB. */ + int qp_index_lp = 0; + int qp_index_hp = 0; + jxr_image_t plane = (plane_idx == 0 ? image : image->alpha); + + if (plane->bands_present!=3) { + if (plane->num_lp_qps>1 && !plane->lp_use_dc_qp) { + qp_index_lp = _jxr_DECODE_QP_INDEX(str, plane->num_lp_qps); + DEBUG(" DECODE_QP_INDEX(%d) --> %u (LP)\n", plane->num_lp_qps, qp_index_lp); + } + qp_index_hp = 0; + if (plane->bands_present!=2 && plane->num_hp_qps>1) { + if (!plane->hp_use_lp_qp) { + qp_index_hp = _jxr_DECODE_QP_INDEX(str, plane->num_hp_qps); + DEBUG(" DECODE_QP_INDEX(%d) --> %u (HP)\n", plane->num_hp_qps, qp_index_hp); + } + else { + qp_index_hp = qp_index_lp; + } + } + } + for (ch = 0 ; ch < plane->num_channels ; ch += 1) { + /* Save the LP Quant *INDEX* here. Prediction needs it. */ + MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx) = qp_index_lp; + DEBUG(" LP_QUANT INDEX for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx, + MACROBLK_CUR_LP_QUANT(plane,ch,tx,mx)); + MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx) = plane->hp_quant_ch[ch][qp_index_hp]; + DEBUG(" HP_QUANT VALUE for tx=%u ty=%u ch=%u MBx=%d is %d\n", tx, ty, ch, mx, + MACROBLK_CUR_HP_QUANT(plane,ch,tx,mx)); + } + + _jxr_r_MB_DC(plane, str, plane_idx, tx, ty, mx, my); + if (plane->bands_present != 3 /* DCONLY */) { + _jxr_r_MB_LP(plane, str, plane_idx, tx, ty, mx, my); + _jxr_complete_cur_dclp(plane, tx, mx, my); + if (plane->bands_present != 2 /* NOHIGHPASS */) { + rc = _jxr_r_MB_CBP(plane, str, plane_idx, tx, ty, mx, my); + if (rc < 0) { + DEBUG("r_MB_CBP returned ERROR rc=%d\n", rc); + return rc; + } + rc = _jxr_r_MB_HP(plane, str, plane_idx, tx, ty, mx, my); + if (rc < 0) { + DEBUG("r_MB_HP returned ERROR rc=%d\n", rc); + return rc; + } + } + } else { + _jxr_complete_cur_dclp(plane, tx, mx, my); + } + } + } + } + + /* Flush the remaining strips to output. */ + if (tx+1 == image->tile_columns && ty+1 == image->tile_rows) { + DEBUG(" Cleanup flush after last tile (tx=%d, ty=%d)\n", tx, ty); + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height); + _jxr_rflush_mb_strip(image, tx, ty, mb_height); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+1); + _jxr_rflush_mb_strip(image, tx, ty, mb_height+1); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+2); + _jxr_rflush_mb_strip(image, tx, ty, mb_height+2); + + if (ALPHACHANNEL_FLAG(image)) + _jxr_rflush_mb_strip(image->alpha, tx, ty, mb_height+3); + _jxr_rflush_mb_strip(image, tx, ty, mb_height+3); + } + _jxr_rbitstream_syncbyte(str); + DEBUG("END TILE_SPATIAL\n"); + return 0; +} + +/* +* $Log: r_tile_spatial.c,v $ +* Revision 1.55 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.54 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.53 2008/03/20 22:39:41 steve +* Fix various debug prints of QP data. +* +* Revision 1.52 2008/03/20 18:11:25 steve +* Handle case of NumLPQP==1 and NumHPQPS>1 +* +* Revision 1.51 2008/03/18 21:09:12 steve +* Fix distributed color prediction. +* +* Revision 1.50 2008/03/07 19:00:52 steve +* Improved comments. +* +* Revision 1.49 2008/03/06 22:47:39 steve +* Clean up parsing/encoding of QP counts +* +* Revision 1.48 2008/03/06 02:05:48 steve +* Distributed quantization +* +* Revision 1.47 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.46 2007/11/26 01:47:15 steve +* Add copyright notices per MS request. +* +* Revision 1.45 2007/11/21 23:26:14 steve +* make all strip buffers store MB data. +* +* Revision 1.44 2007/11/20 17:08:02 steve +* Fix SPATIAL processing of QUANT values for color. +* +* Revision 1.43 2007/11/16 21:33:48 steve +* Store MB Quant, not qp_index. +* +* Revision 1.42 2007/11/16 20:03:57 steve +* Store MB Quant, not qp_index. +* +* Revision 1.41 2007/11/16 00:29:06 steve +* Support FREQUENCY mode HP and FLEXBITS +* +* Revision 1.40 2007/11/14 23:56:17 steve +* Fix TILE ordering, using seeks, for FREQUENCY mode. +* +* Revision 1.39 2007/11/14 00:17:27 steve +* Fix parsing of QP indices. +* +* Revision 1.38 2007/11/13 03:27:24 steve +* Add Frequency mode LP support. +* +* Revision 1.37 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +* Revision 1.36 2007/11/08 19:38:38 steve +* Get stub DCONLY compression to work. +* +* Revision 1.35 2007/11/01 21:09:40 steve +* Multiple rows of tiles. +* +* Revision 1.34 2007/10/31 21:20:54 steve +* Init, not Adapt, on tile boundaries. +* +* Revision 1.33 2007/10/30 21:32:46 steve +* Support for multiple tile columns. +* +* Revision 1.32 2007/10/19 16:20:21 steve +* Parse YUV420 HP +* +* Revision 1.31 2007/10/04 23:03:26 steve +* HP blocks uf YUV42X chroma are not shuffled. +* +* Revision 1.30 2007/10/04 00:30:47 steve +* Fix prediction of HP CBP for YUV422 data. +* +* Revision 1.29 2007/10/02 20:36:29 steve +* Fix YUV42X DC prediction, add YUV42X HP parsing. +* +* Revision 1.28 2007/10/01 20:39:34 steve +* Add support for YUV422 LP bands. +* +* Revision 1.27 2007/09/18 17:00:50 steve +* Fix bad calculation of lap_mean for chroma. +* +* Revision 1.26 2007/09/13 23:12:34 steve +* Support color HP bands. +* +* Revision 1.25 2007/09/12 01:09:24 steve +* Dump the TRIM_FLEXBITS value. +* +* Revision 1.24 2007/09/11 01:06:12 steve +* Forgot to properly save LP data. +* +* Revision 1.23 2007/09/11 00:40:06 steve +* Fix rendering of chroma to add the missing *2. +* Fix handling of the chroma LP samples +* Parse some of the HP CBP data in chroma. +* +* Revision 1.22 2007/09/10 23:42:00 steve +* Fix LP processing steps when color involved. +* +* Revision 1.21 2007/09/08 01:01:44 steve +* YUV444 color parses properly. +* +* Revision 1.20 2007/09/04 22:48:09 steve +* Fix calculation of flex bits on 0 coefficients. +* +* Revision 1.19 2007/09/04 19:10:46 steve +* Finish level1 overlap filtering. +* +* Revision 1.18 2007/08/31 23:31:49 steve +* Initialize CBP VLC tables at the right time. +* +* Revision 1.17 2007/08/31 23:20:57 steve +* Dump MB_CBP details. +* +* Revision 1.16 2007/08/15 01:54:11 steve +* Add level2 filter to decoder. +* +* Revision 1.15 2007/08/13 22:24:43 steve +* Fix Reset Context of absLevelInd. +* +* Revision 1.14 2007/07/31 15:27:19 steve +* Get transpose of FLEXBITS right. +* +* Revision 1.13 2007/07/30 23:09:57 steve +* Interleave FLEXBITS within HP block. +* +* Revision 1.12 2007/07/24 20:56:28 steve +* Fix HP prediction and model bits calculations. +* +* Revision 1.11 2007/07/21 00:25:48 steve +* snapshot 2007 07 20 +* +* Revision 1.10 2007/07/12 22:48:17 steve +* Decode FLEXBITS +* +* Revision 1.9 2007/07/11 00:53:36 steve +* HP adaptation and precition corrections. +* +* Revision 1.8 2007/07/06 23:18:41 steve +* calculate and propagate HP band predictions. +* +* Revision 1.7 2007/07/05 20:19:13 steve +* Fix accumulation of HP CBP, and add HP predictions. +* +* Revision 1.6 2007/07/03 20:45:11 steve +* Parse and place HP data. +* +* Revision 1.5 2007/06/28 20:03:11 steve +* LP processing seems to be OK now. +* +* Revision 1.4 2007/06/21 17:31:22 steve +* Successfully parse LP components. +* +* Revision 1.3 2007/06/11 20:00:09 steve +* Parse FLEXBITS +* +* Revision 1.2 2007/06/07 18:53:06 steve +* Parse HP coeffs that are all 0. +* +* Revision 1.1 2007/06/06 17:19:12 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/sample.qp b/jpegxr/sample.qp new file mode 100644 index 000000000..50f3de15d --- /dev/null +++ b/jpegxr/sample.qp @@ -0,0 +1,96 @@ + +# This is a sample QP map file that defines a QP map for a +# color image with a tile 4x4 macroblocks. The format is simple enough +# and this example illustrates all the aspects of the format. +# +# The file is free-formatted. Comments start with a '#' and continue +# to the end of the text line. white space separates tokens and can be +# used freely. Keywords are case sensitive, and numbers are unsigned +# decimal. + +# The complete list of keywords is: +# +# DC, HP, LP, channel, independent, separate, tile, uniform +# + +# A tile section is needed for each tile in the image to compress. The +# values in the () are the column and row of the tile that you are +# configuring. In this case, the (0,0) means this is the upper left tile. +tile (0,0) { + + # Specify a component mode. The value values are: + # + # uniform - all the components are the same. In this case, you + # only need to specify channel 0, and all the other + # channels will copy their values from that channel. + # + # separate - The first channel uses one QP set, and all the other + # channels use another QP set. You will only need to + # specify channel-0 and channel-1. + # independent + # - All the channels have their own channel set. You + # need to specify the channel set for all the channels + # in the image. + separate + + # Next, give all the QP parameters for the channels that you + # need. For each channel, specify the DC, LP and HP qp values. The + # QP values range from 0-255 inclusive, with 0 being lossless and + # 255 being most lossy. + # + # There is always exactly 1 DC QP value for each channel. + # + # There is at least 1 and at most 16 LP(HP) QP values, and the + # number of LP(HP) values must be the same for each channel. For + # example, if channel 0 has 2 LP values, channel 1 must also have 2 + # LP values. The same is true for HP values. (There can be different + # numbers of LP and HP QP values. For example, it is OK to have 2 LP + # QP values and 1 HP QP value. + channel 0 { + DC { 1 } + LP { 1, 100 } + HP { 1, 150 } + } + # Note that the comma listing the QP values is optional. + channel 1 { + DC { 5 } + LP { 5 240 } + HP { 5 250 } + } + + # Finally, map each macroblock to an LP(HP) QP value by specifying + # the index here. For this step you need the dimensions of the tile + # in macroblocks, and you need to specify a map value for each + # macroblock. In this example, there are 16 macroblocks in this tile + # (it doesn't matter if they are arranged 4x4 or 8x2 or whatever) + # and they are assigned in raster order. + # + # The number in the map is an index into the LP or HP list above, + # and can range from 0 to the number of items in the list above. For + # example, in this example the channels have 2 LP QP values so the + # index value can be 0 or 1. If there were 5 LP QP items then the + # values would range from 0-4. + # + # You need to map the LP and HP values independently. + # + # Each map selects the LP(HP) QP values for all the channels. Recall + # the constraint above that the LP(HP) QP list have the same length + # for all the channels. + # + # If an LP or HP map is left out, then it is assumed to contain all + # zeros. This is useful if for example there is only 1 QP value for + # LP/HP subband, or if the subband is to be dropped by the + # compressor. + # + # Note that the map is surrounded by [] instead of {} to more + # clearly distinguish this map from the QP list inside the channels. + LP [ 0 0 0 0 + 0 0 0 0 + 1 1 1 1 + 1 1 1 1 ] + + HP [ 0 0 0 0 + 0 0 0 0 + 1 1 1 1 + 1 1 1 1 ] +} diff --git a/jpegxr/stdint_minimal.h b/jpegxr/stdint_minimal.h new file mode 100644 index 000000000..c2ebee20e --- /dev/null +++ b/jpegxr/stdint_minimal.h @@ -0,0 +1,71 @@ +#ifndef __stdint_minimal_H +#define __stdint_minimal_H + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: stdint_minimal.h,v 1.2 2008/02/28 18:50:31 steve Exp $") +#else +#ident "$Id: stdint_minimal.h,v 1.2 2008/02/28 18:50:31 steve Exp $" +#endif + +/* +* Microsoft VC compilers do not support C99, so we provide here a few +* of the basic typedefs that we need to get the code to +* compile. Since C99 stdint.h is not supported, the typedefs cannot +* be done portably, so we just do the most likely types. +* +* Note that this is specific to Microsoft compilers and not the +* Microsoft system. Mingw32, for example, does support C99 and this +* header file is not used in that case. +*/ + +typedef unsigned char uint8_t; +typedef unsigned short uint16_t; +typedef unsigned int uint32_t; +typedef unsigned long long uint64_t; + +typedef char int8_t; +typedef short int16_t; +typedef int int32_t; +typedef long long int64_t; + +#endif diff --git a/jpegxr/versions-windows.txt b/jpegxr/versions-windows.txt new file mode 100644 index 000000000..50d65744d --- /dev/null +++ b/jpegxr/versions-windows.txt @@ -0,0 +1,11 @@ + JPEG XR MSVS 2008 Versions + +0.1.0.0 20080227 Code ported to MSVS 2008 solution. 2 Projects in separate sub-directories - app and dll. JPEG XR library compiled as a DLL. + +0.1.0.1 20080228 The 2 projects directories are merged into a single directory (the top level solution directory). So sub-directories APP and DLL have been removed. + +0.1.1.0 20080304 Tweaks to SP setting API (at the C level) in preparation for distributed QP work. + +0.1.2.0 20090410 Several updates for April 2009 JPEG Maui meeting + +0.1.2.1 20090410 Bug fixes for October 2009 JPEG meeting diff --git a/jpegxr/w_emit.c b/jpegxr/w_emit.c new file mode 100644 index 000000000..224e96c85 --- /dev/null +++ b/jpegxr/w_emit.c @@ -0,0 +1,3307 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: w_emit.c,v 1.25 2008/03/24 18:06:56 steve Exp $") +#else +#ident "$Id: w_emit.c,v 1.25 2008/03/24 18:06:56 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <assert.h> + +void initialize_index_table(jxr_image_t image); + +static int w_image_header(jxr_image_t image, struct wbitstream*str); +static int w_image_plane_header(jxr_image_t image, struct wbitstream*str, int alpha); +static void w_INDEX_TABLE(jxr_image_t image, struct wbitstream*str); +static uint64_t w_PROFILE_LEVEL_INFO(jxr_image_t image, struct wbitstream*str, uint64_t bytes); +static void w_TILE(jxr_image_t image, struct wbitstream*str); + +static int short_header_ok(jxr_image_t image); +static int need_windowing_flag(jxr_image_t image); +static int need_trim_flexbits_flag(jxr_image_t image); + + +static void w_MB_FLEXBITS(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my); +static void w_BLOCK_FLEXBITS(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + unsigned ch, unsigned bl, unsigned model_bits); +static void w_DEC_DC(jxr_image_t image, struct wbitstream*str, + int model_bits, int chroma_flag, int is_dc_ch, + int32_t dc_val); +static void w_DECODE_ABS_LEVEL(jxr_image_t image, struct wbitstream*str, + int band, int chroma_flag, uint32_t level); +static void w_DECODE_BLOCK(jxr_image_t image, struct wbitstream*str, int band, int chroma_flag, + const int RLCoeffs[32], int num_non_zero); +static void w_DECODE_FIRST_INDEX(jxr_image_t image, struct wbitstream*str, + int chroma_flag, int band, int index_code); +static void w_DECODE_INDEX(jxr_image_t image, struct wbitstream*str, + int location, int chroma_flag, int band, int context, + int index_code); +static void w_DECODE_RUN(jxr_image_t image, struct wbitstream*str, int max_run, int run); +static int w_DECODE_BLOCK_ADAPTIVE(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned mx, + int cbp_flag, int chroma_flag, + int channel, int block, int mbhp_pred_mode, + unsigned model_bits); +static void w_REFINE_CBP(jxr_image_t image, struct wbitstream*str, int cbp_block_mask); +static void w_REFINE_CBP_CHR(jxr_image_t image, struct wbitstream*str, int cbp_block_mask); +static void refine_cbp_chr422(jxr_image_t image, struct wbitstream*str, int diff_cbp, int block); + + +static const int transpose420[4] = {0, 2, +1, 3 }; +static const int transpose422[8] = {0, 2, 1, 3, 4, 6, 5, 7}; + + +void initialize_index_table(jxr_image_t image) +{ + int num_index_table_entries; + + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) == 0 /* SPATIAL MODE */) { + num_index_table_entries = image->tile_columns * image->tile_rows; + } + else + { + num_index_table_entries = image->tile_columns * image->tile_rows; + switch (image->bands_present_of_primary) { + case 4: /* ISOLATED */ + num_index_table_entries *= 4; + break; + default: + num_index_table_entries *= (4 - image->bands_present_of_primary); + break; + } + } + image->tile_index_table_length = num_index_table_entries; + + assert(image->tile_index_table == 0); + image->tile_index_table = (int64_t*)calloc(num_index_table_entries, sizeof(int64_t)); + DEBUG(" INDEX_TABLE has %d table entries\n", num_index_table_entries); +} + +static int fill_in_image_defaults(jxr_image_t image) +{ + unsigned * temp_ptr, idx; + + if (image->tile_columns == 0) + image->tile_columns = 1; + if (image->tile_rows == 0) + image->tile_rows = 1; + + if (image->tile_columns > 1 || image->tile_rows > 1) + image->header_flags1 |= 0x80; /* TILING FLAG */ + + if (short_header_ok(image)) + image->header_flags2 |= 0x80; /* SHORT_HEADER FLAG */ + else + image->header_flags2 &= ~0x80; + + if (need_windowing_flag(image)) + image->header_flags2 |= 0x20; /* WINDOWING_FLAG */ + + image->window_extra_bottom = 15 - ((image->height1 + image->window_extra_top) % 16); + image->extended_height = image->height1 + 1 + image->window_extra_top + image->window_extra_bottom; + image->window_extra_right = 15 - ((image->width1 + image->window_extra_left) % 16); + image->extended_width = image->width1 + 1 + image->window_extra_left + image->window_extra_right; + + if (need_trim_flexbits_flag(image)) + image->header_flags2 |= 0x10; /* TRIM_FLEXBITS_FLAG */ + else + image->header_flags2 &= ~0x10; + + /* Test OUTPUT_CLR_FMT against size requirements */ + switch(image->output_clr_fmt) { + case JXR_OCF_YUV420: /* YUV420 */ + assert(image->height1 & 0x1); + assert((image->window_extra_top & 0x1) == 0); + assert((image->window_extra_bottom & 0x1) == 0); + case JXR_OCF_YUV422: /* YUV422 */ + assert(image->width1 & 0x1); + assert((image->window_extra_left & 0x1) == 0); + assert((image->window_extra_right & 0x1) == 0); + break; + } + + /* Force scaling ON if we are using a subsampled color format. */ + switch (image->use_clr_fmt) { + + /* If external and internal formats are both YUV420 (or YUV422), don't change scaled_flag. + Otherwise, color format is subsampled(lossy) and scaled_flag should be set as 1. */ + case 1: /*YUV420*/ + if (OVERLAP_INFO(image) == 2) + assert(image->extended_width >= 32); + if (image->output_clr_fmt != JXR_OCF_YUV420) + image->scaled_flag = 1; + break; + case 2: /*YUV422*/ + if (OVERLAP_INFO(image) == 2) + assert(image->extended_width >= 32); + if (image->output_clr_fmt != JXR_OCF_YUV422) + image->scaled_flag = 1; + break; + } + + temp_ptr = image->tile_column_width; + image->tile_column_width = (unsigned*)calloc(2*image->tile_columns, sizeof(unsigned)); + for (idx = 0 ; idx < image->tile_columns ; idx++) + image->tile_column_width[idx] = temp_ptr[idx]; + image->tile_column_position = image->tile_column_width + image->tile_columns; + + temp_ptr = image->tile_row_height; + image->tile_row_height = (unsigned*)calloc(2*image->tile_rows, sizeof(unsigned)); + for (idx = 0 ; idx < image->tile_rows ; idx++) + image->tile_row_height[idx] = temp_ptr[idx]; + image->tile_row_position = image->tile_row_height + image->tile_rows; + + if (TILING_FLAG(image)) { + unsigned width_MB = EXTENDED_WIDTH_BLOCKS(image), height_MB = EXTENDED_HEIGHT_BLOCKS(image); + unsigned min_width = 1, total_width = 0, min_height = 1, total_height = 0; + + if (image->tile_column_width[0] == 0) { + total_width = 0; + for ( idx = 0 ; idx < image->tile_columns - 1 ; idx++ ) { + image->tile_column_width[idx] = width_MB / image->tile_columns; + image->tile_column_position[idx] = total_width; + total_width += image->tile_column_width[idx]; + } + image->tile_column_width[image->tile_columns - 1] = width_MB - total_width; + image->tile_column_position[image->tile_columns - 1] = total_width; + } + total_width = 0; + + if ((OVERLAP_INFO(image) == 2) && ((image->use_clr_fmt == 1/*YUV420*/) || (image->use_clr_fmt == 2/*YUV422*/)) && image->disableTileOverlapFlag) + min_width = 2; + for ( idx = 0 ; idx < image->tile_columns - 1 ; idx++ ) { + if (image->tile_column_width[idx] < min_width) { + DEBUG(" Tile %d width is below minimum width\n", idx); + assert(0); + break; + } + image->tile_column_position[idx] = total_width; + total_width += image->tile_column_width[idx]; + } + if ((total_width + min_width) > width_MB) { + DEBUG(" Total specified tile width is above image width\n"); + assert(0); + } + image->tile_column_position[image->tile_columns - 1] = total_width; + image->tile_column_width[image->tile_columns - 1] = (width_MB - total_width); + + if (image->tile_row_height[0] == 0) { + total_height = 0; + for ( idx = 0 ; idx < image->tile_rows - 1 ; idx++ ) { + image->tile_row_height[idx] = height_MB / image->tile_rows; + image->tile_row_position[idx] = total_height; + total_height += image->tile_row_height[idx]; + } + image->tile_row_height[image->tile_rows - 1] = height_MB - total_height; + image->tile_row_position[image->tile_rows - 1] = total_height; + } + total_height = 0; + + for ( idx = 0 ; idx < image->tile_rows - 1 ; idx++ ) { + if (image->tile_row_height[idx] < min_height) { + DEBUG(" Tile %d height is below minimum height\n", idx); + assert(0); + break; + } + image->tile_row_position[idx] = total_height; + total_height += image->tile_row_height[idx]; + } + if ((total_height + min_height) > height_MB) { + DEBUG(" Total specified tile height is above image height\n"); + assert(0); + } + image->tile_row_position[image->tile_rows - 1] = total_height; + image->tile_row_height[image->tile_rows - 1] = (height_MB - total_height); + + } else { + image->tile_column_width[0] = EXTENDED_WIDTH_BLOCKS(image); + image->tile_column_position[0] = 0; + + image->tile_row_height[0] = EXTENDED_HEIGHT_BLOCKS(image); + image->tile_row_position[0] = 0; + } + + image->lwf_test = 0; + + _jxr_make_mbstore(image, 1); + image->cur_my = -5; + return 0; +} + +int jxr_write_image_bitstream(jxr_image_t image, FILE*fd) +{ + int rc, res = 0; + + struct wbitstream bits; + _jxr_wbitstream_initialize(&bits, fd); + + /* Clean up the image structure in preparation for actually + writing the image. This checks for and configures any + values left to defaults, and checks for bogus settings. */ + rc = fill_in_image_defaults(image); + if (rc < 0) + return rc; + + /* Prepare index table storage */ + initialize_index_table(image); + + + rc = w_image_header(image, &bits); + assert(rc >= 0); + + rc = w_image_plane_header(image, &bits, 0); + assert(rc >= 0); + + if (ALPHACHANNEL_FLAG(image)) { + unsigned char window_params[5]; + if (image->window_extra_top || image->window_extra_right) { + window_params[0] = 1; + window_params[1] = image->window_extra_top; + window_params[2] = image->window_extra_left; + window_params[3] = image->window_extra_bottom; + window_params[4] = image->window_extra_right; + } + else { + window_params[4] = window_params[3] = window_params[2] = window_params[1] = window_params[0] = 0; + } + + image->alpha = jxr_create_image(image->width1 + 1, image->height1 + 1, window_params); + + *image->alpha = *image; + image->alpha->strip[0].up4 = image->alpha->strip[0].up3 = image->alpha->strip[0].up2 = + image->alpha->strip[0].up1 = image->alpha->strip[0].cur = NULL; + + jxr_set_INTERNAL_CLR_FMT(image->alpha, JXR_YONLY, 1); + _jxr_make_mbstore(image->alpha, 1); + image->alpha->dc_component_mode = image->alpha->lp_component_mode = image->alpha->hp_component_mode = JXR_CM_UNIFORM; + image->alpha->primary = 0; + image->alpha->cur_my = -5; + + rc = w_image_plane_header(image->alpha, &bits, 1); + assert(rc >= 0); + } + + if (INDEXTABLE_PRESENT_FLAG(image)) { + struct wbitstream strCodedTiles; + FILE*fdCodedTiles = fopen("codedtiles.tmp", "wb"); + uint64_t subsequent_bytes; + struct rbitstream strCodedTilesRead; + FILE*fdCodedTilesRead; + size_t idx; + _jxr_wbitstream_initialize(&strCodedTiles, fdCodedTiles); + + /* CODED_TILES() */ + w_TILE(image, &strCodedTiles); + + w_INDEX_TABLE(image, &bits); + + _jxr_wbitstream_flush(&strCodedTiles); + fclose(fdCodedTiles); + + /* Profile / Level info */ + subsequent_bytes = 4; + _jxr_wbitstream_intVLW(&bits, subsequent_bytes); + + if (subsequent_bytes > 0) { + uint64_t additional_bytes; + uint64_t ibyte; + + additional_bytes = w_PROFILE_LEVEL_INFO(image, &bits, subsequent_bytes) ; + + for (ibyte = 0 ; ibyte < additional_bytes ; ibyte += 1) + _jxr_wbitstream_uint8(&bits, 0); /* RESERVED_A_BYTE */ + } + + DEBUG("MARK HERE as the tile base. bitpos=%zu\n", _jxr_wbitstream_bitpos(&bits)); + _jxr_wbitstream_mark(&bits); + + fdCodedTilesRead = fopen("codedtiles.tmp", "rb"); + _jxr_rbitstream_initialize(&strCodedTilesRead, fdCodedTilesRead); + + for (idx = 0; idx < strCodedTiles.write_count; idx++) { + _jxr_wbitstream_uint8(&bits, _jxr_rbitstream_uint8(&strCodedTilesRead)); + } + fclose(fdCodedTilesRead); + /* delete file associated with CodedTiles */ + remove("codedtiles.tmp"); + + } + else { + /* Profile / Level info */ + uint64_t subsequent_bytes = 4; + _jxr_wbitstream_intVLW(&bits, subsequent_bytes); + + if (subsequent_bytes > 0) { + uint64_t additional_bytes; + uint64_t ibyte; + additional_bytes = w_PROFILE_LEVEL_INFO(image, &bits, subsequent_bytes) ; + + for (ibyte = 0 ; ibyte < additional_bytes ; ibyte += 1) + _jxr_wbitstream_uint8(&bits, 0); /* RESERVED_A_BYTE */ + } + + DEBUG("MARK HERE as the tile base. bitpos=%zu\n", _jxr_wbitstream_bitpos(&bits)); + _jxr_wbitstream_mark(&bits); + + /* CODED_TILES() */ + w_TILE(image, &bits); + } + + _jxr_wbitstream_flush(&bits); + +#ifdef VERIFY_16BIT + if(image->lwf_test == 0) + DEBUG("Meets conditions for LONG_WORD_FLAG == 0!"); + else { + DEBUG("Does not meet conditions for LONG_WORD_FLAG == 0!"); + if (LONG_WORD_FLAG(image) == 0) + return JXR_EC_BADFORMAT; + } +#endif + + return res; +} + +#if defined(DETAILED_DEBUG) +static const char*bitdepth_names[16] = { + "BD1WHITE1", "BD8", "BD16", "BD16S", + "BD16F", "RESERVED5", "BD32S", "BD32F", + "BD5", "BD10", "BD565", "RESERVED11" + "RESERVED12", "RESERVED12", "RESERVED12","BD1BLACK1" +}; + +#endif + +static int w_image_header(jxr_image_t image, struct wbitstream*str) +{ + const char GDI_SIG[] = "WMPHOTO\0"; + int res = 0; + unsigned idx; + + /* GDI SIGNATURE */ + for (idx = 0 ; idx < 8 ; idx += 1) { + _jxr_wbitstream_uint8(str, GDI_SIG[idx]); + } + + DEBUG("START IMAGE_HEADER (bitpos=%zu)\n", _jxr_wbitstream_bitpos(str)); + + _jxr_wbitstream_uint4(str, 1); /* VERSION_INFO */ + + _jxr_wbitstream_uint1(str, image->disableTileOverlapFlag); /* HARD_TILING_FLAG */ + + _jxr_wbitstream_uint3(str, 1); /* SUB_VERSION_INFO */ + + DEBUG(" Flags group1=0x%02x\n", image->header_flags1); + _jxr_wbitstream_uint8(str, image->header_flags1); + + DEBUG(" Flags group2=0x%02x\n", image->header_flags2); + _jxr_wbitstream_uint8(str, image->header_flags2); + + DEBUG(" OUTPUT_CLR_FMT=%d\n", SOURCE_CLR_FMT(image)); + DEBUG(" OUTPUT_BITEDPTH=%d (%s)\n", SOURCE_BITDEPTH(image), bitdepth_names[SOURCE_BITDEPTH(image)]); + _jxr_wbitstream_uint8(str, image->header_flags_fmt); + + if (SHORT_HEADER_FLAG(image)) { + DEBUG(" SHORT_HEADER_FLAG=true\n"); + _jxr_wbitstream_uint16(str, image->width1); + _jxr_wbitstream_uint16(str, image->height1); + } else { + DEBUG(" SHORT_HEADER_FLAG=false\n"); + _jxr_wbitstream_uint32(str, image->width1); + _jxr_wbitstream_uint32(str, image->height1); + } + + DEBUG(" Image dimensions: %u x %u\n", image->width1+1, image->height1+1); + + /* Write TILE geometry information, if there is TILING. */ + if (jxr_get_TILING_FLAG(image)) { + + DEBUG(" TILING %u columns, %u rows\n", + image->tile_columns, image->tile_rows); + + _jxr_wbitstream_uint12(str, image->tile_columns -1); + _jxr_wbitstream_uint12(str, image->tile_rows -1); + + for (idx = 0 ; idx < image->tile_columns-1 ; idx += 1) { + if (SHORT_HEADER_FLAG(image)) + _jxr_wbitstream_uint8(str, image->tile_column_width[idx]); + else + _jxr_wbitstream_uint16(str,image->tile_column_width[idx]); + } + for (idx = 0 ; idx < image->tile_rows-1 ; idx += 1) { + if (SHORT_HEADER_FLAG(image)) + _jxr_wbitstream_uint8(str, image->tile_row_height[idx]); + else + _jxr_wbitstream_uint16(str,image->tile_row_height[idx]); + } + } else { + DEBUG(" NO TILING\n"); + } + +#if defined(DETAILED_DEBUG) + DEBUG(" Tile widths:"); + for (idx = 0 ; idx < image->tile_columns ; idx += 1) + DEBUG(" %u", image->tile_column_width[idx]); + DEBUG("\n"); + DEBUG(" Tile heights:"); + for (idx = 0 ; idx < image->tile_rows ; idx += 1) + DEBUG(" %u", image->tile_row_height[idx]); + DEBUG("\n"); +#endif + + /* Write out windowing bits. */ + if (WINDOWING_FLAG(image)) { + _jxr_wbitstream_uint6(str, (uint8_t)image->window_extra_top); + _jxr_wbitstream_uint6(str, (uint8_t)image->window_extra_left); + _jxr_wbitstream_uint6(str, (uint8_t)image->window_extra_bottom); + _jxr_wbitstream_uint6(str, (uint8_t)image->window_extra_right); + } + + DEBUG("END IMAGE_HEADER\n"); + return res; +} + +static int w_image_plane_header(jxr_image_t image, struct wbitstream*str, int alpha) +{ + DEBUG("START IMAGE_PLANE_HEADER (bitpos=%zu)\n", _jxr_wbitstream_bitpos(str)); + + DEBUG(" INTERNAL_CLR_FMT = %d\n", image->use_clr_fmt); + DEBUG(" SCALED_FLAG = %s\n", image->scaled_flag? "true" : "false"); + DEBUG(" BANDS_PRESENT = %d\n", image->bands_present); + + _jxr_wbitstream_uint3(str, image->use_clr_fmt); + _jxr_wbitstream_uint1(str, image->scaled_flag); /* SCALED_FLAG = 1 */ + _jxr_wbitstream_uint4(str, image->bands_present); + + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + image->num_channels = 1; + break; + case 1: /* YUV420 */ + image->num_channels = 3; + _jxr_wbitstream_uint4(str, 0); /* CHROMA_CENTERING */ + _jxr_wbitstream_uint4(str, 0); /* COLOR_INTERPRETATION==0 */ + break; + case 2: /* YUV422 */ + image->num_channels = 3; + _jxr_wbitstream_uint4(str, 0); /* CHROMA_CENTERING */ + _jxr_wbitstream_uint4(str, 0); /* COLOR_INTERPRETATION==0 */ + break; + case 3: /* YUV444 */ + image->num_channels = 3; + _jxr_wbitstream_uint4(str, 0); /* CHROMA_CENTERING */ + _jxr_wbitstream_uint4(str, 0); /* COLOR_INTERPRETATION==0 */ + break; + case 4: /* YUVK */ + image->num_channels = 4; + break; + case 6: /* NCOMPONENT */ + _jxr_wbitstream_uint4(str, image->num_channels-1); + _jxr_wbitstream_uint4(str, 0); /* COLOR_INTERPRETATION==0 */ + break; + case 5: /* RESERVED */ + case 7: /* RESERVED */ + break; + } + + switch (SOURCE_BITDEPTH(image)) { + case 0: /* BD1WHITE1 */ + case 1: /* BD8 */ + case 4: /* BD16F */ + case 8: /* BD5 */ + case 9: /* BD10 */ + case 10: /* BD565 */ + case 15: /* BD1BLACK1 */ + break; + case 2: /* BD16 */ + case 3: /* BD16S */ + case 6: /* BD32S */ + _jxr_wbitstream_uint8(str, image->shift_bits); /* SHIFT_BITS */ + break; + case 7: /* BD32F */ + _jxr_wbitstream_uint8(str, image->len_mantissa); /* LEN_MANTISSA */ + _jxr_wbitstream_uint8(str, image->exp_bias); /* EXP_BIAS */ + break; + default: /* RESERVED */ + break; + } + + /* Emit QP information for DC pass. */ + _jxr_wbitstream_uint1(str, image->dc_frame_uniform); /* DC_FRAME_UNIFORM */ + if (image->dc_frame_uniform) { + DEBUG(" DC_FRAME_UNIFORM = %s\n", image->dc_frame_uniform?"true":"false"); + _jxr_w_DC_QP(image, str); + } + + if (image->bands_present != 3 /*DCONLY*/) { + /* Emit QP information for LP pass. */ + _jxr_wbitstream_uint1(str, 0); /* RESERVED_I_BIT */ + _jxr_wbitstream_uint1(str, image->lp_frame_uniform); + DEBUG(" LP_FRAME_UNIFORM = %s\n", image->lp_frame_uniform?"true":"false"); + if (image->lp_frame_uniform) { + assert(image->num_lp_qps > 0); + /* _jxr_wbitstream_uint4(str, image->num_lp_qps-1); */ + _jxr_w_LP_QP(image, str); + } + + if (image->bands_present != 2 /*NOHIGHPASS*/) { + /* Emit QP information for HP pass. */ + _jxr_wbitstream_uint1(str, 0); /* RESERVED_J_BIT */ + _jxr_wbitstream_uint1(str, image->hp_frame_uniform); + DEBUG(" HP_FRAME_UNIFORM = %s\n", image->hp_frame_uniform?"true":"false"); + if (image->hp_frame_uniform) { + _jxr_w_HP_QP(image, str); + } + } + } + + _jxr_wbitstream_syncbyte(str); + DEBUG("END IMAGE_PLANE_HEADER (bitpos=%zu)\n", _jxr_wbitstream_bitpos(str)); + + return 0; +} + +static int put_ch_mode(jxr_image_t image, struct wbitstream*str) +{ + int use_mode; + /* If there is only 1 channel, then CH_MODE==0 is implicit. */ + if (image->num_channels == 1) { + assert(image->dc_component_mode == JXR_CM_UNIFORM); + return 0; + } + + use_mode = image->dc_component_mode; + _jxr_wbitstream_uint2(str, use_mode); + return use_mode; +} + +void _jxr_w_DC_QP(jxr_image_t image, struct wbitstream*str) +{ + int idx; + int ch_mode = put_ch_mode(image, str); + DEBUG(" DC_QP CH_MODE=%d ", ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + DEBUG(" DC_QUANT UNIFORM =%u", image->dc_quant_ch[0]); + _jxr_wbitstream_uint8(str, image->dc_quant_ch[0]); + break; + case 1: /* SEPARATE */ + DEBUG(" DC_QUANT SEPARATE Y=%u, Chr=%u", image->dc_quant_ch[0],image->dc_quant_ch[1]); + _jxr_wbitstream_uint8(str, image->dc_quant_ch[0]); + _jxr_wbitstream_uint8(str, image->dc_quant_ch[1]); + break; + case 2: /* INDEPENDENT */ + DEBUG(" DC_QUANT INDEPENDENT ="); + for (idx = 0 ; idx < image->num_channels ; idx +=1) { + DEBUG(" %u", image->dc_quant_ch[idx]); + _jxr_wbitstream_uint8(str, image->dc_quant_ch[idx]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + break; + } + DEBUG("\n"); +} + +void _jxr_w_LP_QP(jxr_image_t image, struct wbitstream*str) +{ + unsigned idx; + for (idx = 0 ; idx < image->num_lp_qps ; idx += 1) { + int ch_mode = put_ch_mode(image, str); + int ch; + DEBUG(" LP_QP[%d] CH_MODE=%d ", idx, ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + DEBUG(" LP_QUANT UNIFORM =%u", image->lp_quant_ch[0][idx]); + _jxr_wbitstream_uint8(str, image->lp_quant_ch[0][idx]); + break; + case 1: /* SEPARATE */ + DEBUG(" LP_QUANT SEPARATE Y=%u, Chr=%u", image->lp_quant_ch[0][idx],image->lp_quant_ch[1][idx]); + _jxr_wbitstream_uint8(str, image->lp_quant_ch[0][idx]); + _jxr_wbitstream_uint8(str, image->lp_quant_ch[1][idx]); + break; + case 2: /* INDEPENDENT */ + DEBUG(" LP_QUANT INDEPENDENT ="); + for (ch = 0 ; ch < image->num_channels ; ch +=1) { + DEBUG(" %u", image->lp_quant_ch[ch][idx]); + _jxr_wbitstream_uint8(str, image->lp_quant_ch[ch][idx]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + break; + } + DEBUG("\n"); + } +} + +void _jxr_w_HP_QP(jxr_image_t image, struct wbitstream*str) +{ + unsigned idx; + for (idx = 0 ; idx < image->num_hp_qps ; idx += 1) { + int ch_mode = put_ch_mode(image, str); + int ch; + DEBUG(" HP_QP[%d] CH_MODE=%d ", idx, ch_mode); + + switch (ch_mode) { + case 0: /* UNIFORM */ + _jxr_wbitstream_uint8(str, image->hp_quant_ch[0][idx]); + DEBUG("UNIFORM %d", image->hp_quant_ch[0][idx]); + break; + case 1: /* SEPARATE */ + DEBUG("SEPARATE Y=%u, Chr=%u", image->hp_quant_ch[0][idx],image->hp_quant_ch[1][idx]); + _jxr_wbitstream_uint8(str, image->hp_quant_ch[0][idx]); + _jxr_wbitstream_uint8(str, image->hp_quant_ch[1][idx]); + break; + case 2: /* INDEPENDENT */ + DEBUG("INDEPENDENT ="); + for (ch = 0 ; ch < image->num_channels ; ch +=1) { + DEBUG(" %u", image->hp_quant_ch[ch][idx]); + _jxr_wbitstream_uint8(str, image->hp_quant_ch[ch][idx]); + } + break; + case 3: /* Reserved */ + break; + default: + assert(0); + } + DEBUG(" bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + } +} + +static void w_INDEX_TABLE(jxr_image_t image, struct wbitstream*str) +{ + DEBUG("START INDEX_TABLE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + + if (INDEXTABLE_PRESENT_FLAG(image)) { + int idx; + /* INDEX_TABLE_STARTCODE == 0x0001 */ + DEBUG(" INDEX_TAB:E_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x01); + + for (idx = 0 ; idx < image->tile_index_table_length ; idx++) { + _jxr_wbitstream_intVLW(str, image->tile_index_table[idx]); + } + + DEBUG(" INDEX_TABLE has %d table entries\n", image->tile_index_table_length); + + } + + DEBUG("INTEX_TABLE DONE bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); +} + +static uint64_t w_PROFILE_LEVEL_INFO(jxr_image_t image, struct wbitstream*str, uint64_t bytes) +{ + uint64_t additional_bytes; + for (additional_bytes = bytes; additional_bytes > 3 ; additional_bytes -= 4) { + /* These profile and level values are default. More logic needed */ + _jxr_wbitstream_uint8(str, image->profile_idc); /* PROFILE_IDC */ + _jxr_wbitstream_uint8(str, image->level_idc); /* LEVEL_IDC */ + _jxr_wbitstream_uint15(str, 0); /* RESERVED_L */ + if (additional_bytes > 7) + _jxr_wbitstream_uint1(str, 0); /* LAST_FLAG */ + else + _jxr_wbitstream_uint1(str, 1); /* LAST_FLAG */ + } + + return additional_bytes; +} + +static void w_TILE(jxr_image_t image, struct wbitstream*str) +{ + unsigned tile_idx = 0; + + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) == 0 /* SPATIALMODE */) { + + if (TILING_FLAG(image)) { + unsigned tx, ty; + for (ty = 0 ; ty < image->tile_rows ; ty += 1) + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + _jxr_w_TILE_SPATIAL(image, str, tx, ty); + image->tile_index_table[tile_idx] = str->write_count; + tile_idx++; + } + } else { + _jxr_w_TILE_SPATIAL(image, str, 0, 0); + } + + } else { /* FREQUENCYMODE */ + /* Temporarily declare these bitstreams til I figure out the tmp file vs in memory issue*/ + unsigned tx, ty; + uint8_t bands_present = image->bands_present_of_primary; + + for (ty = 0 ; ty < image->tile_rows ; ty += 1) { + for (tx = 0 ; tx < image->tile_columns ; tx += 1) { + _jxr_w_TILE_DC(image, str, tx, ty); + image->tile_index_table[tile_idx * (4 - bands_present) + 0] = str->write_count; + if (bands_present != 3) { + _jxr_w_TILE_LP(image, str, tx, ty); + image->tile_index_table[tile_idx * (4 - bands_present) + 1] = str->write_count; + if (bands_present != 2) { + _jxr_w_TILE_HP_FLEX(image, str, tx, ty); + } + } + + + tile_idx++; + } + } + } + + if (INDEXTABLE_PRESENT_FLAG(image)) { + for (tile_idx = image->tile_index_table_length - 1 ; tile_idx > 0 ; tile_idx--) { + image->tile_index_table[tile_idx] = image->tile_index_table[tile_idx - 1]; + } + image->tile_index_table[0] = 0; + } + +} + + +static int short_header_ok(jxr_image_t image) +{ + /* If the image width or height is too big for short header, + then we need a long header. */ + if (image->width1 >= 0x10000 || image->height1 >= 0x10000) + return 0; + + /* If the tile width/height is too big for a short header, + then we need to use a long header. */ + if (jxr_get_TILING_FLAG(image)) { + unsigned idx; + + for (idx = 0 ; idx < image->tile_columns ; idx += 1) + if (jxr_get_TILE_WIDTH(image,idx)/16 > 0x100) + return 0; + for (idx = 0 ; idx < image->tile_rows ; idx += 1) + if (jxr_get_TILE_HEIGHT(image,idx)/16 > 0x100) + return 0; + } + + /* If nothing else forces us to use a long header, then we can + use a short header. */ + return 1; +} + +static int need_windowing_flag(jxr_image_t image) +{ + if (image->window_extra_top > 0) + return 1; + if (image->window_extra_left > 0) + return 1; + + return 0; +} + +static int need_trim_flexbits_flag(jxr_image_t image) +{ + /* If no FLEXBTS data, then no TRIM_FLEXBITS flag */ + if (image->bands_present != JXR_BP_ALL) + return 0; + if (image->trim_flexbits == 0) + return 0; + + return 1; +} + +void _jxr_w_TILE_HEADER_DC(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty) +{ + if (image->dc_frame_uniform == 0) { + int ch; + struct jxr_tile_qp*cur; + + /* per-tile configuration, so get the QP settings from the + per-tile store and make it current. */ + assert(image->tile_quant); + cur = GET_TILE_QUANT(image, tx, ty); + image->dc_component_mode = cur->component_mode; + switch (image->dc_component_mode) { + case JXR_CM_UNIFORM: + for (ch = 0 ; ch < image->num_channels ; ch += 1) + image->dc_quant_ch[ch] = cur->channel[0].dc_qp; + break; + case JXR_CM_SEPARATE: + image->dc_quant_ch[0] = cur->channel[0].dc_qp; + for (ch = 1 ; ch < image->num_channels ; ch += 1) + image->dc_quant_ch[ch] = cur->channel[1].dc_qp; + break; + case JXR_CM_INDEPENDENT: + for (ch = 0 ; ch < image->num_channels ; ch += 1) + image->dc_quant_ch[ch] = cur->channel[ch].dc_qp; + break; + case JXR_CM_Reserved: + assert(0); + break; + } + + _jxr_w_DC_QP(image, str); + } +} + +void _jxr_w_TILE_HEADER_LOWPASS(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty) +{ + if (image->lp_frame_uniform == 0) { + int ch; + unsigned idx; + struct jxr_tile_qp*cur; + + /* per-tile configuration, so get the QP settings from the + per-tile store and make it current. */ + assert(image->tile_quant); + cur = GET_TILE_QUANT(image, tx, ty); + image->lp_component_mode = cur->component_mode; + image->num_lp_qps = cur->channel[0].num_lp; + + switch (image->lp_component_mode) { + case JXR_CM_UNIFORM: + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_lp_qps ; idx += 1) + image->lp_quant_ch[ch][idx] = cur->channel[0].lp_qp[idx]; + } + break; + case JXR_CM_SEPARATE: + for (idx = 0 ; idx < image->num_lp_qps ; idx += 1) + image->lp_quant_ch[0][idx] = cur->channel[0].lp_qp[idx]; + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_lp_qps ; idx += 1) + image->lp_quant_ch[ch][idx] = cur->channel[1].lp_qp[idx]; + } + break; + case JXR_CM_INDEPENDENT: + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_lp_qps ; idx += 1) + image->lp_quant_ch[ch][idx] = cur->channel[ch].lp_qp[idx]; + } + break; + case JXR_CM_Reserved: + assert(0); + break; + } + + _jxr_wbitstream_uint1(str, 0); /* XXXX USE_DC_QP == FALSE */ + assert(image->num_lp_qps > 0); + DEBUG(" TILE_HEADER_LP: NUM_LP_QPS = %d\n", image->num_lp_qps); + _jxr_wbitstream_uint4(str, image->num_lp_qps-1); + _jxr_w_LP_QP(image, str); + } +} + +void _jxr_w_TILE_HEADER_HIGHPASS(jxr_image_t image, struct wbitstream*str, + int alpha_flag, unsigned tx, unsigned ty) +{ + if (image->hp_frame_uniform == 0) { + int ch; + unsigned idx; + struct jxr_tile_qp*cur; + + /* per-tile configuration, so get the QP settings from the + per-tile store and make it current. */ + assert(image->tile_quant); + cur = GET_TILE_QUANT(image, tx, ty); + image->hp_component_mode = cur->component_mode; + image->num_hp_qps = cur->channel[0].num_hp; + + switch (image->hp_component_mode) { + case JXR_CM_UNIFORM: + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_hp_qps ; idx += 1) + image->hp_quant_ch[ch][idx] = cur->channel[0].hp_qp[idx]; + } + break; + case JXR_CM_SEPARATE: + for (idx = 0 ; idx < image->num_hp_qps ; idx += 1) + image->hp_quant_ch[0][idx] = cur->channel[0].hp_qp[idx]; + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_hp_qps ; idx += 1) + image->hp_quant_ch[ch][idx] = cur->channel[1].hp_qp[idx]; + } + break; + case JXR_CM_INDEPENDENT: + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + for (idx = 0 ; idx < image->num_hp_qps ; idx += 1) + image->hp_quant_ch[ch][idx] = cur->channel[ch].hp_qp[idx]; + } + break; + case JXR_CM_Reserved: + assert(0); + break; + } + + _jxr_wbitstream_uint1(str, 0); /* XXXX USE_LP_QP == FALSE */ + assert(image->num_hp_qps > 0); + _jxr_wbitstream_uint4(str, image->num_hp_qps-1); + _jxr_w_HP_QP(image, str); + } +} + +void _jxr_w_ENCODE_QP_INDEX(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty, unsigned mx, unsigned my, + unsigned num_qps, unsigned qp_index) +{ + static const unsigned bits_qp_index[17] = {0, 0,1,1,2, 2,3,3,3, 3,4,4,4, 4,4,4,4}; + int bits_count; + + assert(num_qps > 1 && num_qps <= 16); + + if (qp_index == 0) { + /* IS_QPINDEX_NONZERO_FLAG == false */ + _jxr_wbitstream_uint1(str, 0); + return; + } + + /* IS_QPINDEX_NONZERO_FLAG == true */ + _jxr_wbitstream_uint1(str, 1); + + bits_count = bits_qp_index[num_qps]; + assert(bits_count > 0); /* num_qps must be >1 here. */ + + _jxr_wbitstream_uintN(str, qp_index-1, bits_count); +} + +static void encode_val_dc_yuv(jxr_image_t image, struct wbitstream*str, int val) +{ + assert(val >= 0 && val <= 7); + + switch (val) { + case 0: /* 10 */ + _jxr_wbitstream_uint2(str, 2); + break; + case 1: /* 001 */ + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 2: /* 0000 1 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 3: /* 0001 */ + _jxr_wbitstream_uint4(str, 1); + break; + case 4: /* 11 */ + _jxr_wbitstream_uint2(str, 3); + break; + case 5: /* 010 */ + _jxr_wbitstream_uint2(str, 1); + _jxr_wbitstream_uint1(str, 0); + break; + case 6: /* 0000 0 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint1(str, 0); + break; + case 7: /* 011 */ + _jxr_wbitstream_uint2(str, 1); + _jxr_wbitstream_uint1(str, 1); + break; + } +} + +void _jxr_w_MB_DC(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int lap_mean[2]; + lap_mean[0] = 0; + lap_mean[1] = 0; + + DEBUG(" MB_DC tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_wbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_DC: Initialize Context\n"); + _jxr_InitVLCTable(image, AbsLevelIndDCLum); + _jxr_InitVLCTable(image, AbsLevelIndDCChr); + _jxr_InitializeModelMB(&image->model_dc, 0/*DC*/); + } + + if (image->use_clr_fmt==0 || image->use_clr_fmt==4 || image->use_clr_fmt==6) { + int32_t dc_val = 0; + + /* clr_fmt == YONLY, YUVK or NCOMPONENT */ + unsigned idx; + for (idx = 0 ; idx < image->num_channels ; idx += 1) { + int m = (idx == 0)? 0 : 1; + int model_bits = image->model_dc.bits[m]; + + unsigned is_dc_ch = (labs(dc_val)>>model_bits) != 0 ? 1 : 0; + + dc_val = MACROBLK_CUR_DC(image,idx,tx,mx); + m = (idx == 0)? 0 : 1; + model_bits = image->model_dc.bits[m]; + + is_dc_ch = (labs(dc_val)>>model_bits) != 0 ? 1 : 0; + _jxr_wbitstream_uint1(str, is_dc_ch); + DEBUG(" MB_DC: IS_DC_CH=%u, model_bits=%d\n", + is_dc_ch, model_bits); + if (is_dc_ch) { + lap_mean[m] += 1; + } + DEBUG(" dc_val at t=[%u %u], m=[%u %u] == %d (0x%08x)\n", + tx, ty, mx, my, dc_val, dc_val); + w_DEC_DC(image, str, model_bits, 0/*chroma*/, is_dc_ch, dc_val); + } + } else { + int32_t dc_val_Y = MACROBLK_CUR_DC(image,0,tx,mx); + int32_t dc_val_U = MACROBLK_CUR_DC(image,1,tx,mx); + int32_t dc_val_V = MACROBLK_CUR_DC(image,2,tx,mx); + int val_dc_yuv = 0; + int model_bits; + int is_dc_ch; + + if ((labs(dc_val_Y) >> image->model_dc.bits[0]) != 0) { + val_dc_yuv |= 0x4; + lap_mean[0] += 1; + } + if ((labs(dc_val_U) >> image->model_dc.bits[1]) != 0) { + val_dc_yuv |= 0x2; + lap_mean[1] += 1; + } + if ((labs(dc_val_V) >> image->model_dc.bits[1]) != 0) { + val_dc_yuv |= 0x1; + lap_mean[1] += 1; + } + + DEBUG(" VAL_DC_YUV = %x\n", val_dc_yuv); + encode_val_dc_yuv(image, str, val_dc_yuv); + + DEBUG(" dc_val_Y at t=[%u %u], m=[%u %u] == %d (0x%08x)\n", + tx, ty, mx, my, dc_val_Y, dc_val_Y); + model_bits = image->model_dc.bits[0]; + is_dc_ch = val_dc_yuv&0x4 ? 1 : 0; + w_DEC_DC(image, str, model_bits, 0/*chroma*/, is_dc_ch, dc_val_Y); + + DEBUG(" dc_val_U at t=[%u %u], m=[%u %u] == %d (0x%08x)\n", + tx, ty, mx, my, dc_val_U, dc_val_U); + model_bits = image->model_dc.bits[1]; + is_dc_ch = val_dc_yuv&0x2 ? 1 : 0; + w_DEC_DC(image, str, model_bits, 1/*chroma*/, is_dc_ch, dc_val_U); + + DEBUG(" dc_val_V at t=[%u %u], m=[%u %u] == %d (0x%08x)\n", + tx, ty, mx, my, dc_val_V, dc_val_V); + model_bits = image->model_dc.bits[1]; + is_dc_ch = val_dc_yuv&0x1 ? 1 : 0; + w_DEC_DC(image, str, model_bits, 1/*chroma*/, is_dc_ch, dc_val_V); + } + + /* */ + DEBUG(" MB_DC: UpdateModelMB: lap_mean={%u %u}\n", lap_mean[0], lap_mean[1]); + _jxr_UpdateModelMB(image, lap_mean, &image->model_dc, 0/*DC*/); + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" MB_DC: Reset Context\n"); + _jxr_AdaptVLCTable(image, AbsLevelIndDCLum); + _jxr_AdaptVLCTable(image, AbsLevelIndDCChr); + } + + DEBUG(" MB_DC DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); +} + +static void w_REFINE_LP(struct wbitstream*str, int coeff, int model_bits) +{ + if (coeff > 0) { + _jxr_wbitstream_uintN(str, coeff, model_bits); + coeff >>= model_bits; + if (coeff == 0) + _jxr_wbitstream_uint1(str, 0); + } else if (coeff < 0) { + coeff = -coeff; + _jxr_wbitstream_uintN(str, coeff, model_bits); + coeff >>= model_bits; + if (coeff == 0) + _jxr_wbitstream_uint1(str, 1); + } else { + _jxr_wbitstream_uintN(str, 0, model_bits); + coeff >>= model_bits; + /* No sign bit is needed for zero values. */ + } +} + +/* +* This maps the values in src[1-15] into dst[1-15], and adapts the +* map as it goes. +*/ +static void AdaptiveLPPermute(jxr_image_t image, int dst[16], const int src[16]) +{ + int idx; + for (idx = 1 ; idx < 16 ; idx += 1) { + + int map = image->lopass_scanorder[idx-1]; + dst[idx] = src[map]; + + if (dst[idx] == 0) + continue; + + image->lopass_scantotals[idx-1] += 1; + + if (idx > 1 && image->lopass_scantotals[idx-1] > image->lopass_scantotals[idx-2]) { + SWAP(image->lopass_scantotals[idx-1], image->lopass_scantotals[idx-2]); + SWAP(image->lopass_scanorder[idx-1], image->lopass_scanorder[idx-2]); + } + } +} + +static void FixedLPPermuteUV(jxr_image_t image, int dst[16], int src[8][16]) +{ + int k; + int count_chr = 14; + static const int remap_arr422[] = {4, 1, 2, 3, 5, 6, 7}; + + assert(image->use_clr_fmt==1/*YUV420*/ || image->use_clr_fmt==2/*YUV422*/); + + if (image->use_clr_fmt==1/*YUV420*/) + count_chr = 6; + + /* Shuffle the UV planes into a single dst */ + for (k = 0; k < count_chr; k += 1) { + int remap = k>>1; + int plane = (k&1) + 1; /* 1 or 2 (U or V) */ + + if (image->use_clr_fmt==1/*YUV420*/) + remap += 1; + if (image->use_clr_fmt==2/*YUV422*/) + remap = remap_arr422[remap]; + + if (image->use_clr_fmt==1/*YUV420*/) + remap = transpose420[remap]; + if (image->use_clr_fmt==2/*YUV422*/) + remap = transpose422[remap]; + dst[k+1] = src[plane][remap]; + } + + for (k = count_chr; k < 15; k += 1) + dst[k+1] = 0; +} + +static void AdaptiveHPPermute(jxr_image_t image, int dst[16], const int src[16], int mbhp_pred_mode) +{ + if (mbhp_pred_mode == 1) { + int idx; + for (idx = 1 ; idx < 16 ; idx += 1) { + int map = image->hipass_ver_scanorder[idx-1]; + dst[idx] = src[map]; + + if (dst[idx] == 0) + continue; + + image->hipass_ver_scantotals[idx-1] += 1; + + + if (idx > 1 && image->hipass_ver_scantotals[idx-1] > image->hipass_ver_scantotals[idx-2]) { + SWAP(image->hipass_ver_scantotals[idx-1], image->hipass_ver_scantotals[idx-2]); + SWAP(image->hipass_ver_scanorder[idx-1], image->hipass_ver_scanorder[idx-2]); + } + } + } else { + int idx; + for (idx = 1 ; idx < 16 ; idx += 1) { + int map = image->hipass_hor_scanorder[idx-1]; + dst[idx] = src[map]; + + if (dst[idx] == 0) + continue; + + image->hipass_hor_scantotals[idx-1] += 1; + + + if (idx > 1 && image->hipass_hor_scantotals[idx-1] > image->hipass_hor_scantotals[idx-2]) { + SWAP(image->hipass_hor_scantotals[idx-1], image->hipass_hor_scantotals[idx-2]); + SWAP(image->hipass_hor_scanorder[idx-1], image->hipass_hor_scanorder[idx-2]); + } + } + } +} + +/* +* Convert the string of LP values to a compact list of non-zero LP +* values interspersed with the run of zero values. This is what will +* ultimately be encoded. The idea is that an LP set is generally +* sparse and it is more compact to encode the zero-runs then the +* zeros themselves. +*/ +static int RunLengthEncode(jxr_image_t image, int RLCoeffs[32], const int LPInput[16]) +{ + int lp_index = 1; + int rl_index = 0; + int run_count = 0; + + DEBUG(" RLCoeffs:"); + while (lp_index < 16) { + if (LPInput[lp_index] == 0) { + lp_index += 1; + run_count += 1; + continue; + } + + assert(rl_index <= 30); + RLCoeffs[rl_index+0] = run_count; + RLCoeffs[rl_index+1] = LPInput[lp_index]; + + DEBUG(" %d--0x%x", RLCoeffs[rl_index+0], RLCoeffs[rl_index+1]); + + rl_index += 2; + run_count = 0; + lp_index += 1; + } + + DEBUG(" num_non_zero=%d\n", rl_index/2); + + /* Return the number of non-zero values. */ + return rl_index/2; +} + +static int collect_lp_input(jxr_image_t image, int ch, int tx, int mx, int LPInput[8][16], int model_bits) +{ + int num_non_zero = 0; + + int count = 16; + int k; + if (ch > 0 && image->use_clr_fmt==2/*YUV422*/) + count = 8; + if (ch > 0 && image->use_clr_fmt==1/*YUV420*/) + count = 4; + + /* Collect into LPInput the coefficient values with the + model_bits stripped out. Be careful to shift only POSITIVE + numbers because the encoding later on uses magnitude-sign + to encode these values. The values can come out differently. */ + for (k = 1 ; k < count ; k += 1) { + int sign_flag = 0; + LPInput[ch][k] = MACROBLK_CUR_LP(image,ch,tx,mx,k-1); + if (LPInput[ch][k] < 0) { + sign_flag = 1; + LPInput[ch][k] = -LPInput[ch][k]; + } + LPInput[ch][k] >>= model_bits; + if (LPInput[ch][k] != 0) { + num_non_zero += 1; + if (sign_flag) + LPInput[ch][k] = -LPInput[ch][k]; + } + } + + return num_non_zero; +} + +void _jxr_w_MB_LP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int LPInput[8][16]; + int idx; + int full_planes; + int lap_mean[2]; + int ndx; + int cbplp; + + lap_mean[0] = 0; + lap_mean[1] = 0; + + for (idx = 0 ; idx < 8 ; idx += 1) { + int k; + for (k = 0 ; k < 16 ; k += 1) + LPInput[idx][k] = 0; + } + + + DEBUG(" MB_LP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_wbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" Init contexts\n"); + _jxr_InitializeCountCBPLP(image); + _jxr_InitLPVLC(image); + _jxr_InitializeAdaptiveScanLP(image); + _jxr_InitializeModelMB(&image->model_lp, 1/*LP*/); + } + + if (_jxr_ResetTotals(image, mx)) { + _jxr_ResetTotalsAdaptiveScanLP(image); + } + + full_planes = image->num_channels; + if (image->use_clr_fmt==1/*YUV420*/ || image->use_clr_fmt==2/*YUV422*/) + full_planes = 2; + + /* The CBPLP signals whether any non-zero coefficients are + present in the LP band for this macroblock. It is a bitmask + with a bit for each channel. So for example, YONLY, which + has 1 channel, has a 1-bit cbplp. */ + + cbplp = 0; + /* if CLR_FMT is YUV420, YUV422 or YUV444... */ + if (image->use_clr_fmt==1 || image->use_clr_fmt==2 || image->use_clr_fmt==3) { + int max; + int model_bits0; + int model_bits1; + int num_non_zero; + assert(full_planes == 2 || full_planes == 3); + + max = full_planes * 4 - 5; + model_bits0 = image->model_lp.bits[0]; + model_bits1 = image->model_lp.bits[1]; + + num_non_zero = collect_lp_input(image, 0, tx, mx, LPInput, model_bits0); + if (num_non_zero > 0) + cbplp |= 1; + + switch (image->use_clr_fmt) { + case 1:/*YUV420*/ + case 2:/*YUV422*/ + /* YUV422 has a 2-bit CBPLP, the low bit is the + CBP for Y, and the high bit for UV. */ + num_non_zero = collect_lp_input(image, 1, tx, mx, LPInput, model_bits1); + if (num_non_zero > 0) + cbplp |= 2; + num_non_zero = collect_lp_input(image, 2, tx, mx, LPInput, model_bits1); + if (num_non_zero > 0) + cbplp |= 2; + break; + + case 3:/*YUV444*/ + num_non_zero = collect_lp_input(image, 1, tx, mx, LPInput, model_bits1); + if (num_non_zero > 0) + cbplp |= 2; + num_non_zero = collect_lp_input(image, 2, tx, mx, LPInput, model_bits1); + if (num_non_zero > 0) + cbplp |= 4; + break; + } + + DEBUG(" MB_LP: count_zero_CBPLP=%d, count_max_CBPLP=%d, bitpos=%zu\n", + image->count_zero_CBPLP, image->count_max_CBPLP, _jxr_wbitstream_bitpos(str)); + if (image->count_zero_CBPLP <= 0 || image->count_max_CBPLP < 0) { + int cbplp_yuv; + if (image->count_max_CBPLP < image->count_zero_CBPLP) { + assert(max >= cbplp); + cbplp_yuv = max - cbplp; + } else { + cbplp_yuv = cbplp; + } + switch (image->use_clr_fmt) { + case 1:/*YUV420*/ + case 2:/*YUV422*/ + if (cbplp_yuv == 0) { + _jxr_wbitstream_uint1(str, 0); /* 0 */ + } else if (cbplp_yuv == 1) { + _jxr_wbitstream_uint2(str, 2); /* 10 */ + } else { + _jxr_wbitstream_uint2(str, 3); + if (cbplp_yuv == 2) + _jxr_wbitstream_uint1(str, 0); /* 110 */ + else + _jxr_wbitstream_uint1(str, 1); /* 111 */ + } + break; + + case 3:/*YUV444*/ + switch (cbplp_yuv) { /* YUV444 encoding */ + case 0: /* 0 */ + _jxr_wbitstream_uint1(str, 0); + break; + case 1: /* 100 */ + _jxr_wbitstream_uint2(str, 2); + _jxr_wbitstream_uint1(str, 0); + break; + default: + _jxr_wbitstream_uint4(str, 0xaa + cbplp_yuv-2); + break; + } + break; + default: + assert(0); + } + } else { + int ch; + for (ch = 0 ; ch < full_planes ; ch += 1) { + if (cbplp & (1<<(full_planes-1-ch))) + _jxr_wbitstream_uint1(str, 1); + else + _jxr_wbitstream_uint1(str, 0); + } + } + _jxr_UpdateCountCBPLP(image, cbplp, max); + + } else { + int ch; + cbplp = 0; + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int chroma_flag = ch > 0? 1 : 0; + int model_bits = image->model_lp.bits[chroma_flag]; + int num_non_zero; + + DEBUG(" MB_LP: ch=%d, model_bits=%d\n", ch, model_bits); + + num_non_zero = collect_lp_input(image, ch, tx, mx, LPInput, model_bits); + + /* If there are non-zero coefficients, then CBPLP + for this plane is 1. Also, the CBPLP in the + stream is a single bit for each plane. */ + if (num_non_zero > 0) { + _jxr_wbitstream_uint1(str, 1); + cbplp |= 1 << ch; + } else { + _jxr_wbitstream_uint1(str, 0); + } + } + } + DEBUG(" MB_LP: cbplp = 0x%x (full_planes=%u)\n", cbplp, full_planes); + + for (ndx = 0 ; ndx < full_planes ; ndx += 1) { + const int chroma_flag = ndx>0? 1 : 0; + int model_bits; + + DEBUG(" MB_LP: process full_plane %u, CBPLP for plane=%d, bitpos=%zu\n", + ndx, (cbplp>>ndx)&1, _jxr_wbitstream_bitpos(str)); +#if defined(DETAILED_DEBUG) + if (chroma_flag && image->use_clr_fmt == 2/*YUV422*/) { + int k; + DEBUG(" lp val[ndx=%d] refined data ==", ndx); + for (k = 1 ; k<8; k+=1) { + DEBUG(" 0x%x/0x%x", MACROBLK_CUR_LP(image,1,tx,mx,k-1), MACROBLK_CUR_LP(image,2,tx,mx,k-1)); + } + DEBUG("\n"); + DEBUG(" lp val[ndx=%d] before LPPermute ==", ndx); + for (k = 1 ; k<8; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + } + DEBUG("\n"); + + } else if (chroma_flag && image->use_clr_fmt == 1/*YUV420*/) { + int k; + DEBUG(" lp val[ndx=%d] before LPPermute ==", ndx); + for (k = 1 ; k<4; k+=1) { + DEBUG(" 0x%x/0x%x", LPInput[1][k], LPInput[2][k]); + } + DEBUG("\n"); + + } else { + int k; + DEBUG(" lp val[ndx=%d] refined data ==", ndx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_CUR_LP(image,ndx,tx,mx,k-1)); + } + DEBUG("\n"); + DEBUG(" lp val[ndx=%d] before LPPermute ==", ndx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", LPInput[ndx][k]); + } + DEBUG("\n"); + DEBUG(" scan order =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->lopass_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->lopass_scantotals[k]); + } + DEBUG("\n"); + } +#endif + /* If there are coeff bits, encode them. */ + if ((cbplp>>ndx) & 1) { + int LPInput_n[16]; + int RLCoeffs[32] = {0}; + int num_non_zero; + + if (chroma_flag && (image->use_clr_fmt==1 || image->use_clr_fmt==2)) { + /* LP for YUV42X components are shuffled by + a fixed permute. */ + FixedLPPermuteUV(image, LPInput_n, LPInput); + } else { + /* LP for YUV444 components (and the Y of + all YUV) are adaptively ordered. */ + AdaptiveLPPermute(image, LPInput_n, LPInput[ndx]); + } + + num_non_zero = RunLengthEncode(image, RLCoeffs, LPInput_n); + w_DECODE_BLOCK(image, str, 1 /* LP */, chroma_flag, RLCoeffs, num_non_zero); + lap_mean[chroma_flag] += num_non_zero; + } + + /* Emit REFINEMENT bits after the coeff bits are done. */ + + model_bits = image->model_lp.bits[chroma_flag]; + if (model_bits) { + static const int transpose444[16] = { 0, 4, 8,12, + 1, 5, 9,13, + 2, 6,10,14, + 3, 7,11,15 }; + DEBUG(" MB_LP: Start refine ndx=%d, model_bits=%d, bitpos=%zu\n", + ndx, model_bits, _jxr_wbitstream_bitpos(str)); + if (chroma_flag == 0) { + int k; + for (k=1 ;k<16; k+=1) { + int k_ptr = transpose444[k]; + w_REFINE_LP(str, MACROBLK_CUR_LP(image,ndx,tx,mx,k_ptr-1), model_bits); + } + } else { + int k; + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + for (k=1 ; k<4; k+=1) { + int k_ptr = transpose420[k]; + DEBUG(" MP_LP: Refine LP_Input[1/2][%d] = 0x%x/0x%x bitpos=%zu\n", + k_ptr, LPInput[1][k_ptr], LPInput[2][k_ptr], + _jxr_wbitstream_bitpos(str)); + w_REFINE_LP(str, MACROBLK_CUR_LP(image,1,tx,mx,k_ptr-1), model_bits); + w_REFINE_LP(str, MACROBLK_CUR_LP(image,2,tx,mx,k_ptr-1), model_bits); + } + break; + case 2: /* YUV422 */ + for (k=1 ; k<8; k+=1) { + int k_ptr = transpose422[k]; + DEBUG(" MP_LP: Refine LP_Input[1/2][%d] = 0x%x/0x%x bitpos=%zu\n", + k_ptr, LPInput[1][k_ptr], LPInput[2][k_ptr], + _jxr_wbitstream_bitpos(str)); + w_REFINE_LP(str, MACROBLK_CUR_LP(image,1,tx,mx,k_ptr-1), model_bits); + w_REFINE_LP(str, MACROBLK_CUR_LP(image,2,tx,mx,k_ptr-1), model_bits); + } + break; + default: /* All others */ + for (k=1 ;k<16; k+=1) { + int k_ptr = transpose444[k]; + w_REFINE_LP(str, MACROBLK_CUR_LP(image,ndx,tx,mx,k_ptr-1), model_bits); + } + break; + } + } + } + } + + DEBUG(" MB_LP: UpdateModelMB lap_mean={%d, %d}\n", lap_mean[0], lap_mean[1]); + _jxr_UpdateModelMB(image, lap_mean, &image->model_lp, 1/*band=LP*/); + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" AdaptLP at the end of mx=%d (my=%d, ndx=%u)\n", mx, my, ndx); + _jxr_AdaptLP(image); + } + + DEBUG(" MB_LP DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); +} + +static void encode_val_1(jxr_image_t image, struct wbitstream*str, +struct adaptive_vlc_s*vlc, int val1, int chr_cbp) +{ + int tmp; + + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + case 4: /* YUVK */ + case 6: /* NCOMPONENT */ + assert(val1 < 5); + if (vlc->table == 0) { + switch (val1) { + case 0: + _jxr_wbitstream_uint1(str, 1); + break; + case 1: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 2: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 3: + _jxr_wbitstream_uint4(str, 0); + break; + case 4: + _jxr_wbitstream_uint4(str, 1); + break; + } + } + else { + switch (val1) { + case 0: + _jxr_wbitstream_uint1(str, 1); + break; + case 1: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 0); + break; + case 2: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 1); + break; + case 3: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 2); + break; + case 4: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 3); + break; + } + } + break; + + case 1: /* YUV420 */ + case 2: /* YUV422 */ + case 3: /* YUV444 */ + tmp = val1; + if (tmp > 8) + tmp = 8; + + if (vlc->table == 0) { + switch (tmp) { + case 0: /* 010 */ + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 2); + break; + case 1: /* 00000 */ + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint4(str, 0); + break; + case 2: /* 0010 */ + _jxr_wbitstream_uint4(str, 2); + break; + case 3: /* 00001 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 4: /* 00010 */ + _jxr_wbitstream_uint4(str, 1); + _jxr_wbitstream_uint1(str, 0); + break; + case 5: /* 1 */ + _jxr_wbitstream_uint1(str, 1); + break; + case 6: /* 011 */ + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 3); + break; + case 7: /* 00011 */ + _jxr_wbitstream_uint4(str, 1); + _jxr_wbitstream_uint1(str, 1); + break; + case 8: /* 0011 */ + _jxr_wbitstream_uint4(str, 3); + break; + } + } + else { + switch (tmp) { + case 0: /* 1 */ + _jxr_wbitstream_uint1(str, 1); + break; + case 1: /* 001 */ + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 2: /* 010 */ + _jxr_wbitstream_uint2(str, 1); + _jxr_wbitstream_uint1(str, 0); + break; + case 3: /* 0001 */ + _jxr_wbitstream_uint4(str, 1); + break; + case 4: /* 0000 01 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint2(str, 1); + break; + case 5: /* 011 */ + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 3); + break; + case 6: /* 0000 1 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + case 7: /* 0000 000 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 0); + break; + case 8: /* 0000 001 */ + _jxr_wbitstream_uint4(str, 0); + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + } + } + + if (tmp >= 5) { + DEBUG(" MB_CBP: CHR_CBP=%x\n", chr_cbp); + assert(chr_cbp < 3); + switch (chr_cbp) { + case 0: /* 1 */ + _jxr_wbitstream_uint1(str, 1); + break; + case 1: /* 01 */ + _jxr_wbitstream_uint2(str, 1); + break; + case 2: /* 00 */ + _jxr_wbitstream_uint2(str, 0); + break; + } + } + + if (tmp == 8) { + int val_inc; + assert((val1 - tmp) <= 2); + val_inc = val1 - tmp; + DEBUG(" MB_CBP: VAL_INC=%d\n", val_inc); + switch (val_inc) { + case 0: /* 1 */ + _jxr_wbitstream_uint1(str, 1); + break; + case 1: /* 01 */ + _jxr_wbitstream_uint2(str, 1); + break; + case 2: /* 00 */ + _jxr_wbitstream_uint2(str, 0); + break; + } + } + break; + default: + assert(0); + } +} + +void _jxr_w_MB_CBP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + int channels; + int diff_cbp[MAX_CHANNELS]; + int ch; + int cbp; + int block; + DEBUG(" MB_CBP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_wbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_CBP: InitContext\n"); + /* This happens only at the top left edge of the tile. */ + _jxr_InitCBPVLC(image); + } + + /* "Channels" is not quite the same as "planes". For the + purposes of CBP parsing, a color image has 1 channel. */ + channels = 1; + if (image->use_clr_fmt==4/*YUVK*/ || image->use_clr_fmt==6/*NCOMPONENT*/) + channels = image->num_channels; + + /* Get the diff_cbp values for all the channels. */ + for (ch = 0 ; ch < image->num_channels ; ch += 1) + diff_cbp[ch] = MACROBLK_CUR(image,ch,tx,mx).hp_diff_cbp; + + /* Now process the diff_cbp values for the channels. Note that + if this is a YUV image, then channels is 1 and the loop + knows to process three planes at once. */ + for (ch = 0 ; ch < channels ; ch += 1) { + + /* The CBP Block mask is a 4-bit mask that indicates + which bit-blocks of the 16bit diff_cbp has non-zero + bits in them. The cbp_X_block_masks are 4bit values + that indicate which nibbles of the 16bit diff_cbp + values have bits set. */ + int cbp_Y_block_mask = 0; + int cbp_U_block_mask = 0; + int cbp_V_block_mask = 0; + if (diff_cbp[ch] & 0x000f) + cbp_Y_block_mask |= 0x001; + if (diff_cbp[ch] & 0x00f0) + cbp_Y_block_mask |= 0x002; + if (diff_cbp[ch] & 0x0f00) + cbp_Y_block_mask |= 0x004; + if (diff_cbp[ch] & 0xf000) + cbp_Y_block_mask |= 0x008; + + + switch (image->use_clr_fmt) { + /* If thie is a YUV420 image, then the block mask + includes masks for all the 3 planes. The UV + planes' have only 1 CBP bit per block, so this + is simple. */ + case 1: /* YUV420 */ + if (diff_cbp[1] & 0x01) + cbp_U_block_mask |= 0x01; + if (diff_cbp[1] & 0x02) + cbp_U_block_mask |= 0x02; + if (diff_cbp[1] & 0x04) + cbp_U_block_mask |= 0x04; + if (diff_cbp[1] & 0x08) + cbp_U_block_mask |= 0x08; + if (diff_cbp[2] & 0x01) + cbp_V_block_mask |= 0x01; + if (diff_cbp[2] & 0x02) + cbp_V_block_mask |= 0x02; + if (diff_cbp[2] & 0x04) + cbp_V_block_mask |= 0x04; + if (diff_cbp[2] & 0x08) + cbp_V_block_mask |= 0x08; + break; + /* If this is a YUV422 iamge, then the block mask + includes masks for all the 3 planes, with the + UV diff_cbp bits encoded funny. */ + case 2: /* YUV422*/ + if (diff_cbp[1] & 0x05) + cbp_U_block_mask |= 0x01; + if (diff_cbp[1] & 0x0a) + cbp_U_block_mask |= 0x02; + if (diff_cbp[1] & 0x50) + cbp_U_block_mask |= 0x04; + if (diff_cbp[1] & 0xa0) + cbp_U_block_mask |= 0x08; + if (diff_cbp[2] & 0x05) + cbp_V_block_mask |= 0x01; + if (diff_cbp[2] & 0x0a) + cbp_V_block_mask |= 0x02; + if (diff_cbp[2] & 0x50) + cbp_V_block_mask |= 0x04; + if (diff_cbp[2] & 0xa0) + cbp_V_block_mask |= 0x08; + break; + /* If this is a YUV444 image, then the block mask + includes masks for all 3 planes. */ + case 3: /*YUV444*/ + assert(ch == 0); + if (diff_cbp[1] & 0x000f) + cbp_U_block_mask |= 0x01; + if (diff_cbp[1] & 0x00f0) + cbp_U_block_mask |= 0x02; + if (diff_cbp[1] & 0x0f00) + cbp_U_block_mask |= 0x04; + if (diff_cbp[1] & 0xf000) + cbp_U_block_mask |= 0x08; + if (diff_cbp[2] & 0x000f) + cbp_V_block_mask |= 0x01; + if (diff_cbp[2] & 0x00f0) + cbp_V_block_mask |= 0x02; + if (diff_cbp[2] & 0x0f00) + cbp_V_block_mask |= 0x04; + if (diff_cbp[2] & 0xf000) + cbp_V_block_mask |= 0x08; + break; + default: + break; + } + + DEBUG(" MB_CBP: diff_cbp[%d]=0x%x (HP_CBP=0x%x) cbp_block_mask=0x%x:%x:%x\n", + ch, diff_cbp[ch], MACROBLK_CUR_HPCBP(image,ch,tx,mx), + cbp_Y_block_mask, cbp_U_block_mask, cbp_V_block_mask); + + /* A bit in the CBP (up to 4 bits) is true if the + corresponding bit of any of hte YUV planes' cbp is + set. That tells the decoder to look for CBP values + in any of the planes. */ + cbp = cbp_Y_block_mask | cbp_U_block_mask | cbp_V_block_mask; + DEBUG(" MB_CBP: Refined CBP=0x%x\n", cbp); + w_REFINE_CBP(image, str, cbp); + + for (block = 0 ; block < 4 ; block += 1) { + struct adaptive_vlc_s*vlc; + int blkcbp; + /* If there are no diff_cbp bits in this nibble of + any of the YUV planes, then skip. */ + if ((cbp & (1<<block)) == 0) + continue; + + vlc = image->vlc_table + DecNumBlkCBP; + assert(vlc->deltatable == 0); + + DEBUG(" MB_CBP: block=%d Use DecNumBlkCBP table=%d, discriminant=%d, bitpos=%zu\n", + block, vlc->table, vlc->discriminant, _jxr_wbitstream_bitpos(str)); + + /* This is the block of CBP bits to encode. The + blkcbp is the nibble (indexed by "block") of + the diff_cbp for the Y plane, also also bits + set if the UV diff_cbp values have bits + set. The cbp_chr_X masks have the nibbles of + the UV diff_cbp. */ + blkcbp = (diff_cbp[ch] >> 4*block) & 0x000f; + + if (cbp_U_block_mask & (1<<block)) + blkcbp |= 0x10; + if (cbp_V_block_mask & (1<<block)) + blkcbp |= 0x20; + + { + /* Map the CBP bit block to a more encodable + code. Note that this map doesn't look at the + chroma mask bits because this code is used to + generate only the low 4 bits by the receiver. */ + static const int code_from_blkcbp[16] = { + 0, 4, 5, 2, + 6, 8, 9,12, + 7,10,11,13, + 3,14,15, 1 }; + int code = code_from_blkcbp[blkcbp&0x0f]; + /* Break the code down to a further encoded val + and refinement bit count. */ + static const int val_from_code[16] = { + 0, 5, 2, 2, + 1, 1, 1, 1, + 3, 3, 3, 3, + 4, 4, 4, 4 }; + int val = val_from_code[code]; + int chr_cbp = (blkcbp >> 4) & 0x3; + int num_blkcbp; + if (chr_cbp > 0) { + chr_cbp -= 1; + val += 6; + } + + assert(val > 0); + num_blkcbp = val-1; + + DEBUG(" MB_CBP: NUM_BLKCBP=%d, iVal=%d, iCode=%d\n", num_blkcbp, val, code); + DEBUG(" MB_CBP: blkcbp=0x%x, code=%d for chunk blk=%d\n", blkcbp, code, block); + + /* Adapt DecNumBlkCBP based on the num_blkcbp value. */ + if (image->use_clr_fmt==0 || image->use_clr_fmt==4 || image->use_clr_fmt==6) { + static const int Num_BLKCBP_Delta5[5] = {0, -1, 0, 1, 1}; + assert(num_blkcbp < 5); + vlc->discriminant += Num_BLKCBP_Delta5[num_blkcbp]; + } else { + int tmp = val-1; + static const int Num_BLKCBP_Delta9[9] = {2, 2, 1, 1, -1, -2, -2, -2, -3}; + if (tmp > 8) { + assert(tmp < 11); + tmp = 8; + } + assert(tmp < 9); + vlc->discriminant += Num_BLKCBP_Delta9[tmp]; + } + + DEBUG(" MB_CBP: NUM_BLKCBP=%d, discriminant becomes=%d, \n", + num_blkcbp, vlc->discriminant); + + /* Encode VAL-1, and CHR_CBP if present. */ + encode_val_1(image, str, vlc, val-1, chr_cbp); + + { + /* Encode CODE_INC */ + static const int code_inc_from_code[16] = { + 0, 0, 0, 1, + 0, 1, 2, 3, + 0, 1, 2, 3, + 0, 1, 2, 3 }; + static const int code_inc_bits_from_code[16] = { + 0, 0, 1, 1, + 2, 2, 2, 2, + 2, 2, 2, 2, + 2, 2, 2, 2 }; + + int cbp_chr_U; + int cbp_chr_V; + + assert(code < 16); + + switch (code_inc_bits_from_code[code]) { + case 0: + break; + case 1: + _jxr_wbitstream_uint1(str, code_inc_from_code[code]); + break; + case 2: + _jxr_wbitstream_uint2(str, code_inc_from_code[code]); + break; + default: + assert(0); + } + + cbp_chr_U = 0; + cbp_chr_V = 0; + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + case 4: /* YUVK */ + case 6: /* NCOMPONENT */ + break; + case 1:/* YUV420 */ + /* Nothing to encode. The CHR_CBP bits are + sufficient to carry all the UV CBP + informtation for YUV420 UV planes. */ + break; + case 2: /* YUV422 */ + if (blkcbp & 0x10) + refine_cbp_chr422(image, str, diff_cbp[1], block); + if (blkcbp & 0x20) + refine_cbp_chr422(image, str, diff_cbp[2], block); + break; + case 3: /* YUV444 */ + cbp_chr_U = (diff_cbp[1] >> 4*block) & 0x000f; + cbp_chr_V = (diff_cbp[2] >> 4*block) & 0x000f; + if (blkcbp & 0x10) { + DEBUG(" MB_CBP: Refined CBP_U=0x%x\n", cbp_chr_U); + w_REFINE_CBP_CHR(image, str, cbp_chr_U); + } + if (blkcbp & 0x20) { + DEBUG(" MB_CBP: Refined CBP_V=0x%x\n", cbp_chr_V); + w_REFINE_CBP_CHR(image, str, cbp_chr_V); + } + break; + default: + assert(0); + break; + } + } + } + } + } + + DEBUG(" MB_CBP done tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); +} + +static void refine_cbp_chr422(jxr_image_t image, struct wbitstream*str, int diff_cbp, int block) +{ + static const int shift_mask[4] = {0, 1, 4, 5}; + int bits = diff_cbp >> shift_mask[block]; + switch (bits & 5) { + case 0: + assert(0); + break; + case 1: /* 1 */ + _jxr_wbitstream_uint1(str, 1); + break; + case 4: /* 01 */ + _jxr_wbitstream_uint2(str, 1); + break; + case 5: /* 00 */ + _jxr_wbitstream_uint2(str, 0); + break; + } +} + +static void refine_cbp_core(jxr_image_t image, struct wbitstream*str, int cbp_mask) +{ + switch (cbp_mask) { + case 0x0: + /* If there are no CBP bits, then encode nothing. */ + case 0xf: + break; + /* REF_CBP (num_cbp==1) */ + case 0x1: + _jxr_wbitstream_uint2(str, 0); + break; + case 0x2: + _jxr_wbitstream_uint2(str, 1); + break; + case 0x4: + _jxr_wbitstream_uint2(str, 2); + break; + case 0x8: + _jxr_wbitstream_uint2(str, 3); + break; + /* REF_CBP1 (num_cbp==2) */ + case 0x3: + _jxr_wbitstream_uint2(str, 0); + break; + case 0x5: + _jxr_wbitstream_uint2(str, 1); + break; + case 0x6: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 0); + break; + case 0x9: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 1); + break; + case 0xa: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 2); + break; + case 0xc: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 3); + break; + /* REF_CBP (num_cbp==3) */ + case 0xe: + _jxr_wbitstream_uint2(str, 0); + break; + case 0xd: + _jxr_wbitstream_uint2(str, 1); + break; + case 0xb: + _jxr_wbitstream_uint2(str, 2); + break; + case 0x7: + _jxr_wbitstream_uint2(str, 3); + break; + } +} + +static void w_REFINE_CBP(jxr_image_t image, struct wbitstream*str, int cbp_block_mask) +{ + int num_cbp = 0; + int idx; + static const int Num_CBP_Delta[5] = {0, -1, 0, 1, 1}; + struct adaptive_vlc_s*vlc; + int vlc_table; + + DEBUG(" REFINE_CBP: input CBP=%d (0x%x)\n", cbp_block_mask, cbp_block_mask); + + for (idx = 0 ; idx < 4 ; idx += 1) { + if (cbp_block_mask & (1<<idx)) + num_cbp += 1; + } + + vlc = image->vlc_table + DecNumCBP; + + assert(vlc->deltatable == 0 && num_cbp < 5); + vlc->discriminant += Num_CBP_Delta[num_cbp]; + + + /* First encode the NUM_CBP. (The REFINE_CBP in the spec does + not include this step, but we include it here because it is + part of the cbp_block_mask encoding.) */ + vlc_table = vlc->table; + assert(vlc_table < 2); + + DEBUG(" REFINE_CBP: num_cbp=%d, vlc table=%d\n", num_cbp, vlc_table); + + if (vlc_table == 0) { + switch (num_cbp) { + case 4: + _jxr_wbitstream_uint1(str, 0); + case 2: + _jxr_wbitstream_uint1(str, 0); + case 1: + _jxr_wbitstream_uint1(str, 0); + case 0: + _jxr_wbitstream_uint1(str, 1); + break; + case 3: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + break; + } + } + else { + switch (num_cbp) { + case 0: + _jxr_wbitstream_uint1(str, 1); + break; + default: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, num_cbp-1); + break; + } + } + + /* Now encode the CBP itself. Note that many encodings look + the same. The decoder uses the NUM_CBP encoded above to + distinguish between the different possible values. */ + refine_cbp_core(image, str, cbp_block_mask); +} + +static void w_REFINE_CBP_CHR(jxr_image_t image, struct wbitstream*str, int cbp_block_mask) +{ + int num_cbp = 0; + int idx; + + DEBUG(" REFINE_CBP: input CBP(CHR)= 0x%x)\n", cbp_block_mask); + + for (idx = 0 ; idx < 4 ; idx += 1) { + if (cbp_block_mask & (1<<idx)) + num_cbp += 1; + } + + /* If refining a CBP block mask for a chroma plane, then we + know that there must be at least one block bit set, so we + can encode num_cbp-1 instead, and possibly save space. */ + assert(num_cbp > 0); + num_cbp -= 1; + + /* First encode the NUM_CBP. (The REFINE_CBP in the spec does + not include this step, but we include it here because it is + part of the cbp_block_mask encoding.) */ + DEBUG(" REFINE_CBP(CHR): num_ch_blk=%d\n", num_cbp); + + assert(num_cbp < 4); + switch (num_cbp) { + case 0: /* 1 */ + _jxr_wbitstream_uint1(str,1); + break; + case 1: /* 01 */ + _jxr_wbitstream_uint2(str, 1); + break; + case 2: /* 000 */ + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 0); + break; + case 3: /* 001 */ + _jxr_wbitstream_uint2(str, 0); + _jxr_wbitstream_uint1(str, 1); + break; + } + + /* Now encode the CBP itself. Note that many encodings look + the same. The decoder uses the NUM_CBP encoded above to + distinguish between the different possible values. */ + refine_cbp_core(image, str, cbp_block_mask); +} + + +int _jxr_w_MB_HP(jxr_image_t image, struct wbitstream*str, + int alpha_flag, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + struct wbitstream*strFB) +{ + int flex_flag; + int mbhp_pred_mode; + int idx; + + /* This function can act either as MB_HP() or MB_HP_FLEX() */ + DEBUG(" MB_HP tile=[%u %u] mb=[%u %u] bitpos=%zu\n", + tx, ty, mx, my, _jxr_wbitstream_bitpos(str)); + + if (_jxr_InitContext(image, tx, ty, mx, my)) { + DEBUG(" MB_HP: InitContext\n"); + /* This happens only at the top left edge of the tile. */ + _jxr_InitHPVLC(image); + _jxr_InitializeAdaptiveScanHP(image); + } + + if (_jxr_ResetTotals(image, mx)) { + _jxr_ResetTotalsAdaptiveScanHP(image); + } + + /* FLEXBITS are embedded in the HP data if there are FLEXBITS + present in the bitstream AND we are in SPATIAL (not + FREQUENCY) mode. */ + flex_flag = 1; + if (image->bands_present == 1) /* NOFLEXBITS */ + flex_flag = 0; + if (FREQUENCY_MODE_CODESTREAM_FLAG(image) != 0) /* FREQUENCY_MODE */ + flex_flag = 0; + + mbhp_pred_mode = MACROBLK_CUR(image,0,tx,mx).mbhp_pred_mode; + + for (idx = 0 ; idx < image->num_channels; idx += 1) { + int chroma_flag = idx>0? 1 : 0; + int nblocks = 4; + unsigned model_bits; + int cbp; + int block; + if (chroma_flag && image->use_clr_fmt==1/*YUV420*/) + nblocks = 1; + else if (chroma_flag && image->use_clr_fmt==2/*YUV422*/) + nblocks = 2; + + model_bits = MACROBLK_CUR(image,0,tx,mx).hp_model_bits[chroma_flag]; + cbp = MACROBLK_CUR_HPCBP(image, idx, tx, mx); + + DEBUG(" MB_HP channel=%d, cbp=0x%x, model_bits=%u MBHPMode=%d\n", + idx, cbp, model_bits, mbhp_pred_mode); + for (block=0 ; block<(nblocks*4) ; block += 1, cbp >>= 1) { + int bpos = block; + int num_nonzero; + /* Only remap the Y plane of YUV42X data. */ + if (nblocks == 4) + bpos = _jxr_hp_scan_map[block]; + num_nonzero = w_DECODE_BLOCK_ADAPTIVE(image, str, tx, mx, + cbp&1, chroma_flag, + idx, bpos, mbhp_pred_mode, + model_bits); + if (num_nonzero < 0) { + DEBUG("ERROR: r_DECODE_BLOCK_ADAPTIVE returned rc=%d\n", num_nonzero); + return JXR_EC_ERROR; + } + if (strFB) + w_BLOCK_FLEXBITS(image, strFB, tx, ty, mx, my, + idx, bpos, model_bits); + else if (flex_flag) + w_BLOCK_FLEXBITS(image, str, tx, ty, mx, my, + idx, bpos, model_bits); + } + + } + + if (_jxr_ResetContext(image, tx, mx)) { + DEBUG(" MB_HP: Run AdaptHP\n"); + _jxr_AdaptHP(image); + } + + DEBUG(" MB_HP DONE tile=[%u %u] mb=[%u %u]\n", tx, ty, mx, my); + return 0; +} + +static void w_DECODE_FLEX(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned mx, + int ch, unsigned block, unsigned k, + unsigned flexbits) +{ + int coeff = MACROBLK_CUR_HP(image, ch, tx, mx, block, k); + int sign = 0; + int mask; + int flex_ref; + + if (coeff < 0) { + sign = 1; + coeff = -coeff; + } + + coeff >>= image->trim_flexbits; + mask = (1 << flexbits) - 1; + + flex_ref = coeff & mask; + coeff &= ~mask; + DEBUG(" DECODE_FLEX: coeff=0x%08x, flex_ref=0x%08x\n", coeff, flex_ref); + + _jxr_wbitstream_uintN(str, flex_ref, flexbits); + + if (coeff == 0 && flex_ref != 0) + _jxr_wbitstream_uint1(str, sign); +} + +static void w_BLOCK_FLEXBITS(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty, + unsigned mx, unsigned my, + unsigned ch, unsigned bl, unsigned model_bits) +{ + const int transpose444 [16] = {0, 4, 8,12, + 1, 5, 9,13, + 2, 6,10,14, + 3, 7,11,15 }; + unsigned flexbits_left = model_bits; + if (image->trim_flexbits > flexbits_left) + flexbits_left = 0; + else + flexbits_left -= image->trim_flexbits; + + DEBUG(" BLOCK_FLEXBITS: flexbits_left=%u (model=%u, trim=%u) block=%u bitpos=%zu\n", + flexbits_left, model_bits, image->trim_flexbits, bl, _jxr_wbitstream_bitpos(str)); + + if (flexbits_left > 0) { + int idx; + for (idx = 1 ; idx < 16 ; idx += 1) { + int idx_trans = transpose444[idx]; + w_DECODE_FLEX(image, str, tx, mx, ch, bl, idx_trans-1, flexbits_left); + } + } + + DEBUG(" BLOCK_FLEXBITS done\n"); +} + +static void w_DEC_DC(jxr_image_t image, struct wbitstream*str, + int model_bits, int chroma_flag, int is_dc_ch, + int32_t dc_val) +{ + int idx; + int sign_flag = 0; + int zero_flag = dc_val==0; + uint32_t dc_ref_stack; + + DEBUG(" DEC_DC: DC value is %d (0x%08x)\n", dc_val, dc_val); + + /* Values are encoded as magnitude/sign, and *not* the 2s + complement value. So here we get the sign of the value and + convert it to a magnitude for encoding. */ + if (dc_val < 0) { + sign_flag = 1; + dc_val = -dc_val; + } + + /* Pull the LSB bits from the value and save them in a stack + of DC_REF values. This reduces the number of bits in the dc + val that will be encoded. */ + dc_ref_stack = 0; + for (idx = 0 ; idx < model_bits ; idx += 1) { + dc_ref_stack <<= 1; + dc_ref_stack |= dc_val&1; + dc_val >>= 1; + } + + /* The is_dc_ch flag only gates the encoding of the high bits + of the absolute level. If the level is non-zero, then + presumably the is_dc_ch flag is true and we go ahead and + encode the level. The model_bits are encoded in any case. */ + if (dc_val != 0) { + assert( is_dc_ch ); + DEBUG(" DEC_DC: DECODE_ABS_LEVEL = %d (0x%08x)\n", dc_val, dc_val); + w_DECODE_ABS_LEVEL(image, str, 0/*DC*/, chroma_flag, dc_val + 1); + } + + /* Play back the bits in the dc_ref stack. This causes them to + appear MSB first in the DC_REF field. These are the + model_bits, the LSB of the level. */ + for (idx = 0 ; idx < model_bits ; idx += 1) { + _jxr_wbitstream_uint1(str, dc_ref_stack&1); + dc_ref_stack >>= 1; + } + + /* The sign bit is last. Include it only if the value is nonzero*/ + if (!zero_flag) { + DEBUG(" DEC_DC: sign_flag=%s\n", sign_flag? "true":"false"); + _jxr_wbitstream_uint1(str, sign_flag); + } +} + +static void encode_abslevel_index(jxr_image_t image, struct wbitstream*str, + int abslevel_index, int vlc_select); + +/* +* This function actually *ENCODES* the ABS_LEVEL. +*/ +static void w_DECODE_ABS_LEVEL(jxr_image_t image, struct wbitstream*str, + int band, int chroma_flag, uint32_t level) +{ + int vlc_select = _jxr_vlc_select(band, chroma_flag); + const uint32_t abslevel_limit[6] = { 2, 3, 5, 9, 13, 17 }; + const uint32_t abslevel_remap[6] = {2, 3, 4, 6, 10, 14}; + const int abslevel_fixedlen[6] = {0, 0, 1, 2, 2, 2}; + int abslevel_index; + + DEBUG(" Use vlc_select = %s (table=%d) to encode level index, bitpos=%zu\n", + _jxr_vlc_index_name(vlc_select), image->vlc_table[vlc_select].table, + _jxr_wbitstream_bitpos(str)); + + /* choose the smallest level index that can carry "level". the + abslevel_limit array holds the maximim value that each + index can encode. */ + abslevel_index = 0; + while (abslevel_index < 6 && abslevel_limit[abslevel_index] < level) { + abslevel_index += 1; + } + + DEBUG(" ABSLEVEL_INDEX = %d\n", abslevel_index); + encode_abslevel_index(image, str, abslevel_index, vlc_select); + + image->vlc_table[vlc_select].discriminant += _jxr_abslevel_index_delta[abslevel_index]; + + if (abslevel_index < 6) { + /* The level index encodes most of the level value. The + abslevel_remap is the actual value that the index + encodes. The fixedlen array then gives the number of + extra bits available to encode the last bit of + value. This *must* be enough. */ + + int idx; + int fixedlen = abslevel_fixedlen[abslevel_index]; + uint32_t level_ref = level - abslevel_remap[abslevel_index]; + uint32_t level_ref_stack = 0; + + DEBUG(" ABS_LEVEL = 0x%x (fixed = %d, level_ref = %d)\n", + level, fixedlen, level_ref); + + /* Stack the residual bits... */ + for (idx = 0 ; idx < fixedlen ; idx += 1) { + level_ref_stack <<= 1; + level_ref_stack |= level_ref & 1; + level_ref >>= 1; + } + + assert(level_ref == 0); + + /* Emit the residual bits in MSB order. */ + for (idx = 0 ; idx < fixedlen ; idx += 1) { + _jxr_wbitstream_uint1(str, level_ref_stack&1); + level_ref_stack >>= 1; + } + + } else { + uint32_t level_ref = level - 2; + unsigned fixed = 0; + unsigned fixed_tmp; + assert(level_ref > 1); + while (level_ref > 1) { + level_ref >>= 1; + fixed += 1; + } + + assert(level >= ((1U<<fixed) + 2)); + level_ref = level - (1<<fixed) - 2; + DEBUG(" ABS_LEVEL = 0x%x (fixed = %d, level_ref = %u\n", level, fixed, level_ref); + + fixed_tmp = fixed - 4; + if (fixed_tmp < 15) { + _jxr_wbitstream_uint4(str, fixed_tmp); + + } else { + _jxr_wbitstream_uint4(str, 0xf); + fixed_tmp -= 15; + if (fixed_tmp < 3) { + _jxr_wbitstream_uint2(str, fixed_tmp); + } else { + _jxr_wbitstream_uint2(str, 0x3); + fixed_tmp -= 3; + assert(fixed_tmp < 8); + _jxr_wbitstream_uint3(str, fixed_tmp); + } + } + _jxr_wbitstream_uintN(str, level_ref, fixed); + } +} + +static void encode_abslevel_index(jxr_image_t image, struct wbitstream*str, + int abslevel_index, int vlc_select) +{ + int table = image->vlc_table[vlc_select].table; + assert(table==0 || table==1); + + if (table==0) { + switch (abslevel_index) { + case 0: + _jxr_wbitstream_uint2(str, 0x1); + break; + case 1: + _jxr_wbitstream_uint2(str, 0x2); + break; + case 2: + _jxr_wbitstream_uint2(str, 0x3); + break; + case 3: + _jxr_wbitstream_uint2(str, 0x0); + _jxr_wbitstream_uint1(str, 0x1); + break; + case 4: + _jxr_wbitstream_uint4(str, 0x1); + break; + case 5: + _jxr_wbitstream_uint4(str, 0x0); + _jxr_wbitstream_uint1(str, 0x0); + break; + case 6: + _jxr_wbitstream_uint4(str, 0x0); + _jxr_wbitstream_uint1(str, 0x1); + break; + } + } + else { + switch (abslevel_index) { + case 0: + _jxr_wbitstream_uint1(str, 0x1); + break; + case 1: + _jxr_wbitstream_uint2(str, 0x1); + break; + case 2: + _jxr_wbitstream_uint2(str, 0x0); + _jxr_wbitstream_uint1(str, 0x1); + break; + case 3: + _jxr_wbitstream_uint4(str, 0x1); + break; + case 4: + _jxr_wbitstream_uint4(str, 0x0); + _jxr_wbitstream_uint1(str, 0x1); + break; + case 5: + _jxr_wbitstream_uint4(str, 0x0); + _jxr_wbitstream_uint2(str, 0x0); + break; + case 6: + _jxr_wbitstream_uint4(str, 0x0); + _jxr_wbitstream_uint2(str, 0x1); + break; + } + } +} + +static void w_DECODE_BLOCK(jxr_image_t image, struct wbitstream*str, int band, int chroma_flag, + const int RLCoeffs[32], int num_non_zero) +{ + int location = 1; + int index_code = 0; + int sign_flag = 0; + int value = RLCoeffs[1]; + int context; + int nz_index; + + /* if CLR_FMT is YUV420 or YUV422 */ + if (image->use_clr_fmt==1/*YUV420*/ && chroma_flag && band==1) + location = 10; + if (image->use_clr_fmt==2/*YUV422*/ && chroma_flag && band==1) + location = 2; + + if (value < 0) { + sign_flag = 1; + value = -value; + } + + /* FIRST_INDEX */ + if (RLCoeffs[0] == 0) + index_code |= 1; + if (value != 1) + index_code |= 2; + + if (num_non_zero == 1) + index_code |= 0<<2; + else if (RLCoeffs[2] == 0) + index_code |= 1<<2; + else + index_code |= 2<<2; + + DEBUG(" DECODE_BLOCK: chroma_flag=%d, band=%d value=%s%d num_non_zero=%d index_code=0x%x bitpos=%zu\n", + chroma_flag, band, sign_flag?"-":"+", value, num_non_zero, index_code, _jxr_wbitstream_bitpos(str)); + + DEBUG(" coeff[0] = %d (run)\n", RLCoeffs[0]); + DEBUG(" coeff[1] = 0x%x\n", RLCoeffs[1]); + DEBUG(" coeff[1*2+0] = %d (run)\n", RLCoeffs[2]); + + context = (index_code&1) & (index_code>>2); + + /* Encode FIRST_INDEX */ + w_DECODE_FIRST_INDEX(image, str, chroma_flag, band, index_code); + /* SIGN_FLAG */ + _jxr_wbitstream_uint1(str, sign_flag); + if (index_code&2) { + DEBUG(" DECODE_BLOCK: DECODE_ABS_LEVEL = %d (0x%08x)\n", value, value); + w_DECODE_ABS_LEVEL(image, str, band, context, value); + } + if ((index_code&1) == 0) { + w_DECODE_RUN(image, str, 15-location, RLCoeffs[0]); + } + location += 1 + RLCoeffs[0]; + + nz_index = 1; + while (nz_index < num_non_zero) { + /* If the previous index didn't already flag this as a + zero run, then encode the run now. */ + if (RLCoeffs[2*nz_index+0] > 0) + w_DECODE_RUN(image, str, 15-location, RLCoeffs[2*nz_index+0]); + + location += 1 + RLCoeffs[2*nz_index+0]; + + value = RLCoeffs[2*nz_index+1]; + sign_flag = 0; + if (value < 0) { + sign_flag = 1; + value = -value; + } + + /* index_code */ + index_code = 0; + if (value != 1) + index_code |= 1; + if (nz_index+1 == num_non_zero) + index_code |= 0<<1; + else if (RLCoeffs[2*nz_index+2] == 0) + index_code |= 1<<1; + else + index_code |= 2<<1; + + DEBUG(" DECODE_BLOCK: nz_index=%u, index_code=%x\n", nz_index, index_code); + w_DECODE_INDEX(image, str, location, chroma_flag, band, context, index_code); + context &= index_code >> 1; + + _jxr_wbitstream_uint1(str, sign_flag); + if (value != 1) { + w_DECODE_ABS_LEVEL(image, str, band, context, value); + } + + nz_index += 1; + } +} + +static void w_DECODE_FIRST_INDEX(jxr_image_t image, struct wbitstream*str, + int chroma_flag, int band, int first_index) +{ + struct encode_table_s{ + unsigned char bits; + unsigned char len; + }; + + typedef struct encode_table_s first_index_table_t[12]; + static const first_index_table_t first_index_vlc[5] = { + { /* VLC0 */ + { 0x08, 5 }, /* 0 == 0000 1... */ + { 0x04, 6 }, /* 1 == 0000 01.. */ + { 0x00, 7 }, /* 2 == 0000 000. */ + { 0x02, 7 }, /* 3 == 0000 001. */ + { 0x20, 5 }, /* 4 == 0010 0... */ + { 0x40, 3 }, /* 5 == 010. .... */ + { 0x28, 5 }, /* 6 == 0010 1... */ + { 0x80, 1 }, /* 7 == 1... .... */ + { 0x30, 5 }, /* 8 == 0011 0... */ + { 0x10, 4 }, /* 9 == 0001 .... */ + { 0x38, 5 }, /* 10 == 0011 1... */ + { 0x60, 3 } /* 11 == 011. .... */ + }, + { /* VLC1 */ + { 0x20, 4 }, /* 0 == 0010 .... */ + { 0x10, 5 }, /* 1 == 0001 0... */ + { 0x00, 6 }, /* 2 == 0000 00.. */ + { 0x04, 6 }, /* 3 == 0000 01.. */ + { 0x30, 4 }, /* 4 == 0011 .... */ + { 0x40, 3 }, /* 5 == 010. .... */ + { 0x18, 5 }, /* 6 == 0001 1... */ + { 0xc0, 2 }, /* 7 == 11.. .... */ + { 0x60, 3 }, /* 8 == 011. .... */ + { 0x80, 3 }, /* 9 == 100. .... */ + { 0x08, 5 }, /* 10 == 0000 1... */ + { 0xa0, 3 } /* 11 == 101. .... */ + }, + { /* VLC2 */ + { 0xc0, 2 }, /* 0 == 11.. .... */ + { 0x20, 3 }, /* 1 == 001. .... */ + { 0x00, 7 }, /* 2 == 0000 000. */ + { 0x02, 7 }, /* 3 == 0000 001. */ + { 0x08, 5 }, /* 4 == 0000 1... */ + { 0x40, 3 }, /* 5 == 010. .... */ + { 0x04, 7 }, /* 6 == 0000 010. */ + { 0x60, 3 }, /* 7 == 011. .... */ + { 0x80, 3 }, /* 8 == 100. .... */ + { 0xa0, 3 }, /* 9 == 101. .... */ + { 0x06, 7 }, /* 10 == 0000 011. */ + { 0x10, 4 }, /* 11 == 0001 .... */ + }, + { /* VLC3 */ + { 0x20, 3 }, /* 0 == 001. .... */ + { 0xc0, 2 }, /* 1 == 11.. .... */ + { 0x00, 7 }, /* 2 == 0000 000. */ + { 0x08, 5 }, /* 3 == 0000 1... */ + { 0x10, 5 }, /* 4 == 0001 0... */ + { 0x40, 3 }, /* 5 == 010. .... */ + { 0x02, 7 }, /* 6 == 0000 001. */ + { 0x60, 3 }, /* 7 == 011. .... */ + { 0x18, 5 }, /* 8 == 0001 1... */ + { 0x80, 3 }, /* 9 == 100. .... */ + { 0x04, 6 }, /* 10 == 0000 01.. */ + { 0xa0, 3 } /* 11 == 101. .... */ + }, + { /* VLC4 */ + { 0x40, 3 }, /* 0 == 010. .... */ + { 0x80, 1 }, /* 1 == 1... .... */ + { 0x02, 7 }, /* 2 == 0000 001. */ + { 0x10, 4 }, /* 3 == 0001 .... */ + { 0x04, 7 }, /* 4 == 0000 010. */ + { 0x60, 3 }, /* 5 == 011. .... */ + { 0x00, 8 }, /* 6 == 0000 0000 */ + { 0x20, 4 }, /* 7 == 0010 .... */ + { 0x06, 7 }, /* 8 == 0000 011. */ + { 0x30, 4 }, /* 9 == 0011 .... */ + { 0x01, 8 }, /* 10 == 0000 0001 */ + { 0x08, 5 } /* 11 == 0000 1... */ + } + }; + int vlc_table; + unsigned char bits; + unsigned char len; + + int delta_table; + int delta2table; + + typedef int deltatable_t[12]; + const deltatable_t FirstIndexDelta[4] = { + { 1, 1, 1, 1, 1, 0, 0,-1, 2, 1, 0, 0 }, + { 2, 2,-1,-1,-1, 0,-2,-1, 0, 0,-2,-1 }, + {-1, 1, 0, 2, 0, 0, 0, 0,-2, 0, 1, 1 }, + { 0, 1, 0, 1,-2, 0,-1,-1,-2,-1,-2,-2 } + }; + + abs_level_vlc_index_t vlc_select = (abs_level_vlc_index_t)0; + + switch (band) { + case 1: /* LP */ + if (chroma_flag) + vlc_select = DecFirstIndLPChr; + else + vlc_select = DecFirstIndLPLum; + break; + case 2: /* HP */ + if (chroma_flag) + vlc_select = DecFirstIndHPChr; + else + vlc_select = DecFirstIndHPLum; + break; + default: + assert(0); + break; + } + + vlc_table = image->vlc_table[vlc_select].table; + DEBUG(" DECODE_FIRST_INDEX: vlc_select = %s, vlc_table = %d, encode 0x%x\n", + _jxr_vlc_index_name(vlc_select), vlc_table, first_index); + + bits = first_index_vlc[vlc_table][first_index].bits; + len = first_index_vlc[vlc_table][first_index].len; + + DEBUG(" bits/len = 0x%02x/%u\n", bits, len); + + while (len > 0) { + _jxr_wbitstream_uint1(str, (bits&0x80)? 1 : 0); + bits <<= 1; + len -= 1; + } + + delta_table = image->vlc_table[vlc_select].deltatable; + delta2table = image->vlc_table[vlc_select].delta2table; + + assert(delta_table < 4); + assert(delta2table < 4); + assert(first_index < 12); + image->vlc_table[vlc_select].discriminant += FirstIndexDelta[delta_table][first_index]; + image->vlc_table[vlc_select].discriminant2 += FirstIndexDelta[delta2table][first_index]; +} + +static void w_DECODE_INDEX(jxr_image_t image, struct wbitstream*str, + int location, int chroma_flag, int band, int context, + int index_code) +{ + int vlc_select = 0; + int vlc_table; + struct encode_table_s{ + unsigned char bits; + unsigned char len; + }; + + typedef struct encode_table_s index1_table_t[6]; + static const index1_table_t index1_vlc[5] = { + { /* VLC0 */ + { 0x80, 1 }, /* 0 == 1... .... */ + { 0x00, 5 }, /* 1 == 0000 0... */ + { 0x20, 3 }, /* 2 == 001. .... */ + { 0x08, 5 }, /* 3 == 0000 1... */ + { 0x40, 2 }, /* 4 == 01.. .... */ + { 0x10, 4 } /* 5 == 0001 .... */ + }, + { /* VLC1 */ + { 0x40, 2 }, /* 0 == 01.. .... */ + { 0x00, 4 }, /* 1 == 0000 .... */ + { 0x80, 2 }, /* 2 == 10.. .... */ + { 0x10, 4 }, /* 3 == 0001 .... */ + { 0xc0, 2 }, /* 4 == 11.. .... */ + { 0x20, 3 } /* 5 == 001. .... */ + }, + { /* VLC2 */ + { 0x00, 4 }, /* 0 == 0000 .... */ + { 0x10, 4 }, /* 1 == 0001 .... */ + { 0x40, 2 }, /* 2 == 01.. .... */ + { 0x80, 2 }, /* 3 == 10.. .... */ + { 0xc0, 2 }, /* 4 == 11.. .... */ + { 0x20, 3 } /* 5 == 001. .... */ + }, + { /* VLC3 */ + { 0x00, 5 }, /* 0 == 0000 0... */ + { 0x08, 5 }, /* 1 == 0000 1... */ + { 0x40, 2 }, /* 2 == 01.. .... */ + { 0x80, 1 }, /* 3 == 1... .... */ + { 0x10, 4 }, /* 4 == 0001 .... */ + { 0x20, 3 } /* 5 == 001. .... */ + } + }; + unsigned char bits; + unsigned char len; + int vlc_delta; + int vlc_delta2; + + typedef int deltatable_t[6]; + const deltatable_t Index1Delta[3] = { + {-1, 1, 1, 1, 0, 1 }, + {-2, 0, 0, 2, 0, 0 }, + {-1,-1, 0, 1,-2, 0 } + }; + + + switch (band) { + case 1: /* LP */ + if (chroma_flag) + vlc_select = context? DecIndLPChr1 : DecIndLPChr0; + else + vlc_select = context? DecIndLPLum1 : DecIndLPLum0; + break; + case 2: /* HP */ + if (chroma_flag) + vlc_select = context? DecIndHPChr1 : DecIndHPChr0; + else + vlc_select = context? DecIndHPLum1 : DecIndHPLum0; + break; + default: + assert(0); + break; + } + + /* If location>15, then there can't possibly be coefficients + after the next, so only the low bit need be encoded. */ + if (location > 15) { + DEBUG(" DECODE_INDEX: location=%d, index_code=%d\n", location, index_code); + assert(index_code <= 1); + _jxr_wbitstream_uint1(str, index_code); + return; + } + + if (location == 15) { + DEBUG(" DECODE_INDEX: location=%d, index_code=%d\n", location, index_code); + /* Table 61 + * INDEX2 table + * 0 0 + * 2 10 + * 1 110 + * 3 111 + */ + switch (index_code) { + case 0: + _jxr_wbitstream_uint1(str, 0); + break; + case 2: + _jxr_wbitstream_uint2(str, 2); + break; + case 1: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 2); + break; + case 3: + _jxr_wbitstream_uint1(str, 1); + _jxr_wbitstream_uint2(str, 3); + break; + default: + assert(0); + } + return; + } + + vlc_table = image->vlc_table[vlc_select].table; + DEBUG(" DECODE_INDEX: vlc_select = %s, vlc_table = %d chroma_flag=%d, index_code=%d\n", + _jxr_vlc_index_name(vlc_select), vlc_table, chroma_flag, index_code); + + bits = index1_vlc[vlc_table][index_code].bits; + len = index1_vlc[vlc_table][index_code].len; + + DEBUG(" bits/len = 0x%02x/%u\n", bits, len); + + while (len > 0) { + _jxr_wbitstream_uint1(str, (bits&0x80)? 1 : 0); + bits <<= 1; + len -= 1; + } + + vlc_delta = image->vlc_table[vlc_select].deltatable; + vlc_delta2 = image->vlc_table[vlc_select].delta2table; + + image->vlc_table[vlc_select].discriminant += Index1Delta[vlc_delta][index_code]; + image->vlc_table[vlc_select].discriminant2+= Index1Delta[vlc_delta2][index_code]; + + DEBUG(" DECODE_INDEX: deltatable/2 = %d/%d, discriminant/2 becomes %d/%d\n", + vlc_delta, vlc_delta2, + image->vlc_table[vlc_select].discriminant, + image->vlc_table[vlc_select].discriminant2); + +} + +static void w_DECODE_RUN(jxr_image_t image, struct wbitstream*str, int max_run, int run) +{ + static const int remap[15] = {1,2,3,5,7,1,2,3,5,7,1,2,3,4,5}; + static const int run_bin[15] = {-1,-1,-1,-1,2,2,2,1,1,1,1,0,0,0,0}; + static const int run_fixed_len[15] = {0,0,1,1,3,0,0,1,1,2,0,0,0,0,1}; + int index_run_bin; + int run_index; + + assert(run > 0); + if (max_run < 5) { + DEBUG(" DECODE_RUN max_run=%d (<5) run=%d, bitpos=%zu\n", + max_run, run, _jxr_wbitstream_bitpos(str)); + + switch (max_run) { + case 1: + assert(run == 1); + break; + case 2: + assert(run <= 2); + if (run == 2) + _jxr_wbitstream_uint1(str, 0); + else + _jxr_wbitstream_uint1(str, 1); + break; + case 3: + if (run == 1) + _jxr_wbitstream_uint1(str, 1); + else if (run == 2) { + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 1); + } else { + assert(run == 3); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + } + break; + case 4: + if (run == 1) { + _jxr_wbitstream_uint1(str, 1); + } else if (run == 2) { + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 1); + } else if (run == 3) { + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 1); + } else { + assert(run == 4); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint1(str, 0); + } + } + return; + } + + assert(max_run < 15); + index_run_bin = 5*run_bin[max_run]; + + run_index = 0; + for (run_index = 0; run_index < 5; run_index += 1) { + int index = run_index + index_run_bin; + int use_run; + int fixed; + int range; + int run_fixed; + + if (index < 0) + continue; + + use_run = remap[index]; + if (use_run > run) + continue; + + fixed = run_fixed_len[index]; + range = 1 << fixed; + if (run >= (use_run + range)) + continue; + + /* RUN_INDEX */ + switch(run_index) { + case 0: + _jxr_wbitstream_uint1(str, 1); + break; + case 1: + _jxr_wbitstream_uint2(str, 1); + break; + case 2: + _jxr_wbitstream_uint1(str, 0); + _jxr_wbitstream_uint2(str, 1); + break; + case 3: + _jxr_wbitstream_uint4(str, 0); + break; + case 4: + _jxr_wbitstream_uint4(str, 1); + break; + } + + run_fixed = 0; + if (fixed > 0) { + run_fixed = run - use_run; + assert(run_fixed >= 0 && run_fixed < (1<<fixed)); + _jxr_wbitstream_uintN(str, run_fixed, fixed); + } + + DEBUG(" DECODE_RUN max_run=%d run=%d+%d = %d, bitpos=%zu\n", + max_run, use_run, run_fixed, run, _jxr_wbitstream_bitpos(str)); + + return; + } + assert(0); +} + +static int w_DECODE_BLOCK_ADAPTIVE(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned mx, + int cbp_flag, int chroma_flag, + int channel, int block, int mbhp_pred_mode, + unsigned model_bits) +{ + int values[16]; + int values2[16]; + int idx; + int coeffs[32]; + int num_nonzero; + + /* If the CBP flag is off, then there isn't really anything to + encode here. */ + if (cbp_flag == 0) + return 0; + + values[0] = 0; + DEBUG(" HP val[tx=%d, mx=%d, block=%d] ==", tx, mx, block); + for (idx = 0 ; idx < 15 ; idx += 1) { + values[1+idx] = MACROBLK_CUR_HP(image,channel,tx,mx,block,idx); + /* Shift out the model bits. Be careful to note that the + value is processed as sign/magnitude, so do the + shifting to the abs of the value and invert it back + if nesessary. */ + if (values[1+idx] >= 0) + values[1+idx] >>= model_bits; + else + values[1+idx] = - ( (-values[1+idx]) >> model_bits ); + DEBUG(" 0x%x", values[1+idx]); + } + DEBUG("\n"); + + values2[0] = 0; + AdaptiveHPPermute(image, values2, values, mbhp_pred_mode); +#if defined(DETAILED_DEBUG) + { + int k; + DEBUG(" adapted hor scan order (MBHPMode=%d) ==", mbhp_pred_mode); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_hor_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" adapted hor scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_hor_scantotals[k]); + } + DEBUG("\n"); + DEBUG(" adapted ver scan order (MBHPMode=%d) ==", mbhp_pred_mode); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_ver_scanorder[k]); + } + DEBUG("\n"); + DEBUG(" adapted ver scan totals =="); + for (k = 0 ; k<15; k+=1) { + DEBUG(" %2d", image->hipass_ver_scantotals[k]); + } + DEBUG("\n"); + } +#endif + + num_nonzero = RunLengthEncode(image, coeffs, values2); + + w_DECODE_BLOCK(image, str, 2, chroma_flag, coeffs, num_nonzero); + + return num_nonzero;; +} + +/* +* $Log: w_emit.c,v $ +* Revision 1.28 2009/09/16 12:00:00 microsoft +* Reference Software v1.8 updates. +* +* Revision 1.27 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.26 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.25 2008/03/24 18:06:56 steve +* Imrpove DEBUG messages around quantization. +* +* Revision 1.24 2008/03/21 18:05:53 steve +* Proper CMYK formatting on input. +* +* Revision 1.23 2008/03/13 21:23:27 steve +* Add pipeline step for YUV420. +* +* Revision 1.22 2008/03/13 00:30:56 steve +* Force SCALING on if using a subsampled color format. +* +* Revision 1.21 2008/03/11 22:12:49 steve +* Encode YUV422 through DC. +* +* Revision 1.20 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.19 2008/03/05 04:04:30 steve +* Clarify constraints on USE_DC_QP in image plane header. +* +* Revision 1.18 2008/03/05 00:31:18 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.17 2008/03/02 19:56:27 steve +* Infrastructure to read write BD16 files. +* +* Revision 1.16 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.15 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.14 2008/02/22 23:01:33 steve +* Compress macroblock HP CBP packets. +* +* Revision 1.13 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.12 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.11 2008/01/07 16:19:10 steve +* Properly configure TRIM_FLEXBITS_FLAG bit. +* +* Revision 1.10 2008/01/04 17:07:36 steve +* API interface for setting QP values. +* +* Revision 1.9 2007/12/13 18:01:09 steve +* Stubs for HP encoding. +* +* Revision 1.8 2007/12/07 01:20:34 steve +* Fix adapt not adapting on line ends. +* +* Revision 1.7 2007/12/05 18:14:19 steve +* hard-code LOG_WORD_FLAG true. +* +* Revision 1.6 2007/12/04 22:06:10 steve +* Infrastructure for encoding LP. +* +* Revision 1.5 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.4 2007/11/26 01:47:16 steve +* Add copyright notices per MS request. +* +* Revision 1.3 2007/11/08 19:38:38 steve +* Get stub DCONLY compression to work. +* +* Revision 1.2 2007/11/08 02:52:33 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.1 2007/06/06 17:19:13 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/w_strip.c b/jpegxr/w_strip.c new file mode 100644 index 000000000..abd8ca5ba --- /dev/null +++ b/jpegxr/w_strip.c @@ -0,0 +1,3348 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: w_strip.c,v 1.47 2008/03/24 18:06:56 steve Exp $") +#else +#ident "$Id: w_strip.c,v 1.47 2008/03/24 18:06:56 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <limits.h> +# include <assert.h> + +# define FILTERED_YUV_SAMPLE 1 + +static void w_rotate_mb_strip(jxr_image_t image); +static void collect_and_scale_up4(jxr_image_t image, int ty); +static void scale_and_shuffle_up3(jxr_image_t image); +static void first_prefilter_up2(jxr_image_t image, int ty); +static void PCT_stage2_up1(jxr_image_t image, int ch, int ty); +static void second_prefilter_up1(jxr_image_t image, int ty); +static void PCT_stage1_up2(jxr_image_t image, int ch, int ty); +static void w_predict_up1_dclp(jxr_image_t image, int tx, int ty, int mx); +static int w_calculate_mbhp_mode_up1(jxr_image_t image, int tx, int mx); +static void w_predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); +static void w_predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode); +static void w_predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode); +static void calculate_hpcbp_up1(jxr_image_t image, int tx, int ty, int mx); +static void w_predict_up1_hp(jxr_image_t image, int ch, int tx, int mx, int mbhp_pred_mode); +static void w_PredCBP(jxr_image_t image, unsigned tx, unsigned ty, unsigned mx); +static void wflush_to_tile_buffer(jxr_image_t image, int my); +static void wflush_collect_mb_strip_data(jxr_image_t image, int my); +static void _jxr_w_store_hpcbp_state(jxr_image_t image, int tx); +static void _jxr_w_load_hpcbp_state(jxr_image_t image, int tx); + +static unsigned char w_guess_dc_quant(jxr_image_t image, int ch, + unsigned tx, unsigned ty) +{ + struct jxr_tile_qp*cur; + + if (image->dc_frame_uniform) + return image->dc_quant_ch[ch]; + + cur = GET_TILE_QUANT(image,tx,ty); + + if (ch == 0) + return cur->channel[0].dc_qp; + + switch (cur->component_mode) { + case JXR_CM_UNIFORM: + return cur->channel[0].dc_qp; + case JXR_CM_SEPARATE: + return cur->channel[1].dc_qp; + case JXR_CM_INDEPENDENT: + return cur->channel[ch].dc_qp; + default: + assert(0); + return 0; + } +} + +unsigned char _jxr_select_lp_index(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + struct jxr_tile_qp*cur; + unsigned mxy; + unsigned lp_index; + /* If this is frame uniform LP QP, then implicitly the QP + index is always zero. */ + if (image->lp_frame_uniform) + return 0; + + /* Otherwise we have the more complicated case that the LP QP + index may vary per MB. */ + cur = GET_TILE_QUANT(image,tx,ty); + if (cur->lp_map == 0) + return 0; + + mxy = my*jxr_get_TILE_WIDTH(image, tx) + mx; + + lp_index = cur->lp_map[mxy]; + assert(lp_index < cur->channel[0].num_lp || lp_index==0); + + return lp_index; +} + +static unsigned char w_guess_lp_quant(jxr_image_t image, int ch, + unsigned tx, unsigned ty, unsigned mx, unsigned my) +{ + unsigned idx; + struct jxr_tile_qp*cur; + + if (image->lp_frame_uniform) + return image->lp_quant_ch[ch][0]; + + idx = _jxr_select_lp_index(image, tx, ty, mx, my); + cur = GET_TILE_QUANT(image,tx,ty); + + if (ch == 0) + return cur->channel[0].lp_qp[idx]; + + switch (cur->component_mode) { + case JXR_CM_UNIFORM: + return cur->channel[0].lp_qp[idx]; + case JXR_CM_SEPARATE: + return cur->channel[1].lp_qp[idx]; + case JXR_CM_INDEPENDENT: + return cur->channel[ch].lp_qp[idx]; + default: + assert(0); + return 0; + } +} + +unsigned char _jxr_select_hp_index(jxr_image_t image, unsigned tx, unsigned ty, + unsigned mx, unsigned my) +{ + unsigned mxy; + unsigned hp_index; + struct jxr_tile_qp*cur; + + if (image->hp_frame_uniform) + return 0; + + cur = GET_TILE_QUANT(image,tx,ty); + /* If there is no actual map, then assume all indices in the + tile are zero. */ + if (cur->hp_map == 0) + return 0; + + mxy = my*jxr_get_TILE_WIDTH(image, tx) + mx; + + hp_index = cur->hp_map[mxy]; + assert(hp_index < cur->channel[0].num_hp || hp_index == 0); + + return hp_index; +} + +static unsigned char w_guess_hp_quant(jxr_image_t image, int ch, + unsigned tx, unsigned ty, + int mx, int my) +{ + unsigned idx; + struct jxr_tile_qp*cur; + + if (image->hp_frame_uniform) + return image->hp_quant_ch[ch][0]; + + idx = _jxr_select_hp_index(image, tx, ty, mx, my); + cur = GET_TILE_QUANT(image,tx,ty); + + if (ch == 0) + return cur->channel[0].hp_qp[idx]; + + switch (cur->component_mode) { + case JXR_CM_UNIFORM: + return cur->channel[0].hp_qp[idx]; + case JXR_CM_SEPARATE: + return cur->channel[1].hp_qp[idx]; + case JXR_CM_INDEPENDENT: + return cur->channel[ch].hp_qp[idx]; + default: + assert(0); + return 0; + } +} + +static int quantize_dc(int value, int quant) +{ + int sign = 1; + int offset; + if (value < 0) { + sign = -1; + value = -value; + } + + offset = quant >> 1; + + return sign * (value + offset)/quant; +} + +static int quantize_lphp(int value, int quant) +{ + int sign = 1; + int offset; + if (value < 0) { + sign = -1; + value = -value; + } + + offset = (quant*3 + 1) >> 3; + + return sign * (value + offset)/quant; +} + +static void dump_all_strips(jxr_image_t image) +{ +#if defined(DETAILED_DEBUG) && 0 + int mx; + int ch; +#if 1 + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int jdx; + DEBUG("up3: mx=%3d ch=%d:", mx, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%8 == 0 && jdx != 0) + DEBUG("\n%*s", 17, ""); + DEBUG(" %08x", image->strip[ch].up3[mx].data[jdx]); + } + DEBUG("\n"); + } + } +#endif +#if 0 + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int jdx; + DEBUG("up2: mx=%3d ch=%d:", mx, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%8 == 0 && jdx != 0) + DEBUG("\n%*s", 17, ""); + DEBUG(" %08x", image->strip[ch].up2[mx].data[jdx]); + } + DEBUG("\n"); + } + } +#endif +#if 0 + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int jdx; + DEBUG("up1: mx=%3d ch=%d:", mx, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%8 == 0 && jdx != 0) + DEBUG("\n%*s", 17, ""); + DEBUG(" %08x", image->strip[ch].up1[mx].data[jdx]); + } + DEBUG("\n"); + } + } +#endif +#endif +} + +/* +* This function is use to prepare a strip of MB data for use by the +* encoder. After this call is complete, the "my" strip with tx/ty is +* ready in the CUR strip. The data is filled into the pipeline +* starting with UP3, where it is processed and worked down to +* CUR. The CUR strip is then processed and formatted. +* +* On entry to this function, the CUR strip is no longer needed, so +* may immediately be tossed. +*/ +static void wflush_process_strip(jxr_image_t image, int ty) +{ + int ch; + const int height = EXTENDED_HEIGHT_BLOCKS(image); + int cur_row; + + DEBUG("wflush_process_strip: image->cur_my = %d\n", image->cur_my); + dump_all_strips(image); + + cur_row = image->tile_row_position[ty] + image->cur_my; + + /* Finish up scaling of the image data, and shuffle it to the + internal sub-block format. */ + if (cur_row >= -3 && cur_row < (height-3)) { + scale_and_shuffle_up3(image); + } + + /* Transform on up2 data. At this point, the up2 and up3 + strips are lines N (up2) and N+1 (up3) of scaled image + data. After this section is done, the image data in up2 + becomes DC-HP data. */ + if (cur_row >= -2 && cur_row < (height-2)) { + + + /* If overlap filtering is enabled, then do it. The + filter assumes that this strip (up2) and the next + (up3) are collected and scaled. The filter looks + ahead to up3 for bottom context. */ + if (OVERLAP_INFO(image) != 0) + first_prefilter_up2(image,ty); + + /* Transform up2 data to DC-HP coefficients. */ + for (ch = 0; ch < image->num_channels ; ch += 1) + PCT_stage1_up2(image, ch, ty); + + /* read lwf test flag into image container */ + if (image->lwf_test == 0) + image->lwf_test = _jxr_read_lwf_test_flag(); + } + + /* Second tranform on up1 data. The DC-HP data becomes DC-LP-HP. */ + if (cur_row >= -1 && cur_row < (height-1)) { + + /* If intermediate overlap filtering is enabled, then do + it. The filter assumes that this strip (up1) and the + next (up2) have already been PCT processed. */ + if (OVERLAP_INFO(image) == 2) + second_prefilter_up1(image,ty); + + /* PCT_level1_cur */ + for (ch = 0; ch < image->num_channels ; ch += 1) + PCT_stage2_up1(image, ch, ty); + + /* read lwf test flag into image container */ + if (image->lwf_test == 0) + image->lwf_test = _jxr_read_lwf_test_flag(); + } + + if (cur_row >= -1 && cur_row < (height-1)) { + /* DC-LP prediction on the CURUP1strip. At this point CUR an UP1 + are PCT transformed, and CUR is predicted. After this, UP1 + will also be predicted with pred_dclp members filled in + with saved PCT coefficients. */ + int tx; + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + /* Calculate the MB HP prediction mode. This uses + only local information, namely the LP values. */ + int mbhp_pred_mode = w_calculate_mbhp_mode_up1(image, tx, mx); + assert(mbhp_pred_mode < 4); + + MACROBLK_UP1(image,0,tx,mx).mbhp_pred_mode = mbhp_pred_mode; + + /* Run DCLP prediction. This assumes that the + previous (CUR) strip has already been + predicted, and uses some predict values from + that strip. */ + w_predict_up1_dclp(image, tx, ty, mx); + } + } + } + + if (cur_row >= -1 && cur_row < (height-1)) { + int use_num_channels; + int tx; + DEBUG("wflush_process_string: Calculate HP CBP for my=%d\n", cur_row+1); + + /* Perform HP prediction. */ + use_num_channels = image->num_channels; + if (image->use_clr_fmt == 1/*YUV420*/ || image->use_clr_fmt == 2/*YUV422*/) + use_num_channels = 1; + + image->model_hp; + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + if (image->tile_columns > 1) + _jxr_w_load_hpcbp_state(image, tx); + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int mbhp_pred_mode = MACROBLK_UP1(image,0,tx,mx).mbhp_pred_mode; + int idx; + for (idx = 0 ; idx < use_num_channels ; idx += 1) + w_predict_up1_hp(image, idx, tx, mx, mbhp_pred_mode); + + /* Also calculate and predict HPCBP in up1. */ + calculate_hpcbp_up1(image, tx, ty, mx); + w_PredCBP(image, tx, ty, mx); + } + if (image->tile_columns > 1) + _jxr_w_store_hpcbp_state(image, tx); + } + } + + DEBUG("wflush_process_strip done: cur_row = %d\n", cur_row); +} + +/* since hpcbp is processed at each row, need to save context for each tile column */ +void _jxr_w_load_hpcbp_state(jxr_image_t image, int tx) +{ + unsigned idx; + for (idx = 0 ; idx < 2 ; idx += 1) { + image->model_hp.bits[idx] = image->model_hp_buffer[tx].bits[idx]; + image->model_hp.state[idx] = image->model_hp_buffer[tx].state[idx]; + + image->hp_cbp_model.state[idx] = image->hp_cbp_model_buffer[tx].state[idx]; + image->hp_cbp_model.count0[idx] = image->hp_cbp_model_buffer[tx].count0[idx]; + image->hp_cbp_model.count1[idx] = image->hp_cbp_model_buffer[tx].count1[idx]; + } +} + +void _jxr_w_store_hpcbp_state(jxr_image_t image, int tx) +{ + unsigned idx; + for (idx = 0 ; idx < 2 ; idx += 1) { + image->model_hp_buffer[tx].bits[idx] = image->model_hp.bits[idx]; + image->model_hp_buffer[tx].state[idx] = image->model_hp.state[idx]; + + image->hp_cbp_model_buffer[tx].state[idx] = image->hp_cbp_model.state[idx]; + image->hp_cbp_model_buffer[tx].count0[idx] = image->hp_cbp_model.count0[idx]; + image->hp_cbp_model_buffer[tx].count1[idx] = image->hp_cbp_model.count1[idx]; + } +} + +void _jxr_wflush_mb_strip(jxr_image_t image, int tx, int ty, int my, int read_new) +{ + unsigned ty_offset = 0; + DEBUG("wflush_mb_strip: cur_my=%d, tile-x/y=%d/%d, my=%d\n", image->cur_my, tx, ty, my); + + if (FREQUENCY_MODE_CODESTREAM_FLAG(image)) + ty_offset = image->tile_row_position[ty]; + + if (my == 0 && (image->cur_my >= 0)) { + /* reset the current row value for a new tile */ + image->cur_my = my - 1; + + if (ALPHACHANNEL_FLAG(image)) + image->alpha->cur_my = my - 1; + } + + if ((tx == 0) && (read_new == 1)) { + /* Process entire strip, then store it */ + while (image->cur_my < my) { + const int height = EXTENDED_HEIGHT_BLOCKS(image); + int cur_row; + + w_rotate_mb_strip(image); + image->cur_my += 1; + cur_row = image->tile_row_position[ty] + image->cur_my; + if (ALPHACHANNEL_FLAG(image)) { + w_rotate_mb_strip(image->alpha); + image->alpha->cur_my += 1; + } + + /* Load up4 with new image data. */ + if (cur_row >= -4 && cur_row < (height-4)) { + collect_and_scale_up4(image, ty); + } + + wflush_process_strip(image, ty); + if ((INDEXTABLE_PRESENT_FLAG(image)) && (image->cur_my >= 0)) { + /* save processed row */ + wflush_to_tile_buffer(image, image->cur_my + ty_offset); + } + if (ALPHACHANNEL_FLAG(image)) { + wflush_process_strip(image->alpha, ty); + if ((INDEXTABLE_PRESENT_FLAG(image->alpha)) && (image->alpha->cur_my >= 0)) { + /* save processed row */ + wflush_to_tile_buffer(image->alpha, image->alpha->cur_my + ty_offset); + } + } + } + } + else { + /* load a row of mb data as appropriate */ + image->cur_my += 1; + wflush_collect_mb_strip_data(image, image->cur_my + ty_offset); + + if (ALPHACHANNEL_FLAG(image)) { + image->alpha->cur_my += 1; + wflush_collect_mb_strip_data(image->alpha, image->alpha->cur_my + ty_offset); + } + } +} + +/* +* The tile_row_buffer holds flushed mb data in image raster order, +* along with other per-mb data. This is in support of tiled SPATIAL processing. +* This function saves mb row information for all rows of the the current tile row +*/ +static void wflush_to_tile_buffer(jxr_image_t image, int my) +{ + int format_scale = 256; + int tx; + DEBUG("wflush_mb_strip: wflush_to_tile_buffer my=%d\n", my); + + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0 ; mx < (int) image->tile_column_width[tx] ; mx += 1) { + int off; + int ch; + DEBUG("wflush_mb_strip: wflush_to_tile_buffer tx=%d, mx=%d, CUR=0x%08x UP1=0x%08x, UP2=0x%08x, UP3=0x%08x, LP_QUANT=%d\n", + tx, mx, MACROBLK_CUR(image,0,tx,mx).data[0], + MACROBLK_UP1(image,0,tx,mx).data[0], + MACROBLK_UP2(image,0,tx,mx).data[0], + MACROBLK_UP3(image,0,tx,mx).data[0], + MACROBLK_CUR_LP_QUANT(image,0,tx,mx)); + + off = my * EXTENDED_WIDTH_BLOCKS(image) + image->tile_column_position[tx] + mx; + for (ch = 0; ch < image->num_channels; ch += 1) { + int count; + int idx; + struct macroblock_s*mb = image->mb_row_buffer[ch] + off; + mb->lp_quant = MACROBLK_CUR_LP_QUANT(image,ch,tx,mx); + mb->hp_quant = MACROBLK_CUR(image,ch,tx,mx).hp_quant; + mb->hp_cbp = MACROBLK_CUR(image,ch,tx,mx).hp_cbp; + mb->hp_diff_cbp = MACROBLK_CUR(image,ch,tx,mx).hp_diff_cbp; + mb->mbhp_pred_mode = MACROBLK_CUR(image,ch,tx,mx).mbhp_pred_mode; + mb->hp_model_bits[0] = MACROBLK_CUR(image,ch,tx,mx).hp_model_bits[0]; + mb->hp_model_bits[1] = MACROBLK_CUR(image,ch,tx,mx).hp_model_bits[1]; + count = (ch==0)? 256 : format_scale; + for (idx = 0 ; idx < count ; idx += 1) + mb->data[idx] = MACROBLK_CUR(image,ch,tx,mx).data[idx]; + for (idx = 0 ; idx < 7 ; idx += 1) + mb->pred_dclp[idx] = MACROBLK_CUR(image,ch,tx,mx).pred_dclp[idx]; + } + } + } +} + +/* +* Recover a strip of data from all but the last column of data. Skip +* the last column because this function is called while the last +* column is being processed. +* This function loads mb row information for all rows of the the current tile row +*/ +static void wflush_collect_mb_strip_data(jxr_image_t image, int my) +{ + int format_scale = 256; + int tx; + DEBUG("wflush_mb_strip: wflush_collect_mb_strip_data my=%d\n", my); + + if (image->use_clr_fmt == 2 /* YUV422 */) { + format_scale = 16 + 8*15; + } else if (image->use_clr_fmt == 1 /* YUV420 */) { + format_scale = 16 + 4*15; + } + + for (tx = 0; tx < (int) image->tile_columns ; tx += 1) { + int mx; + for (mx = 0; mx < (int) image->tile_column_width[tx]; mx += 1) { + int off = my * EXTENDED_WIDTH_BLOCKS(image) + image->tile_column_position[tx] + mx; + int ch; + for (ch = 0; ch < image->num_channels; ch += 1) { + struct macroblock_s*mb = image->mb_row_buffer[ch] + off; + int count; + int idx; + MACROBLK_CUR_LP_QUANT(image,ch,tx,mx) = mb->lp_quant; + MACROBLK_CUR(image,ch,tx,mx).hp_quant = mb->hp_quant; + MACROBLK_CUR(image,ch,tx,mx).hp_cbp = mb->hp_cbp; + MACROBLK_CUR(image,ch,tx,mx).hp_diff_cbp = mb->hp_diff_cbp; + MACROBLK_CUR(image,ch,tx,mx).mbhp_pred_mode = mb->mbhp_pred_mode; + MACROBLK_CUR(image,ch,tx,mx).hp_model_bits[0] = mb->hp_model_bits[0]; + MACROBLK_CUR(image,ch,tx,mx).hp_model_bits[1] = mb->hp_model_bits[1]; + count = (ch==0)? 256 : format_scale; + for (idx = 0 ; idx < count; idx += 1) + MACROBLK_CUR(image,ch,tx,mx).data[idx] = mb->data[idx]; + for (idx = 0 ; idx < 7 ; idx += 1) + MACROBLK_CUR(image,ch,tx,mx).pred_dclp[idx] = mb->pred_dclp[idx]; + } + DEBUG("wflush_mb_strip: wflush_collect_mb_strip_data tx=%d, mx=%d, CUR=0x%08x UP1=0x%08x, UP2=0x%08x, UP3=0x%08x lp_quant=%d\n", + tx, mx, MACROBLK_CUR(image,0,tx,mx).data[0], + MACROBLK_UP1(image,0,tx,mx).data[0], + MACROBLK_UP2(image,0,tx,mx).data[0], + MACROBLK_UP3(image,0,tx,mx).data[0], + MACROBLK_CUR_LP_QUANT(image,0,tx,mx)); + } + } +} + +static void w_rotate_mb_strip(jxr_image_t image) +{ + int ch; + + _jxr_clear_strip_cur(image); + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + struct macroblock_s*tmp = image->strip[ch].cur; + image->strip[ch].cur = image->strip[ch].up1; + image->strip[ch].up1 = image->strip[ch].up2; + image->strip[ch].up2 = image->strip[ch].up3; + image->strip[ch].up3 = image->strip[ch].up4; + image->strip[ch].up4 = tmp; + } +} + +/* +* Transform RGB input data to YUV444 data. Do the transform in place, +* assuming the input channels are R, G and B in order. +*/ +static void rgb_to_yuv444_up4(jxr_image_t image) +{ + unsigned mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int*dataR = MACROBLK_UP4(image,0,0,mx).data; + int*dataG = MACROBLK_UP4(image,1,0,mx).data; + int*dataB = MACROBLK_UP4(image,2,0,mx).data; + int idx; + for (idx = 0 ; idx < 16*16 ; idx += 1) { + const int R = dataR[idx]; + const int G = dataG[idx]; + const int B = dataB[idx]; + const int V = B - R; + const int tmp = R - G + _jxr_ceil_div2(V); + const int Y = G + _jxr_floor_div2(tmp); + const int U = -tmp; + dataR[idx] = Y; + dataG[idx] = U; + dataB[idx] = V; + } + } +} + +static void cmyk_to_yuvk_up4(jxr_image_t image) +{ + unsigned mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int*datac = MACROBLK_UP4(image,0,0,mx).data; + int*datam = MACROBLK_UP4(image,1,0,mx).data; + int*datay = MACROBLK_UP4(image,2,0,mx).data; + int*datak = MACROBLK_UP4(image,3,0,mx).data; + int idx; + for (idx = 0 ; idx < 16*16 ; idx += 1) { + const int c = datac[idx]; + const int m = datam[idx]; + const int y = datay[idx]; + const int k = datak[idx]; + const int V = c - y; + const int U = c - m - _jxr_floor_div2(V); + const int Y = k - m - _jxr_floor_div2(U); + const int K = k - _jxr_floor_div2(Y); + datac[idx] = Y; + datam[idx] = U; + datay[idx] = V; + datak[idx] = K; + } + } +} + +/* +* Transform YUV444 input data to YUV422 by subsampling the UV planes +* horizontally. +*/ +#if defined(FILTERED_YUV_SAMPLE) +static void yuv444_to_yuv422_up4(jxr_image_t image) +{ + int ch; + int px, py; + + int*buf[16]; + for (py = 0 ; py < 16 ; py += 1) + buf[py] = (int*)calloc(8*EXTENDED_WIDTH_BLOCKS(image), sizeof(int)); + + for (ch = 1 ; ch < 3 ; ch += 1) { + unsigned mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int*prev = mx>0? MACROBLK_UP4(image,ch,0,mx-1).data : 0; + int*data = MACROBLK_UP4(image,ch,0,mx).data; + int*next = (mx+1)<EXTENDED_WIDTH_BLOCKS(image)? MACROBLK_UP4(image,ch,0,mx+1).data : 0; + + for (py = 0 ; py < 16 ; py += 1) { + int*bp = buf[py]+8*mx; + int*src = data + 16*py; + if (prev == 0) { + bp[0] = 2*src[2] + 8*src[1] + 6*src[0] + 8; + } else { + int*tmp = prev + 16*py; + bp[0] = 1*tmp[14] + 4*tmp[15] + 6*src[0] + 4*src[1] + 1*src[2] + 8; + } + + for (px = 2 ; px < 14 ; px += 2) { + bp[px/2] = 1*src[px-2] + 4*src[px-1] + 6*src[px] + 4*src[px+1] + 1*src[px+2] + 8; + } + + if (next==0) { + bp[7] = 1*src[12] + 4*src[13] + 6*src[14] + 4*src[15] + 1*src[14] + 8; + } else { + int*tmp = next + 16*py; + bp[7] = 1*src[12] + 4*src[13] + 6*src[14] + 4*src[15] + 1*tmp[0] + 8; + } + } + } + + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int*data = MACROBLK_UP4(image,ch,0,mx).data; + for (py = 0 ; py < 16 ; py += 1) { + int*bp = buf[py] + 8*mx; + int*dst = data+8*py; + for (px = 0 ; px < 8 ; px += 1) + dst[px] = bp[px] >> 4; + } + } + } + + for (py = 0 ; py < 16 ; py += 1) + free(buf[py]); +} + +static void yuv422_to_yuv420_up3(jxr_image_t image) +{ + int my = image->cur_my + 3; + + int ch; + assert(my >= 0); + for (ch = 1 ; ch < 3 ; ch += 1) { + unsigned mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image); mx += 1) { + int*data = MACROBLK_UP3(image,ch,0,mx).data; + /* Save the unreduced data to allow for overlapping */ + int*dataX = data + 128; + int idx; + int px, py; + for (idx = 0 ; idx < 128 ; idx += 1) + dataX[idx] = data[idx]; + + + /* First, handle py==0 */ + if (my == 0) { + int*next1 = data+1*8; + int*next2 = data+2*8; + for (px = 0 ; px < 8 ; px += 1) { + int val = 2*next2[px] + 8*next1[px] + 6*data[px] + 8; + data[px] = val >> 4; + } + } else { + int*prev2 = MACROBLK_UP2(image,ch,0,mx).data + 128 + 14*8; + int*prev1 = MACROBLK_UP2(image,ch,0,mx).data + 128 + 15*8; + int*cur = dataX+0*8; + int*next1 = dataX+1*8; + int*next2 = dataX+2*8; + for (px = 0 ; px < 8 ; px += 1) { + int val = 1*next2[px] + 4*next1[px] + 6*cur[px] + 4*prev1[px] + 1*prev2[px] +8; + data[px] = val >> 4; + } + } + + /* py = 1-6 */ + for (py = 2 ; py < 14 ; py += 2) { + int*prev2 = dataX + 8*(py-2); + int*prev1 = dataX + 8*(py-1); + int*cur = dataX + 8*(py+0); + int*next1 = dataX + 8*(py+1); + int*next2 = dataX + 8*(py+2); + for (px = 0 ; px < 8 ; px += 1) { + int val = 1*next2[px] + 4*next1[px] + 6*cur[px] + 4*prev1[px] + 1*prev2[px] +8; + data[px + 8*(py/2)] = val >> 4; + } + } + + /* py == 7 */ + if ((my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + int*prev2 = dataX + 8*(14-2); + int*prev1 = dataX + 8*(14-1); + int*cur = dataX + 8*(14+0); + int*next1 = dataX + 8*(14+1); + int*next2 = MACROBLK_UP4(image,ch,0,mx).data + 0*8; + for (px = 0 ; px < 8 ; px += 1) { + int val = 1*next2[px] + 4*next1[px] + 6*cur[px] + 4*prev1[px] + 1*prev2[px] +8; + data[px + 8*(py/2)] = val >> 4; + } + } else { + int*prev2 = dataX + 8*(14-2); + int*prev1 = dataX + 8*(14-1); + int*cur = dataX + 8*(14+0); + int*next1 = dataX + 8*(14+1); + int*next2 = dataX + 8*(14+0); + for (px = 0 ; px < 8 ; px += 1) { + int val = 1*next2[px] + 4*next1[px] + 6*cur[px] + 4*prev1[px] + 1*prev2[px] +8; + data[px + 8*(py/2)] = val >> 4; + } + } + } + } +} + +#else + +/* +* These are simple-minded subsamples for convertion YUV444 to YUV42x. +*/ +static void yuv444_to_yuv422_up4(jxr_image_t image) +{ + int mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image); mx += 1) { + int ch; + for (ch = 1 ; ch < 3 ; ch += 1) { + int*data = MACROBLK_UP4(image,ch,0,mx).data; + int px, py; + for (py = 0 ; py < 16 ; py += 1) { + int*src = data + 16*py; + int*dst = data + 8*py; + for (px = 0 ; px < 16 ; px += 2) { + dst[px/2] = src[px+0]; + } + } + } + } +} + +static void yuv422_to_yuv420_up3(jxr_image_t image) +{ + int mx; + for (mx = 0 ; mx < EXTENDED_WIDTH_BLOCKS(image); mx += 1) { + int ch; + for (ch = 1 ; ch < 3 ; ch += 1) { + int*data = MACROBLK_UP3(image,ch,0,mx).data; + int px, py; + for (py = 0 ; py < 16 ; py += 2) { + int*src = data + 8*py; + int*dst = data + 8*py/2; + for (px = 0 ; px < 8 ; px += 1) { + dst[px] = src[px]; + } + } + } + } +} +#endif + +/* +* Shuffle a set of values that are in a single 16x16 raster block to +* 16 4x4 blocks. The 4x4 blocks are the units that the PCT works on. +*/ +static void block_shuffle444(int*data) +{ + int tmp[256]; + + int idx; + for (idx = 0 ; idx < 256 ; idx += 4) { + int blk = idx/16; + int mbx = blk%4; + int mby = blk/4; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*4*mby + 4*mbx + 16*py; + tmp[idx+0] = data[ptr+0]; + tmp[idx+1] = data[ptr+1]; + tmp[idx+2] = data[ptr+2]; + tmp[idx+3] = data[ptr+3]; + } + + for (idx = 0 ; idx < 256 ; idx += 1) + data[idx] = tmp[idx]; +} + +static void block_shuffle422(int*data) +{ + int tmp[128]; + + int idx; + for (idx = 0 ; idx < 128 ; idx += 4) { + int blk = idx/16; + int mbx = blk%2; + int mby = blk/2; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*2*mby + 4*mbx + 8*py; + tmp[idx+0] = data[ptr+0]; + tmp[idx+1] = data[ptr+1]; + tmp[idx+2] = data[ptr+2]; + tmp[idx+3] = data[ptr+3]; + } + + for (idx = 0 ; idx < 128 ; idx += 1) + data[idx] = tmp[idx]; +} + +static void block_shuffle420(int*data) +{ + int tmp[64]; + + int idx; + for (idx = 0 ; idx < 64 ; idx += 4) { + int blk = idx/16; + int mbx = blk%2; + int mby = blk/2; + int pix = idx%16; + int py = pix/4; + + int ptr = 16*2*mby + 4*mbx + 8*py; + tmp[idx+0] = data[ptr+0]; + tmp[idx+1] = data[ptr+1]; + tmp[idx+2] = data[ptr+2]; + tmp[idx+3] = data[ptr+3]; + } + + for (idx = 0 ; idx < 64 ; idx += 1) + data[idx] = tmp[idx]; +} + +static void collect_and_scale_up4(jxr_image_t image, int ty) +{ + int scale = image->scaled_flag? 3 : 0; + int bias; + int round; + int shift_bits = image->shift_bits; + int my; + int mx; + int ch; + int num_channels; + + if (image->output_clr_fmt == JXR_OCF_RGBE) { + bias = 0; + round = image->scaled_flag? 3 : 0; + } + else { + switch (SOURCE_BITDEPTH(image)) { + case 0: /* BD1WHITE1 */ + case 15: /* BD1BLACK1 */ + bias = 0; + round = image->scaled_flag? 4 : 0; + break; + case 1: /* BD8 */ + bias = 1 << 7; + round = image->scaled_flag? 3 : 0; + break; + case 2: /* BD16 */ + bias = 1 << 15; + round = image->scaled_flag? 4 : 0; + break; + case 3: /* BD16S */ + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + case 4: /* BD16F */ + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + case 6: /* BD32S */ + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + case 7: /* BD32F */ + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + case 8: /* BD5 */ + bias = 1 << 4; + round = image->scaled_flag? 3 : 0; + break; + case 9: /* BD10 */ + bias = 1 << 9; + round = image->scaled_flag? 3 : 0; + break; + case 10: /* BD565 */ + bias = 1 << 5; + round = image->scaled_flag? 3 : 0; + break; + default: /* RESERVED */ + fprintf(stderr, "XXXX Don't know how to scale bit depth %d?\n", SOURCE_BITDEPTH(image)); + bias = 0; + round = image->scaled_flag? 3 : 0; + break; + } + } + + DEBUG("scale_and_emit_top: scale=%d, bias=%d, round=%d, shift_bits=%d\n", + scale, bias, round, shift_bits); + + assert(image->num_channels > 0); + + /* This function operates on a whole image (not tile) basis */ + my = image->cur_my + image->tile_row_position[ty] + 4; + DEBUG("collect_and_scale_up4: Collect strip %d\n", my); + + num_channels = image->num_channels; + + if (ALPHACHANNEL_FLAG(image)) { + num_channels ++; + image->strip[image->num_channels].up4 = image->alpha->strip[0].up4; + } + + for (mx = 0 ; mx < (int) EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + + /* Collect the data from the application. */ + int buffer[17*256]; + int jdx; + assert(image->num_channels <= 16); + image->inp_fun(image, mx, my, buffer); + + /* Pad to the bottom by repeating the last pixel */ + if ((my+1) == EXTENDED_HEIGHT_BLOCKS(image) && ((image->height1+image->window_extra_top+1) % 16 != 0)) { + int last_y = (image->height1 + image->window_extra_top) % 16; + int ydx; + for (ydx = last_y+1 ; ydx < 16 ; ydx += 1) { + int xdx; + for (xdx = 0 ; xdx < 16 ; xdx += 1) { + for (ch = 0 ; ch < num_channels ; ch += 1) { + int pad = buffer[(16*last_y + xdx)*num_channels + ch]; + if ((16*mx + xdx) > (int) image->width1) { + int use_x = (image->width1 + image->window_extra_left) % 16; + pad = buffer[(16*last_y + use_x)*num_channels + ch]; + } + + buffer[(16*ydx + xdx)*num_channels + ch] = pad; + } + } + } + } + + /* Pad to the right by repeating the last pixel */ + if ((mx+1) == EXTENDED_WIDTH_BLOCKS(image) && ((image->width1+image->window_extra_left+1) % 16 != 0)) { + int last_x = (image->width1 + image->window_extra_left) % 16; + int ydx ; + for (ydx = 0; ydx < 16 ; ydx += 1) { + int xdx; + for (xdx = last_x+1 ; xdx < 16 ; xdx += 1) { + for (ch = 0 ; ch < num_channels ; ch += 1) { + int pad = buffer[(16*ydx + last_x)*num_channels + ch]; + buffer[(16*ydx + xdx)*num_channels + ch] = pad; + } + } + } + } + + /* And finally collect the strip data. */ + /* image->alpha->strip[0].up4 == image->strip[image->num_channels].up4 !!! */ + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + int ch; + for (ch = 0 ; ch < num_channels ; ch += 1) + image->strip[ch].up4[mx].data[jdx] = buffer[jdx*num_channels + ch]; + } + +#if defined(DETAILED_DEBUG) && 0 + for (ch = 0 ; ch < num_channels ; ch += 1) { + DEBUG("image data mx=%3d my=%3d ch=%d:", mx, my, ch); + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + if (jdx%16 == 0 && jdx != 0) + DEBUG("\n%*s", 30, ""); + DEBUG(" %02x", image->strip[ch].up4[mx].data[jdx]); + } + DEBUG("\n"); + } +#endif + + /* AddBias and ComputeScaling */ + if (image->use_clr_fmt == 4 /*YUVK*/ && image->output_clr_fmt == JXR_OCF_CMYK) { + int*dp; + assert(image->num_channels == 4); + for (ch = 0 ; ch < 3 ; ch += 1) { + int jdx; + dp = image->strip[ch].up4[mx].data; + for (jdx = 0 ; jdx < 256 ; jdx += 1) + dp[jdx] = (dp[jdx] - (bias>>1)) << scale; + } + dp = image->strip[3].up4[mx].data; + for (jdx = 0 ; jdx < 256 ; jdx += 1) + dp[jdx] = (dp[jdx] + (bias>>1)) << scale; + + if (num_channels == 5) { // for interleaved CMYKA, num_channels = 5 and image->num_channels = 4 + dp = image->strip[4].up4[mx].data; + for (jdx = 0 ; jdx < 256 ; jdx += 1) + dp[jdx] = (dp[jdx] - bias) << scale; + } + } else { + for (ch = 0 ; ch < num_channels ; ch += 1) { + int*dp = image->strip[ch].up4[mx].data; + int jdx; + for (jdx = 0 ; jdx < 256 ; jdx += 1) { + dp[jdx] = (dp[jdx] - bias) << scale; + } + } + } + } + + /* Transform the color space. */ + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + break; + case 1: /* YUV420 */ + if (image->output_clr_fmt == JXR_OCF_RGB) { + rgb_to_yuv444_up4(image); + yuv444_to_yuv422_up4(image); + /* Do yuv422_to_yuv420_up3 after further processing */ + } + break; + case 2: /* YUV422 */ + if (image->output_clr_fmt == JXR_OCF_RGB) { + rgb_to_yuv444_up4(image); + yuv444_to_yuv422_up4(image); + } + break; + case 3: /* YUV444 */ + if (image->output_clr_fmt == JXR_OCF_RGB) + rgb_to_yuv444_up4(image); + break; + case 4: /* YUVK */ + if (image->output_clr_fmt == JXR_OCF_CMYK) + cmyk_to_yuvk_up4(image); + break; + case 6: /* NCOMPONENT */ + break; + } + +} + +static void scale_and_shuffle_up3(jxr_image_t image) +{ + int mx; + int my = image->cur_my + 3; + int ch; + + /* Finish transform of the color space. */ + switch (image->use_clr_fmt) { + case 0: /* YONLY */ + break; + case 1: /* YUV420 */ + if (image->output_clr_fmt == JXR_OCF_RGB) + yuv422_to_yuv420_up3(image); + break; + case 2: /* YUV422 */ + break; + case 3: /* YUV444 */ + break; + case 6: /* NCOMPONENT */ + break; + } + for (mx = 0 ; mx < (int) EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + +#if defined(DETAILED_DEBUG) && 1 + int jdx; + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int count = 256; + if (ch > 0 && image->use_clr_fmt==2/*YUV422*/) + count = 128; + if (ch > 0 && image->use_clr_fmt==1/*YUV420*/) + count = 64; + + DEBUG("image yuv mx=%3d my=%3d ch=%d:", mx, my, ch); + for (jdx = 0 ; jdx < count ; jdx += 1) { + if (jdx%8 == 0 && jdx != 0) + DEBUG("\n%*s", 29, ""); + DEBUG(" %08x", image->strip[ch].up3[mx].data[jdx]); + } + DEBUG("\n"); + } +#endif + + /* shuffle the data into the internal format. */ + block_shuffle444(image->strip[0].up3[mx].data); + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + block_shuffle420(image->strip[ch].up3[mx].data); + break; + case 2: /* YUV422 */ + block_shuffle422(image->strip[ch].up3[mx].data); + break; + default: + block_shuffle444(image->strip[ch].up3[mx].data); + break; + } + } + } +} + +static int*R2B(int*data, int x, int y) +{ + int bx = x/4; + int by = y/4; + int bl = by*4 + bx; + return data + bl*16 + 4*(y%4) + x%4; +} + +static int*R2B42(int*data, int x, int y) +{ + int bx = x/4; + int by = y/4; + int bl = by*2 + bx; + return data + bl*16 + 4*(y%4) + x%4; +} +#define TOP_Y(y) ( y == image->tile_row_position[ty]) +#define BOTTOM_Y(y) ( y == image->tile_row_position[ty] + image->tile_row_height[ty] - 1) +#define LEFT_X(idx) ( idx == 0) +#define RIGHT_X(idx) ( idx == image->tile_column_width[tx] -1 ) + + +static void first_prefilter444_up2(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + int top_my = image->cur_my + 2; + int idx; + assert(ch == 0 || (image->use_clr_fmt != 2/*YUV422*/ && image->use_clr_fmt !=1/* YUV420*/)); + + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level2 for row %d\n", top_my); + + for(tx = 0; tx < image->tile_columns; tx++) + { + int jdx; + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP2(image,ch,tx,0).data; + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + _jxr_4PreFilter(R2B(dp,0,jdx+0),R2B(dp,0,jdx+1),R2B(dp,0,jdx+2),R2B(dp,0,jdx+3)); + _jxr_4PreFilter(R2B(dp,1,jdx+0),R2B(dp,1,jdx+1),R2B(dp,1,jdx+2),R2B(dp,1,jdx+3)); + } + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + int*dp = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + _jxr_4PreFilter(R2B(dp,14,jdx+0),R2B(dp,14,jdx+1),R2B(dp,14,jdx+2),R2B(dp,14,jdx+3)); + _jxr_4PreFilter(R2B(dp,15,jdx+0),R2B(dp,15,jdx+1),R2B(dp,15,jdx+2),R2B(dp,15,jdx+3)); + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Pre filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + _jxr_4PreFilter(R2B(dp, 2,0),R2B(dp, 3,0),R2B(dp, 4,0),R2B(dp, 5,0)); + _jxr_4PreFilter(R2B(dp, 6,0),R2B(dp, 7,0),R2B(dp, 8,0),R2B(dp, 9,0)); + _jxr_4PreFilter(R2B(dp,10,0),R2B(dp,11,0),R2B(dp,12,0),R2B(dp,13,0)); + + _jxr_4PreFilter(R2B(dp, 2,1),R2B(dp, 3,1),R2B(dp, 4,1),R2B(dp, 5,1)); + _jxr_4PreFilter(R2B(dp, 6,1),R2B(dp, 7,1),R2B(dp, 8,1),R2B(dp, 9,1)); + _jxr_4PreFilter(R2B(dp,10,1),R2B(dp,11,1),R2B(dp,12,1),R2B(dp,13,1)); + + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B(pp,14,0),R2B(pp,15,0),R2B(dp,0,0),R2B(dp,1,0)); + _jxr_4PreFilter(R2B(pp,14,1),R2B(pp,15,1),R2B(dp,0,1),R2B(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch, tx, 0).data; + _jxr_4PreFilter(R2B(dp, 0,0),R2B(dp, 1,0),R2B(dp, 0,1),R2B(dp, 1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B(dp, 14,0),R2B(dp, 15,0),R2B(dp, 14,1),R2B(dp, 15,1)); + } + + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Pre filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP2(image,ch,tx,idx).data; + + _jxr_4PreFilter(R2B(tp, 2,14),R2B(tp, 3,14),R2B(tp, 4,14),R2B(tp, 5,14)); + _jxr_4PreFilter(R2B(tp, 6,14),R2B(tp, 7,14),R2B(tp, 8,14),R2B(tp, 9,14)); + _jxr_4PreFilter(R2B(tp,10,14),R2B(tp,11,14),R2B(tp,12,14),R2B(tp,13,14)); + + _jxr_4PreFilter(R2B(tp, 2,15),R2B(tp, 3,15),R2B(tp, 4,15),R2B(tp, 5,15)); + _jxr_4PreFilter(R2B(tp, 6,15),R2B(tp, 7,15),R2B(tp, 8,15),R2B(tp, 9,15)); + _jxr_4PreFilter(R2B(tp,10,15),R2B(tp,11,15),R2B(tp,12,15),R2B(tp,13,15)); + + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tn = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B(tn,14,14),R2B(tn,15,14),R2B(tp, 0,14),R2B(tp, 1,14)); + _jxr_4PreFilter(R2B(tn,14,15),R2B(tn,15,15),R2B(tp, 0,15),R2B(tp, 1,15)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B(dp, 0,14),R2B(dp, 1, 14),R2B(dp, 0,15),R2B(dp, 1, 15)); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B(dp, 14, 14),R2B(dp, 15, 14),R2B(dp, 14,15),R2B(dp, 15, 15)); + } + + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + int jdx; + + for (jdx = 2 ; jdx < 14 ; jdx += 4) { + + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4PreFilter(R2B(dp, 2,jdx+0),R2B(dp, 3,jdx+0),R2B(dp, 4,jdx+0),R2B(dp, 5,jdx+0), + R2B(dp, 2,jdx+1),R2B(dp, 3,jdx+1),R2B(dp, 4,jdx+1),R2B(dp, 5,jdx+1), + R2B(dp, 2,jdx+2),R2B(dp, 3,jdx+2),R2B(dp, 4,jdx+2),R2B(dp, 5,jdx+2), + R2B(dp, 2,jdx+3),R2B(dp, 3,jdx+3),R2B(dp, 4,jdx+3),R2B(dp, 5,jdx+3)); + _jxr_4x4PreFilter(R2B(dp, 6,jdx+0),R2B(dp, 7,jdx+0),R2B(dp, 8,jdx+0),R2B(dp, 9,jdx+0), + R2B(dp, 6,jdx+1),R2B(dp, 7,jdx+1),R2B(dp, 8,jdx+1),R2B(dp, 9,jdx+1), + R2B(dp, 6,jdx+2),R2B(dp, 7,jdx+2),R2B(dp, 8,jdx+2),R2B(dp, 9,jdx+2), + R2B(dp, 6,jdx+3),R2B(dp, 7,jdx+3),R2B(dp, 8,jdx+3),R2B(dp, 9,jdx+3)); + _jxr_4x4PreFilter(R2B(dp,10,jdx+0),R2B(dp,11,jdx+0),R2B(dp,12,jdx+0),R2B(dp,13,jdx+0), + R2B(dp,10,jdx+1),R2B(dp,11,jdx+1),R2B(dp,12,jdx+1),R2B(dp,13,jdx+1), + R2B(dp,10,jdx+2),R2B(dp,11,jdx+2),R2B(dp,12,jdx+2),R2B(dp,13,jdx+2), + R2B(dp,10,jdx+3),R2B(dp,11,jdx+3),R2B(dp,12,jdx+3),R2B(dp,13,jdx+3)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) { + /* 4x4 at the right */ + int*np = MACROBLK_UP2(image,ch,tx,idx+1).data; + + _jxr_4x4PreFilter(R2B(dp,14,jdx+0),R2B(dp,15,jdx+0),R2B(np, 0,jdx+0),R2B(np, 1,jdx+0), + R2B(dp,14,jdx+1),R2B(dp,15,jdx+1),R2B(np, 0,jdx+1),R2B(np, 1,jdx+1), + R2B(dp,14,jdx+2),R2B(dp,15,jdx+2),R2B(np, 0,jdx+2),R2B(np, 1,jdx+2), + R2B(dp,14,jdx+3),R2B(dp,15,jdx+3),R2B(np, 0,jdx+3),R2B(np, 1,jdx+3)); + } + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + int*up = MACROBLK_UP3(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + _jxr_4PreFilter(R2B(dp,0,14),R2B(dp,0,15),R2B(up,0,0),R2B(up,0,1)); + _jxr_4PreFilter(R2B(dp,1,14),R2B(dp,1,15),R2B(up,1,0),R2B(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + /* 4x4 bottom */ + _jxr_4x4PreFilter(R2B(dp, 2,14),R2B(dp, 3,14),R2B(dp, 4,14),R2B(dp, 5,14), + R2B(dp, 2,15),R2B(dp, 3,15),R2B(dp, 4,15),R2B(dp, 5,15), + R2B(up, 2, 0),R2B(up, 3, 0),R2B(up, 4, 0),R2B(up, 5, 0), + R2B(up, 2, 1),R2B(up, 3, 1),R2B(up, 4, 1),R2B(up, 5, 1)); + _jxr_4x4PreFilter(R2B(dp, 6,14),R2B(dp, 7,14),R2B(dp, 8,14),R2B(dp, 9,14), + R2B(dp, 6,15),R2B(dp, 7,15),R2B(dp, 8,15),R2B(dp, 9,15), + R2B(up, 6, 0),R2B(up, 7, 0),R2B(up, 8, 0),R2B(up, 9, 0), + R2B(up, 6, 1),R2B(up, 7, 1),R2B(up, 8, 1),R2B(up, 9, 1)); + _jxr_4x4PreFilter(R2B(dp,10,14),R2B(dp,11,14),R2B(dp,12,14),R2B(dp,13,14), + R2B(dp,10,15),R2B(dp,11,15),R2B(dp,12,15),R2B(dp,13,15), + R2B(up,10, 0),R2B(up,11, 0),R2B(up,12, 0),R2B(up,13, 0), + R2B(up,10, 1),R2B(up,11, 1),R2B(up,12, 1),R2B(up,13, 1)); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right */ + int*dn = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP3(image,ch,tx,idx+1).data; + + /* 4x4 on right, below, below-right */ + _jxr_4x4PreFilter(R2B(dp,14,14),R2B(dp,15,14),R2B(dn, 0,14),R2B(dn, 1,14), + R2B(dp,14,15),R2B(dp,15,15),R2B(dn, 0,15),R2B(dn, 1,15), + R2B(up,14, 0),R2B(up,15, 0),R2B(un, 0, 0),R2B(un, 1, 0), + R2B(up,14, 1),R2B(up,15, 1),R2B(un, 0, 1),R2B(un, 1, 1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Across vertical blocks, right edge */ + _jxr_4PreFilter(R2B(dp,14,14),R2B(dp,14,15),R2B(up,14,0),R2B(up,14,1)); + _jxr_4PreFilter(R2B(dp,15,14),R2B(dp,15,15),R2B(up,15,0),R2B(up,15,1)); + } + } + } + } +} + +static void first_prefilter422_up2(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + + int top_my = image->cur_my + 2; + int idx; + assert(ch > 0 && image->use_clr_fmt == 2/*YUV422*/); + assert(top_my >= 0 ); + + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level2 for row %d\n", top_my); + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B42(dp,0, 2),R2B42(dp,0, 3),R2B42(dp,0, 4),R2B42(dp,0, 5)); + _jxr_4PreFilter(R2B42(dp,0, 6),R2B42(dp,0, 7),R2B42(dp,0, 8),R2B42(dp,0, 9)); + _jxr_4PreFilter(R2B42(dp,0,10),R2B42(dp,0,11),R2B42(dp,0,12),R2B42(dp,0,13)); + + _jxr_4PreFilter(R2B42(dp,1, 2),R2B42(dp,1, 3),R2B42(dp,1, 4),R2B42(dp,1, 5)); + _jxr_4PreFilter(R2B42(dp,1, 6),R2B42(dp,1, 7),R2B42(dp,1, 8),R2B42(dp,1, 9)); + _jxr_4PreFilter(R2B42(dp,1,10),R2B42(dp,1,11),R2B42(dp,1,12),R2B42(dp,1,13)); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + + int*dp = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4PreFilter(R2B42(dp,6,2),R2B42(dp,6,3),R2B42(dp,6,4),R2B42(dp,6,5)); + _jxr_4PreFilter(R2B42(dp,7,2),R2B42(dp,7,3),R2B42(dp,7,4),R2B42(dp,7,5)); + + _jxr_4PreFilter(R2B42(dp,6,6),R2B42(dp,6,7),R2B42(dp,6,8),R2B42(dp,6,9)); + _jxr_4PreFilter(R2B42(dp,7,6),R2B42(dp,7,7),R2B42(dp,7,8),R2B42(dp,7,9)); + + _jxr_4PreFilter(R2B42(dp,6,10),R2B42(dp,6,11),R2B42(dp,6,12),R2B42(dp,6,13)); + _jxr_4PreFilter(R2B42(dp,7,10),R2B42(dp,7,11),R2B42(dp,7,12),R2B42(dp,7,13)); + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + + _jxr_4PreFilter(R2B42(dp, 2,0),R2B42(dp, 3,0),R2B42(dp, 4,0),R2B42(dp, 5,0)); + _jxr_4PreFilter(R2B42(dp, 2,1),R2B42(dp, 3,1),R2B42(dp, 4,1),R2B42(dp, 5,1)); + + /* Top across for soft tiles */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B42(pp,6,0),R2B42(pp,7,0),R2B(dp,0,0),R2B42(dp,1,0)); + _jxr_4PreFilter(R2B42(pp,6,1),R2B42(pp,7,1),R2B(dp,0,1),R2B42(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch, tx, 0).data; + _jxr_4PreFilter(R2B42(dp,0,0),R2B42(dp,1,0),R2B42(dp,0,1),R2B42(dp,1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B42(dp,6,0),R2B42(dp,7,0),R2B42(dp,6,1),R2B42(dp,7,1)); + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Pre filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP2(image,ch,tx,idx).data; + + _jxr_4PreFilter(R2B42(tp,2,14),R2B42(tp,3,14),R2B42(tp,4,14),R2B42(tp,5,14)); + _jxr_4PreFilter(R2B42(tp,2,15),R2B42(tp,3,15),R2B42(tp,4,15),R2B42(tp,5,15)); + + /* Bottom across for soft tiles */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + /* Blocks that span the MB to the right */ + int*tn = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B42(tn,6,14),R2B42(tn,7,14),R2B42(tp,0,14),R2B42(tp,1,14)); + _jxr_4PreFilter(R2B42(tn,6,15),R2B42(tn,7,15),R2B42(tp,0,15),R2B42(tp,1,15)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B42(dp,0,14),R2B42(dp,1,14),R2B42(dp,0,15),R2B42(dp,1,15)); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B42(dp,6,14),R2B42(dp,7,14),R2B42(dp,6,15),R2B42(dp,7,15)); + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4PreFilter(R2B42(dp,2,2),R2B42(dp,3,2),R2B42(dp,4,2),R2B42(dp,5,2), + R2B42(dp,2,3),R2B42(dp,3,3),R2B42(dp,4,3),R2B42(dp,5,3), + R2B42(dp,2,4),R2B42(dp,3,4),R2B42(dp,4,4),R2B42(dp,5,4), + R2B42(dp,2,5),R2B42(dp,3,5),R2B42(dp,4,5),R2B42(dp,5,5)); + + _jxr_4x4PreFilter(R2B42(dp,2,6),R2B42(dp,3,6),R2B42(dp,4,6),R2B42(dp,5,6), + R2B42(dp,2,7),R2B42(dp,3,7),R2B42(dp,4,7),R2B42(dp,5,7), + R2B42(dp,2,8),R2B42(dp,3,8),R2B42(dp,4,8),R2B42(dp,5,8), + R2B42(dp,2,9),R2B42(dp,3,9),R2B42(dp,4,9),R2B42(dp,5,9)); + + _jxr_4x4PreFilter(R2B42(dp,2,10),R2B42(dp,3,10),R2B42(dp,4,10),R2B42(dp,5,10), + R2B42(dp,2,11),R2B42(dp,3,11),R2B42(dp,4,11),R2B42(dp,5,11), + R2B42(dp,2,12),R2B42(dp,3,12),R2B42(dp,4,12),R2B42(dp,5,12), + R2B42(dp,2,13),R2B42(dp,3,13),R2B42(dp,4,13),R2B42(dp,5,13)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) { + /* Blocks that span the MB to the right */ + int*np = MACROBLK_UP2(image,ch,tx,idx+1).data; + _jxr_4x4PreFilter(R2B42(dp,6,2),R2B42(dp,7,2),R2B42(np,0,2),R2B42(np,1,2), + R2B42(dp,6,3),R2B42(dp,7,3),R2B42(np,0,3),R2B42(np,1,3), + R2B42(dp,6,4),R2B42(dp,7,4),R2B42(np,0,4),R2B42(np,1,4), + R2B42(dp,6,5),R2B42(dp,7,5),R2B42(np,0,5),R2B42(np,1,5)); + + _jxr_4x4PreFilter(R2B42(dp,6,6),R2B42(dp,7,6),R2B42(np,0,6),R2B42(np,1,6), + R2B42(dp,6,7),R2B42(dp,7,7),R2B42(np,0,7),R2B42(np,1,7), + R2B42(dp,6,8),R2B42(dp,7,8),R2B42(np,0,8),R2B42(np,1,8), + R2B42(dp,6,9),R2B42(dp,7,9),R2B42(np,0,9),R2B42(np,1,9)); + + _jxr_4x4PreFilter(R2B42(dp,6,10),R2B42(dp,7,10),R2B42(np,0,10),R2B42(np,1,10), + R2B42(dp,6,11),R2B42(dp,7,11),R2B42(np,0,11),R2B42(np,1,11), + R2B42(dp,6,12),R2B42(dp,7,12),R2B42(np,0,12),R2B42(np,1,12), + R2B42(dp,6,13),R2B42(dp,7,13),R2B42(np,0,13),R2B42(np,1,13)); + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + /* Blocks that MB below */ + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + int*up = MACROBLK_UP3(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + _jxr_4PreFilter(R2B42(dp,0,14),R2B42(dp,0,15),R2B42(up,0,0),R2B42(up,0,1)); + _jxr_4PreFilter(R2B42(dp,1,14),R2B42(dp,1,15),R2B42(up,1,0),R2B42(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + _jxr_4x4PreFilter(R2B42(dp,2,14),R2B42(dp,3,14),R2B42(dp,4,14),R2B42(dp,5,14), + R2B42(dp,2,15),R2B42(dp,3,15),R2B42(dp,4,15),R2B42(dp,5,15), + R2B42(up,2, 0),R2B42(up,3, 0),R2B42(up,4, 0),R2B42(up,5, 0), + R2B42(up,2, 1),R2B42(up,3, 1),R2B42(up,4, 1),R2B42(up,5, 1)); + + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right, below, below-right */ + int*dn = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP3(image,ch,tx,idx+1).data; + + _jxr_4x4PreFilter(R2B42(dp,6,14),R2B42(dp,7,14),R2B42(dn,0,14),R2B42(dn,1,14), + R2B42(dp,6,15),R2B42(dp,7,15),R2B42(dn,0,15),R2B42(dn,1,15), + R2B42(up,6, 0),R2B42(up,7, 0),R2B42(un,0, 0),R2B42(un,1, 0), + R2B42(up,6, 1),R2B42(up,7, 1),R2B42(un,0, 1),R2B42(un,1, 1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + _jxr_4PreFilter(R2B42(dp,6,14),R2B42(dp,6,15),R2B42(up,6,0),R2B42(up,6,1)); + _jxr_4PreFilter(R2B42(dp,7,14),R2B42(dp,7,15),R2B42(up,7,0),R2B42(up,7,1)); + } + } + } + } +} + +static void first_prefilter420_up2(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + int top_my = image->cur_my + 2; + int idx; + assert(ch > 0 && image->use_clr_fmt == 1/*YUV420*/); + + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level2 (YUV420) for row %d\n", top_my); + + for(tx = 0; tx < image->tile_columns; tx++) + { + + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + int*dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B42(dp,0,2),R2B42(dp,0,3),R2B42(dp,0,4),R2B42(dp,0,5)); + _jxr_4PreFilter(R2B42(dp,1,2),R2B42(dp,1,3),R2B42(dp,1,4),R2B42(dp,1,5)); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag){ + int*dp = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4PreFilter(R2B42(dp,6,2),R2B42(dp,6,3),R2B42(dp,6,4),R2B42(dp,6,5)); + _jxr_4PreFilter(R2B42(dp,7,2),R2B42(dp,7,3),R2B42(dp,7,4),R2B42(dp,7,5)); + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Pre filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + _jxr_4PreFilter(R2B42(dp, 2,0),R2B42(dp, 3,0),R2B42(dp, 4,0),R2B42(dp, 5,0)); + _jxr_4PreFilter(R2B42(dp, 2,1),R2B42(dp, 3,1),R2B42(dp, 4,1),R2B42(dp, 5,1)); + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*pp = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B42(pp,6,0),R2B42(pp,7,0),R2B(dp,0,0),R2B42(dp,1,0)); + _jxr_4PreFilter(R2B42(pp,6,1),R2B42(pp,7,1),R2B(dp,0,1),R2B42(dp,1,1)); + } + } + + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B42(dp, 0,0),R2B42(dp, 1, 0),R2B42(dp, 0 ,1),R2B42(dp, 1,1)); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B42(dp, 6,0),R2B42(dp, 7,0),R2B42(dp, 6,1),R2B42(dp, 7,1));; + } + + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Pre filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + int*tp = MACROBLK_UP2(image,ch,tx,idx).data; + + _jxr_4PreFilter(R2B42(tp,2,6),R2B42(tp,3,6),R2B42(tp,4,6),R2B42(tp,5,6)); + _jxr_4PreFilter(R2B42(tp,2,7),R2B42(tp,3,7),R2B42(tp,4,7),R2B42(tp,5,7)); + + + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tn = MACROBLK_UP2(image,ch,tx,idx-1).data; + _jxr_4PreFilter(R2B42(tn,6,6),R2B42(tn,7,6),R2B42(tp,0,6),R2B42(tp,1,6)); + _jxr_4PreFilter(R2B42(tn,6,7),R2B42(tn,7,7),R2B42(tp,0,7),R2B42(tp,1,7)); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx,0).data; + _jxr_4PreFilter(R2B42(dp, 0,6),R2B42(dp, 1, 6),R2B42(dp, 0,7),R2B42(dp, 1, 7)); + } + + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *dp = MACROBLK_UP2(image,ch,tx, image->tile_column_width[tx] - 1 ).data; + _jxr_4PreFilter(R2B42(dp, 6, 6),R2B42(dp, 7, 6),R2B42(dp, 6, 7),R2B42(dp, 7, 7)); + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + int*up = MACROBLK_UP3(image,ch,tx,idx).data; + + /* Fully interior 4x4 filter blocks... */ + _jxr_4x4PreFilter(R2B42(dp,2,2),R2B42(dp,3,2),R2B42(dp,4,2),R2B42(dp,5,2), + R2B42(dp,2,3),R2B42(dp,3,3),R2B42(dp,4,3),R2B42(dp,5,3), + R2B42(dp,2,4),R2B42(dp,3,4),R2B42(dp,4,4),R2B42(dp,5,4), + R2B42(dp,2,5),R2B42(dp,3,5),R2B42(dp,4,5),R2B42(dp,5,5)); + + if ( (image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && !RIGHT_X(idx))) + { + /* 4x4 at the right */ + int*np = MACROBLK_UP2(image,ch,tx,idx+1).data; + + _jxr_4x4PreFilter(R2B42(dp,6,2),R2B42(dp,7,2),R2B42(np,0,2),R2B42(np,1,2), + R2B42(dp,6,3),R2B42(dp,7,3),R2B42(np,0,3),R2B42(np,1,3), + R2B42(dp,6,4),R2B42(dp,7,4),R2B42(np,0,4),R2B42(np,1,4), + R2B42(dp,6,5),R2B42(dp,7,5),R2B42(np,0,5),R2B42(np,1,5)); + } + + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + int*dp = MACROBLK_UP2(image,ch,tx,idx).data; + int*up = MACROBLK_UP3(image,ch,tx,idx).data; + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + _jxr_4PreFilter(R2B42(dp,0,6),R2B42(dp,0,7),R2B42(up,0,0),R2B42(up,0,1)); + _jxr_4PreFilter(R2B42(dp,1,6),R2B42(dp,1,7),R2B42(up,1,0),R2B42(up,1,1)); + } + if((!image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !BOTTOM_Y(top_my))) + { + /* 4x4 straddling lower MB */ + _jxr_4x4PreFilter(R2B42(dp,2,6),R2B42(dp,3,6),R2B42(dp,4,6),R2B42(dp,5,6), + R2B42(dp,2,7),R2B42(dp,3,7),R2B42(dp,4,7),R2B42(dp,5,7), + R2B42(up,2,0),R2B42(up,3,0),R2B42(up,4,0),R2B42(up,5,0), + R2B42(up,2,1),R2B42(up,3,1),R2B42(up,4,1),R2B42(up,5,1)); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* Blocks that span the MB to the right */ + int*dn = MACROBLK_UP2(image,ch,tx,idx+1).data; + int*un = MACROBLK_UP3(image,ch,tx,idx+1).data; + + /* 4x4 right, below, below-right */ + _jxr_4x4PreFilter(R2B42(dp,6,6),R2B42(dp,7,6),R2B42(dn,0,6),R2B42(dn,1,6), + R2B42(dp,6,7),R2B42(dp,7,7),R2B42(dn,0,7),R2B42(dn,1,7), + R2B42(up,6,0),R2B42(up,7,0),R2B42(un,0,0),R2B42(un,1,0), + R2B42(up,6,1),R2B42(up,7,1),R2B42(un,0,1),R2B42(un,1,1)); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Across vertical blocks, right edge */ + _jxr_4PreFilter(R2B42(dp,6,6),R2B42(dp,6,7),R2B42(up,6,0),R2B42(up,6,1)); + _jxr_4PreFilter(R2B42(dp,7,6),R2B42(dp,7,7),R2B42(up,7,0),R2B42(up,7,1)); + } + } + } + } +} + +static void first_prefilter_up2(jxr_image_t image, int ty) +{ + int ch; + first_prefilter444_up2(image, 0, ty); + switch (image->use_clr_fmt) { + case 0: + assert(image->num_channels == 1); + break; + case 1:/*YUV420*/ + first_prefilter420_up2(image, 1, ty); + first_prefilter420_up2(image, 2, ty); + break; + case 2:/*YUV422*/ + first_prefilter422_up2(image, 1, ty); + first_prefilter422_up2(image, 2, ty); + break; + default: + for (ch = 1 ; ch < image->num_channels ; ch += 1) + first_prefilter444_up2(image, ch, ty); + break; + } +} + +static void PCT_stage2_up1(jxr_image_t image, int ch, int ty) +{ + int tx = 0; + int use_my = image->cur_my + 1; + int mx; + int dc_quant; + int dclp_count; + + /* make adjustments based on tiling */ + if (use_my == image->tile_row_height[ty]) { + ty += 1; + use_my = 0; + } + + dclp_count = 16; + if (ch>0 && image->use_clr_fmt == 2/*YUV422*/) + dclp_count = 8; + else if (ch>0 && image->use_clr_fmt == 1/*YUV420*/) + dclp_count = 4; + + dc_quant = w_guess_dc_quant(image, ch, tx, ty); + dc_quant = _jxr_quant_map(image, dc_quant, ch==0? 1 : 0/* iShift for YONLY */); + assert(dc_quant > 0); + + for (mx = 0 ; mx < (int) EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int jdx; + int lp_quant; + + if (ch > 0 && image->use_clr_fmt == 1/*YUV420*/) { + + /* Scale up the chroma channel */ + if (image->scaled_flag) { + for (jdx = 0 ; jdx < 4 ; jdx += 1) { + int val = image->strip[ch].up1[mx].data[jdx]; + val = _jxr_floor_div2(val); + image->strip[ch].up1[mx].data[jdx] = val; + } + } + + _jxr_InvPermute2pt(image->strip[ch].up1[mx].data+1, + image->strip[ch].up1[mx].data+2); + _jxr_2x2IPCT(image->strip[ch].up1[mx].data+0); + + } else if (ch > 0 && image->use_clr_fmt == 2/*YUV422*/) { + +#if defined(DETAILED_DEBUG) && 1 + DEBUG(" DC/LP scaled_flag=%d\n", image->scaled_flag); + { + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Pre-PCT:", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 43, ""); + } + DEBUG("\n"); + } +#endif + /* Scale up the chroma channel */ + if (image->scaled_flag) { + for (jdx = 0 ; jdx < 8 ; jdx += 1) { + int val = image->strip[ch].up1[mx].data[jdx]; + val = _jxr_floor_div2(val); + image->strip[ch].up1[mx].data[jdx] = val; + } + } +#if defined(DETAILED_DEBUG) && 1 + { + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) scaled :", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 43, ""); + } + DEBUG("\n"); + } +#endif + + /* The InvPermute2pt and FwdPermute2pt are identical */ + _jxr_InvPermute2pt(image->strip[ch].up1[mx].data+1, + image->strip[ch].up1[mx].data+2); + _jxr_InvPermute2pt(image->strip[ch].up1[mx].data+5, + image->strip[ch].up1[mx].data+6); + /* The 2x2PCT and 2x2IPCT are identical */ + _jxr_2x2IPCT(image->strip[ch].up1[mx].data+0); + _jxr_2x2IPCT(image->strip[ch].up1[mx].data+4); + + _jxr_2ptFwdT(image->strip[ch].up1[mx].data+0, + image->strip[ch].up1[mx].data+4); + +#if defined(DETAILED_DEBUG) && 1 + DEBUG(" DC/LP scaled_flag=%d\n", image->scaled_flag); + { + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Post-PCT:", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 44, ""); + } + DEBUG("\n"); + } +#endif + + } else { +#if defined(DETAILED_DEBUG) && 1 + { + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Pre-PCT:", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 43, ""); + } + DEBUG("\n"); + } +#endif + /* Scale up the chroma channel */ + if (ch > 0 && image->scaled_flag) { + for (jdx = 0 ; jdx < 16 ; jdx += 1) { + int val = image->strip[ch].up1[mx].data[jdx]; + val = _jxr_floor_div2(val); + image->strip[ch].up1[mx].data[jdx] = val; + } + } + + _jxr_4x4PCT(image->strip[ch].up1[mx].data); + +#if defined(DETAILED_DEBUG) + { + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) post-PCT:", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,0,mx)); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 44, ""); + } + DEBUG("\n"); + } +#endif + } + + /* Quantize */ + lp_quant = w_guess_lp_quant(image, ch, tx, ty, mx, use_my); + MACROBLK_UP1_LP_QUANT(image,ch,tx,mx) = lp_quant; + lp_quant = _jxr_quant_map(image, lp_quant, ch==0? 1 : 0/* iShift for YONLY */); + assert(lp_quant > 0); + + DEBUG(" DC-LP (mx=%d ch=%d) use_dc_quant=%d, use_lp_quant=%d\n", + mx, ch, dc_quant, lp_quant); + + CHECK1(image->lwf_test, MACROBLK_CUR_DC(image,ch,tx,mx)); + MACROBLK_UP_DC(image,ch,tx,mx) = quantize_dc(MACROBLK_UP_DC(image,ch,tx,mx), dc_quant); + for (jdx = 1 ; jdx < dclp_count ; jdx += 1) { + int value; + CHECK1(image->lwf_test, MACROBLK_UP_LP(image,ch,tx,mx,jdx-1)); + value = MACROBLK_UP_LP(image,ch,tx,mx,jdx-1); + MACROBLK_UP_LP(image,ch,tx,mx,jdx-1) = quantize_lphp(value, lp_quant); + } +#if defined(DETAILED_DEBUG) + { int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) post-QP:", use_my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < dclp_count-1 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 43, ""); + } + DEBUG("\n"); + } +#endif + } +} + +static void second_prefilter444_up1(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + int top_my = image->cur_my + 1; + int idx; + + assert(ch == 0 || (image->use_clr_fmt != 2/*YUV422*/ && image->use_clr_fmt !=1/* YUV420*/)); + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level1 (YUV444) for row %d\n", top_my); + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Pre filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx-1).data; /* Macroblock to the right */ + + _jxr_4PreFilter(tp1+2, tp1+3, tp0+0, tp0+1); + _jxr_4PreFilter(tp1+6, tp1+7, tp0+4, tp0+5); + } + } + /* Top left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + _jxr_4PreFilter(tp0+0, tp0+1, tp0+4, tp0+5); + } + /* Top right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4PreFilter(tp0+2, tp0+3, tp0+6, tp0+7); + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Pre filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx-1).data; + _jxr_4PreFilter(tp1+10, tp1+11, tp0+8, tp0+9); + _jxr_4PreFilter(tp1+14, tp1+15, tp0+12, tp0+13); + } + } + + /* Bottom left corner */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + _jxr_4PreFilter(tp0+8, tp0+9, tp0+12, tp0+13); + } + /* Bottom right corner */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + _jxr_4PreFilter(tp0+10, tp0+11, tp0+14, tp0+15); + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + if ((top_my+1) < (int) EXTENDED_HEIGHT_BLOCKS(image)) { + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + int*up0 = MACROBLK_UP2(image,ch,tx,0).data; + + /* Left edge Across Vertical MBs */ + _jxr_4PreFilter(tp0+8, tp0+12, up0+0, up0+4); + _jxr_4PreFilter(tp0+9, tp0+13, up0+1, up0+5); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*up1 = MACROBLK_UP2(image,ch,tx,idx+1).data; + + /* MB below, right, right-below */ + _jxr_4x4PreFilter(tp0+10, tp0+11, tp1+ 8, tp1+ 9, + tp0+14, tp0+15, tp1+12, tp1+13, + up0+ 2, up0+ 3, up1+ 0, up1+ 1, + up0+ 6, up0+ 7, up1+ 4, up1+ 5); + } + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + + /* Right edge Across Vertical MBs */ + _jxr_4PreFilter(tp0+10, tp0+14, up0+2, up0+6); + _jxr_4PreFilter(tp0+11, tp0+15, up0+3, up0+7); + } + } + } + } +} + + +static void second_prefilter422_up1(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + int top_my = image->cur_my + 1; + int idx; + + assert(ch > 0); + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level2 (YUV422) for row %d\n", top_my); + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Difference */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[0] = tp0[0] - tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Difference */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] - tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Difference */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[6] = tp0[6] - tp0[7]; + CHECK1(image->lwf_test, tp0[6]); + } + /* Bottom Right Corner Difference */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[7] = tp0[7] - tp0[6]; + CHECK1(image->lwf_test, tp0[7]); + } + } + } + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Left edge */ + if (tx == 0 || image->disableTileOverlapFlag) + { + /* Interior left edge */ + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + _jxr_2PreFilter(tp0+2, tp0+4); + } + + /* Right edge */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + /* Interior Right edge */ + _jxr_2PreFilter(tp0+3, tp0+5); + } + + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my) )) + { + /* If this is the very first strip of blocks, then process the + first two scan lines with the smaller 4Pre filter. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx-1).data; /* The macroblock to the right */ + + _jxr_2PreFilter(tp1+1, tp0+0); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. finish up with 4Pre filters. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx - 1).data; + _jxr_2PreFilter(tp1+7, tp0+6); + } + } + } + + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + if(top_my< EXTENDED_HEIGHT_BLOCKS(image) -1) + { + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Across vertical blocks, left edge */ + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + int*up0 = MACROBLK_UP2(image,ch,tx,0).data; + + /* Left edge across vertical MBs */ + _jxr_2PreFilter(tp0+6, up0+0); + } + + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + + /* Right edge across MBs */ + _jxr_2PreFilter(tp0+7, up0+1); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*up2 = MACROBLK_UP2(image,ch,tx,idx+1).data; + + /* MB below, right, right-below */ + _jxr_2x2PreFilter(tp0+7, tp1+6, up0+1, up2+0); + } + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + + /* MB to the right */ + _jxr_2x2PreFilter(tp0+3, tp1+2, tp0+5, tp1+4); + } + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[0] = tp0[0] + tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] + tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[6] = tp0[6] + tp0[7]; + CHECK1(image->lwf_test, tp0[6]); + } + /* Bottom Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[7] = tp0[7] + tp0[6]; + CHECK1(image->lwf_test, tp0[7]); + } + } + } +} + +static void second_prefilter420_up1(jxr_image_t image, int ch, int ty) +{ + int tx = 0; /* XXXX */ + int top_my = image->cur_my + 1; + int idx; + assert(ch > 0); + + if (top_my >= image->tile_row_height[ty]) + top_my -= image->tile_row_height[ty++]; + top_my += image->tile_row_position[ty]; + + DEBUG("Pre Level2 (YUV420) for row %d\n", top_my); + + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Difference*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[0] = tp0[0] - tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Difference*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] - tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Difference*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[2] = tp0[2] - tp0[3]; + CHECK1(image->lwf_test, tp0[2]); + } + /* Bottom Right Corner Difference*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[3] = tp0[3] - tp0[2]; + CHECK1(image->lwf_test, tp0[3]); + } + } + } + + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Top edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx-1).data; + _jxr_2PreFilter(tp1+1, tp0+0); + } + } + } + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) { + + /* This is the last row, so there is no UP below + TOP. */ + for (idx = 0; idx < image->tile_column_width[tx] ; idx += 1) + { + /* Bottom edge across */ + if ( (image->tile_column_position[tx] + idx > 0 && !image->disableTileOverlapFlag) + || (image->disableTileOverlapFlag && !LEFT_X(idx))) { + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx-1).data; + _jxr_2PreFilter(tp1+3, tp0+2); + } + } + } + else + { + for (idx = 0 ; idx < image->tile_column_width[tx] ; idx += 1) { + + if ((tx == 0 && idx==0 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && LEFT_X(idx) && !BOTTOM_Y(top_my))) { + /* Left edge across vertical MBs */ + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + int*up0 = MACROBLK_UP2(image,ch,tx,0).data; + + _jxr_2PreFilter(tp0+2, up0+0); + } + + if((image->tile_column_position[tx] + idx == (int) EXTENDED_WIDTH_BLOCKS(image)-1 && !image->disableTileOverlapFlag) || + (image->disableTileOverlapFlag && RIGHT_X(idx) && !BOTTOM_Y(top_my))) + { + /* Right edge across vertical MBs */ + int*tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,image->tile_column_width[tx]-1).data; + + _jxr_2PreFilter(tp0+3, up0+1); + } + + if (((image->tile_column_position[tx] + idx < EXTENDED_WIDTH_BLOCKS(image)-1) && !image->disableTileOverlapFlag ) || + ( image->disableTileOverlapFlag && !RIGHT_X(idx) && !BOTTOM_Y(top_my) ) + ) + { + /* This assumes that the DCLP coefficients are the first + 16 values in the array, and ordered properly. */ + /* MB below, right, right-below */ + int*tp0 = MACROBLK_UP1(image,ch,tx,idx+0).data; + int*tp1 = MACROBLK_UP1(image,ch,tx,idx+1).data; + int*up0 = MACROBLK_UP2(image,ch,tx,idx+0).data; + int*up2 = MACROBLK_UP2(image,ch,tx,idx+1).data; + + _jxr_2x2PreFilter(tp0+3, tp1+2, + up0+1, up2+0); + } + } + } + } + + /* Top edge */ + if(top_my == 0 || (image->disableTileOverlapFlag && TOP_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Top Left Corner Addition */ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[0] = tp0[0] + tp0[1]; + CHECK1(image->lwf_test, tp0[0]); + } + /* Top Right Corner Addition */ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[1] = tp0[1] + tp0[0]; + CHECK1(image->lwf_test, tp0[1]); + } + } + } + + + /* Bottom edge */ + if ((top_my+1) == (int) EXTENDED_HEIGHT_BLOCKS(image) || (image->disableTileOverlapFlag && BOTTOM_Y(top_my))) + { + for(tx = 0; tx < image->tile_columns; tx++) + { + /* Bottom Left Corner Addition*/ + if(tx == 0 || image->disableTileOverlapFlag) + { + int*tp0 = MACROBLK_UP1(image,ch,tx,0).data; + tp0[2] = tp0[2] + tp0[3]; + CHECK1(image->lwf_test, tp0[2]); + } + /* Bottom Right Corner Addition*/ + if(tx == image->tile_columns -1 || image->disableTileOverlapFlag) + { + int *tp0 = MACROBLK_UP1(image,ch,tx,image->tile_column_width[tx]-1).data; + tp0[3] = tp0[3] + tp0[2]; + CHECK1(image->lwf_test, tp0[3]); + } + } + } +} + +static void second_prefilter_up1(jxr_image_t image, int ty) +{ + int ch; + second_prefilter444_up1(image, 0, ty); + switch (image->use_clr_fmt) { + case 0: + assert(image->num_channels == 1); + break; + case 1:/*YUV420*/ + second_prefilter420_up1(image, 1, ty); + second_prefilter420_up1(image, 2, ty); + break; + case 2:/*YUV422*/ + second_prefilter422_up1(image, 1, ty); + second_prefilter422_up1(image, 2, ty); + break; + default: + for (ch = 1 ; ch < image->num_channels ; ch += 1) + second_prefilter444_up1(image, ch, ty); + break; + } +} + +static void dclphp_unshuffle(int*data, int dclp_count) +{ + int buf[256]; + int idx, jdx; + + for (idx = 0 ; idx < dclp_count ; idx += 1) { + buf[idx] = data[idx*16]; + + for (jdx = 1 ; jdx < 16 ; jdx += 1) { + buf[16 + 15*idx + jdx-1] = data[16*idx+jdx]; + } + } + + for (idx = 0 ; idx < 16+15*dclp_count ; idx += 1) + data[idx] = buf[idx]; +} + +static void PCT_stage1_up2(jxr_image_t image, int ch, int ty) +{ + int tx = 0; + int use_my = image->cur_my + 2; + int mx; + int dclp_count; + + /* make adjustments based on tiling */ + if (use_my >= image->tile_row_height[ty]) { + use_my -= image->tile_row_height[ty]; + ty += 1; + if (use_my >= image->tile_row_height[ty]) { + use_my -= image->tile_row_height[ty]; + ty += 1; + } + } + + dclp_count = 16; + if (ch>0 && image->use_clr_fmt == 2/*YUV422*/) + dclp_count = 8; + else if (ch>0 && image->use_clr_fmt == 1/*YUV420*/) + dclp_count = 4; + + for (mx = 0 ; mx < (int) EXTENDED_WIDTH_BLOCKS(image) ; mx += 1) { + int jdx; + int hp_quant_raw; + int hp_quant; + for (jdx = 0 ; jdx < 16*dclp_count ; jdx += 16) { +#if defined(DETAILED_DEBUG) + { + int pix; + DEBUG(" DC-LP-HP (strip=%3d, mbx=%4d ch=%d, block=%2d) pre-PCT:", + use_my, mx, ch, jdx/16); + for (pix = 0; pix < 16 ; pix += 1) { + DEBUG(" 0x%08x", image->strip[ch].up2[mx].data[jdx+pix]); + if (pix%4 == 3 && pix != 15) + DEBUG("\n%*s:", 55, ""); + } + DEBUG("\n"); + } +#endif + _jxr_4x4PCT(image->strip[ch].up2[mx].data+jdx); + +#if defined(DETAILED_DEBUG) + { + int pix; + DEBUG(" DC-LP-HP (strip=%3d, mbx=%4d ch=%d, block=%2d) PCT:", + use_my, mx, ch, jdx/16); + for (pix = 0; pix < 16 ; pix += 1) { + DEBUG(" 0x%08x", image->strip[ch].up2[mx].data[jdx+pix]); + if (pix%4 == 3 && pix != 15) + DEBUG("\n%*s:", 51, ""); + } + DEBUG("\n"); + } +#endif + } + + dclphp_unshuffle(image->strip[ch].up2[mx].data, dclp_count); + + hp_quant_raw = w_guess_hp_quant(image, ch, tx, ty, mx, use_my); + hp_quant = _jxr_quant_map(image, hp_quant_raw, 1); + assert(hp_quant > 0); + + DEBUG(" DC-LP-HP (mx=%d ch=%d) use_hp_quant=%d (hp quant index=%u raw=%d)\n", mx, ch, + hp_quant, _jxr_select_hp_index(image, tx, ty, mx, use_my), hp_quant_raw); + + for (jdx = 0 ; jdx < dclp_count ; jdx += 1) { + int k; + for (k = 0 ; k < 15 ; k += 1) { + int value; + CHECK1(image->lwf_test, MACROBLK_UP2_HP(image,ch,tx,mx,jdx,k)); + value = MACROBLK_UP2_HP(image,ch,tx,mx,jdx,k); + MACROBLK_UP2_HP(image,ch,tx,mx,jdx,k) = quantize_lphp(value, hp_quant); + } +#if defined(DETAILED_DEBUG) + { + int pix; + DEBUG(" DC-LP-HP (strip=%3d, mbx=%4d ch=%d, block=%2d) Quantized: 0x%08x", + use_my, mx, ch, jdx, MACROBLK_UP2_LP(image,ch,tx,mx,jdx)); + for (pix = 1; pix < 16 ; pix += 1) { + DEBUG(" 0x%08x", MACROBLK_UP2_HP(image,ch,tx,mx,jdx,pix-1)); + if (pix%4 == 3 && pix != 15) + DEBUG("\n%*s:", 57, ""); + } + DEBUG("\n"); + } +#endif + } + } +} + +/* +* Calcualte the value of MBDCMode, which defines the prediction for +* the macroblock. There is one MBDCMode value for all the components, +* and will take into account some of the chroma planes if it makes +* sense. +* +* Note that CUR is before UP1 in the stream, and UP1 is the strip +* that is being worked on. +*/ +static int w_calculate_mbdc_mode(jxr_image_t image, int tx, int mx, int my) +{ + /* The context. */ + long left = MACROBLK_UP1(image, 0, tx, mx-1).pred_dclp[0]; + long top = MACROBLK_CUR(image, 0, tx, mx).pred_dclp[0]; + long topleft = MACROBLK_CUR(image, 0, tx, mx-1).pred_dclp[0]; + long strhor = 0; + long strvert = 0; + + if (mx == 0 && my == 0) + return 3; /* No prediction. */ + + if (mx == 0) + return 1; /* Predictions from top only. */ + + if (my == 0) + return 0; /* prediction from left only */ + + /* Calculate horizontal and vertical "strengths". We will use + those strengths to decide which direction prediction should + be. */ + if (image->use_clr_fmt==0 || image->use_clr_fmt==6) {/* YONLY or NCOMPONENT */ + + /* YONLY and NCOMPONENT use only the context of channel-0 + to calculate the strengths. */ + strhor = labs(topleft - left); + strvert = labs(topleft - top); + + } else { + /* YUV4XX and YUVK also include the U and V channels to + calculate the strengths. Note that YUVK (CMYK) + ignores the K channel so that all color images are + processed the same, generally. */ + long left_u = MACROBLK_UP1(image, 1, tx, mx-1).pred_dclp[0]; + long top_u = MACROBLK_CUR(image, 1, tx, mx).pred_dclp[0]; + long topleft_u = MACROBLK_CUR(image, 1, tx, mx-1).pred_dclp[0]; + long left_v = MACROBLK_UP1(image, 2, tx, mx-1).pred_dclp[0]; + long top_v = MACROBLK_CUR(image, 2, tx, mx).pred_dclp[0]; + long topleft_v = MACROBLK_CUR(image, 2, tx, mx-1).pred_dclp[0]; + + long scale = 2; + if (image->use_clr_fmt == 2 /*YUV422*/) + scale = 4; + if (image->use_clr_fmt == 1 /*YUV420*/) + scale = 8; + + strhor = labs(topleft - left)*scale + labs(topleft_u - left_u) + labs(topleft_v - left_v); + strvert = labs(topleft - top)*scale + labs(topleft_u - top_u) + labs(topleft_v - top_v); + } + + if ((strhor*4) < strvert) + return 1; + + if ((strvert*4) < strhor) + return 0; + + return 2; +} + +/* +* Do DC-LP prediction on the UP1 strip. The CUR strip has already +* been processed (and (rotated down from UP1) so CUR is earlier in +* the image stream and is the top context for the prediction. +*/ +static void w_predict_up1_dclp(jxr_image_t image, int tx, int ty, int mx) +{ + int my = image->cur_my + 1; + int mblp_mode; + unsigned char mblp_index; + int mbdc_mode; + int ch; + + /* make adjustments based on tiling */ + if (my == image->tile_row_height[ty]) { + my = 0; + ty += 1; + } + + /* Calculate the mbcd prediction mode. This mode is used for + all the planes of DC data. */ + mbdc_mode = w_calculate_mbdc_mode(image, tx, mx, my); + /* Now process all the planes of DC data. */ + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + long left = mx>0? MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[0] : 0; + long top = MACROBLK_CUR(image,ch,tx,mx).pred_dclp[0]; + + DEBUG(" MBDC_MODE=%d for TX=%d, MBx=%d, MBy=%d, ch=%d, left=0x%lx, top=0x%lx, cur=0x%x\n", + mbdc_mode, tx, mx, my, ch, left, top, MACROBLK_UP_DC(image,ch,tx,mx)); + + /* Save this unpredicted DC value for later prediction steps. */ + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[0] = MACROBLK_UP_DC(image,ch,tx,mx); + + /* Perform the actual DC prediction. */ + switch (mbdc_mode) { + case 0: /* left */ + MACROBLK_UP_DC(image,ch,tx,mx) -= left; + break; + case 1: /* top */ + MACROBLK_UP_DC(image,ch,tx,mx) -= top; + break; + case 2:/* top and left */ + /* Note that we really MEAN >>1 and NOT /2. in + particular, if the sum is -1, we want the + result to also be -1. That extra stuff after + the "|" is there to make sure the sign bit is + not lost. Also, the chroma planes for YUV42X + formats round *up* the mean, where all other + planes round down. */ + if (ch>0 && (image->use_clr_fmt==1/*YUV420*/||image->use_clr_fmt==2/*YUV422*/)) + MACROBLK_UP_DC(image,ch,tx,mx) -= (left+top+1) >> 1 | ((left+top+1)&~INT_MAX); + else + MACROBLK_UP_DC(image,ch,tx,mx) -= (left+top) >> 1 | ((left+top)&~INT_MAX); + break; + default: + break; + } + CHECK1(image->lwf_test, MACROBLK_UP_DC(image,ch,tx,mx)); + + } + + /* The MBLPMode decides the LP prediction within the + macroblock. It is generally the same as the prediction + direction for DC in the macroblock, but we modify it based + on the MBLP QP Index. In particular, if MBDC mode is + predicting from the left, bug the MBLP QP Index from the + left is different from that of the current MB, then cancel + prediction. Same for prediction from above. */ + mblp_mode = 2; + mblp_index = _jxr_select_lp_index(image, tx, ty, mx, my); + if (mbdc_mode == 0) { + unsigned char mblp_index_left = _jxr_select_lp_index(image, tx, ty, mx-1, my); + if (mblp_index == mblp_index_left) + mblp_mode = 0; + else + mblp_mode = 2; + + DEBUG(" MBLP_MODE=%d for MBx=%d, MBy=%d (lp_quant=%d,lp_quant_ctx=%d)\n", mblp_mode, mx, my, + mblp_index, mblp_index_left); + + } else if (mbdc_mode == 1) { + unsigned char mblp_index_up = _jxr_select_lp_index(image, tx, ty, mx, my-1); + if (mblp_index == mblp_index_up) + mblp_mode = 1; + else + mblp_mode = 2; + + DEBUG(" MBLP_MODE=%d for MBx=%d, MBy=%d (lp_quant=%d,lp_quant_ctx=%d)\n", mblp_mode, mx, my, + mblp_index, mblp_index_up); + } else { + + mblp_mode = 2; + DEBUG(" MBLP_MODE=%d for MBx=%d, MBy=%d (lp_quant=%d,lp_quant_ctx=-1)\n", mblp_mode, mx, my, + mblp_index); + } + + w_predict_lp444(image, tx, mx, my, 0, mblp_mode); + for (ch = 1 ; ch < image->num_channels ; ch += 1) { + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + w_predict_lp420(image, tx, mx, my, ch, mblp_mode); + break; + case 2: /* YUV422 */ + w_predict_lp422(image, tx, mx, my, ch, mblp_mode, mbdc_mode); + break; + default: + w_predict_lp444(image,tx, mx, my, ch, mblp_mode); + break; + } + } +} + +static int w_calculate_mbhp_mode_up1(jxr_image_t image, int tx, int mx) +{ + long strength_hor = 0; + long strength_ver = 0; + const long orientation_weight = 4; + + /* Add up the LP magnitudes along the top edge */ + strength_hor += abs(MACROBLK_UP_LP(image, 0, tx, mx, 0)); + strength_hor += abs(MACROBLK_UP_LP(image, 0, tx, mx, 1)); + strength_hor += abs(MACROBLK_UP_LP(image, 0, tx, mx, 2)); + + /* Add up the LP magnitudes along the left edge */ + strength_ver += abs(MACROBLK_UP_LP(image, 0, tx, mx, 3)); + strength_ver += abs(MACROBLK_UP_LP(image, 0, tx, mx, 7)); + strength_ver += abs(MACROBLK_UP_LP(image, 0, tx, mx, 11)); + + switch (image->use_clr_fmt) { + case 0: /*YONLY*/ + case 6: /*NCOMPONENT*/ + break; + case 3: /*YUV444*/ + case 4: /*YUVK */ + strength_hor += abs(MACROBLK_UP_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_UP_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_UP_LP(image, 1, tx, mx, 3)); + strength_ver += abs(MACROBLK_UP_LP(image, 2, tx, mx, 3)); + break; + case 2: /*YUV422*/ + strength_hor += abs(MACROBLK_UP_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_UP_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_UP_LP(image, 1, tx, mx, 1)); + strength_ver += abs(MACROBLK_UP_LP(image, 2, tx, mx, 1)); + strength_hor += abs(MACROBLK_UP_LP(image, 1, tx, mx, 4)); + strength_hor += abs(MACROBLK_UP_LP(image, 2, tx, mx, 4)); + strength_ver += abs(MACROBLK_UP_LP(image, 1, tx, mx, 5)); + strength_ver += abs(MACROBLK_UP_LP(image, 2, tx, mx, 5)); + break; + case 1: /*YUV420*/ + strength_hor += abs(MACROBLK_UP_LP(image, 1, tx, mx, 0)); + strength_hor += abs(MACROBLK_UP_LP(image, 2, tx, mx, 0)); + strength_ver += abs(MACROBLK_UP_LP(image, 1, tx, mx, 1)); + strength_ver += abs(MACROBLK_UP_LP(image, 2, tx, mx, 1)); + break; + default: + assert(0); + } + + if (strength_hor * orientation_weight < strength_ver) + return 0; /* predict from left */ + if (strength_ver * orientation_weight < strength_hor) + return 1; /* predict from top */ + + /* There is no strong weight from top or left, so do not + bother with prediction. */ + return 2; +} + +static void w_predict_up1_hp(jxr_image_t image, int ch, int tx, int mx, int mbhp_pred_mode) +{ + if (mbhp_pred_mode == 0) { /* Prediction left to right */ + int idx; + for (idx = 15 ; idx > 0 ; idx -= 1) { + if (idx%4 == 0) + continue; + + MACROBLK_UP1_HP(image,ch,tx,mx,idx, 3) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-1, 3); + MACROBLK_UP1_HP(image,ch,tx,mx,idx, 7) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-1, 7); + MACROBLK_UP1_HP(image,ch,tx,mx,idx,11) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-1,11); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,ch,tx,mx,idx, 3), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 7), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 11)); + } + } else if (mbhp_pred_mode == 1) { /* Prediction top to bottom */ + int idx; + for (idx = 15 ; idx >= 4 ; idx -= 1) { + MACROBLK_UP1_HP(image,ch,tx,mx,idx,0) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-4,0); + MACROBLK_UP1_HP(image,ch,tx,mx,idx,1) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-4,1); + MACROBLK_UP1_HP(image,ch,tx,mx,idx,2) -= MACROBLK_UP1_HP(image,ch,tx,mx,idx-4,2); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,ch,tx,mx,idx, 0), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 1), MACROBLK_CUR_HP(image,ch,tx,mx,idx, 2)); + } + } + + switch (image->use_clr_fmt) { + case 1:/*YUV420*/ + assert(ch == 0); + if (mbhp_pred_mode == 0) { + int idx; + for (idx = 3 ; idx > 0 ; idx -= 2) { + MACROBLK_UP1_HP(image,1,tx,mx,idx,3) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,3); + MACROBLK_UP1_HP(image,2,tx,mx,idx,3) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,3); + MACROBLK_UP1_HP(image,1,tx,mx,idx,7) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,7); + MACROBLK_UP1_HP(image,2,tx,mx,idx,7) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,7); + MACROBLK_UP1_HP(image,1,tx,mx,idx,11)-= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,11); + MACROBLK_UP1_HP(image,2,tx,mx,idx,11)-= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,11); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 3), MACROBLK_CUR_HP(image,1,tx,mx,idx, 7), MACROBLK_CUR_HP(image,1,tx,mx,idx, 11)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 3), MACROBLK_CUR_HP(image,2,tx,mx,idx, 7), MACROBLK_CUR_HP(image,2,tx,mx,idx, 11)); + } + } else if (mbhp_pred_mode == 1) { + int idx; + for (idx = 3 ; idx >= 2 ; idx -= 1) { + MACROBLK_UP1_HP(image,1,tx,mx,idx,0) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,0); + MACROBLK_UP1_HP(image,2,tx,mx,idx,0) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,0); + MACROBLK_UP1_HP(image,1,tx,mx,idx,1) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,1); + MACROBLK_UP1_HP(image,2,tx,mx,idx,1) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,1); + MACROBLK_UP1_HP(image,1,tx,mx,idx,2) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,2); + MACROBLK_UP1_HP(image,2,tx,mx,idx,2) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,2); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 0), MACROBLK_CUR_HP(image,1,tx,mx,idx, 1), MACROBLK_CUR_HP(image,1,tx,mx,idx, 2)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 0), MACROBLK_CUR_HP(image,2,tx,mx,idx, 1), MACROBLK_CUR_HP(image,2,tx,mx,idx, 2)); + } + } + break; + + case 2:/*YUV422*/ + assert(ch == 0); + if (mbhp_pred_mode == 0) { + int idx; + for (idx = 7 ; idx > 0 ; idx -= 2) { + MACROBLK_UP1_HP(image,1,tx,mx,idx,3) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,3); + MACROBLK_UP1_HP(image,2,tx,mx,idx,3) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,3); + MACROBLK_UP1_HP(image,1,tx,mx,idx,7) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,7); + MACROBLK_UP1_HP(image,2,tx,mx,idx,7) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,7); + MACROBLK_UP1_HP(image,1,tx,mx,idx,11)-= MACROBLK_UP1_HP(image,1,tx,mx,idx-1,11); + MACROBLK_UP1_HP(image,2,tx,mx,idx,11)-= MACROBLK_UP1_HP(image,2,tx,mx,idx-1,11); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 3), MACROBLK_CUR_HP(image,1,tx,mx,idx, 7), MACROBLK_CUR_HP(image,1,tx,mx,idx, 11)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 3), MACROBLK_CUR_HP(image,2,tx,mx,idx, 7), MACROBLK_CUR_HP(image,2,tx,mx,idx, 11)); + } + } else if (mbhp_pred_mode == 1) { + int idx; + for (idx = 7; idx >= 2 ; idx -= 1) { + MACROBLK_UP1_HP(image,1,tx,mx,idx,0) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,0); + MACROBLK_UP1_HP(image,2,tx,mx,idx,0) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,0); + MACROBLK_UP1_HP(image,1,tx,mx,idx,1) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,1); + MACROBLK_UP1_HP(image,2,tx,mx,idx,1) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,1); + MACROBLK_UP1_HP(image,1,tx,mx,idx,2) -= MACROBLK_UP1_HP(image,1,tx,mx,idx-2,2); + MACROBLK_UP1_HP(image,2,tx,mx,idx,2) -= MACROBLK_UP1_HP(image,2,tx,mx,idx-2,2); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,1,tx,mx,idx, 0), MACROBLK_CUR_HP(image,1,tx,mx,idx, 1), MACROBLK_CUR_HP(image,1,tx,mx,idx, 2)); + CHECK3(image->lwf_test, MACROBLK_CUR_HP(image,2,tx,mx,idx, 0), MACROBLK_CUR_HP(image,2,tx,mx,idx, 1), MACROBLK_CUR_HP(image,2,tx,mx,idx, 2)); + } + } +#if defined(DETAILED_DEBUG) && 0 + { + int idx; + for (idx = 0 ; idx < 8 ; idx += 1) { + int k; + DEBUG(" HP val difference[ch=1, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_UP1_HP(image,1,tx,mx,idx,k-1)); + } + DEBUG("\n"); + DEBUG(" HP val difference[ch=2, tx=%u, mx=%d, block=%d] ==", tx, mx, idx); + for (k = 1 ; k<16; k+=1) { + DEBUG(" 0x%x", MACROBLK_UP1_HP(image,2,tx,mx,idx,k-1)); + } + DEBUG("\n"); + } + } +#endif + break; + default: + break; + } +} + +static void w_predict_lp444(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) +{ + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1] = MACROBLK_UP_LP(image,ch,tx,mx,0); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[2] = MACROBLK_UP_LP(image,ch,tx,mx,1); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[3] = MACROBLK_UP_LP(image,ch,tx,mx,2); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[4] = MACROBLK_UP_LP(image,ch,tx,mx,3); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[5] = MACROBLK_UP_LP(image,ch,tx,mx,7); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[6] = MACROBLK_UP_LP(image,ch,tx,mx,11); + +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Predicted:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP1(image,ch,tx,mx).pred_dclp[0]); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 45, ""); + } + DEBUG("\n"); + } +#endif + + switch (mblp_mode) { + case 0: /* left */ + MACROBLK_UP_LP(image,ch,tx,mx,3) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[4]; + MACROBLK_UP_LP(image,ch,tx,mx,7) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[5]; + MACROBLK_UP_LP(image,ch,tx,mx,11) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[6]; + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,7), MACROBLK_CUR_LP(image,ch,tx,mx,11)); + break; + case 1: /* up */ + MACROBLK_UP_LP(image,ch,tx,mx,0) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1]; + MACROBLK_UP_LP(image,ch,tx,mx,1) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[2]; + MACROBLK_UP_LP(image,ch,tx,mx,2) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[3]; + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,2)); + break; + case 2: + break; + } +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Difference:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 15 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 14) + DEBUG("\n%*s:", 46, ""); + } + DEBUG("\n"); + } +#endif +} + +static void w_predict_lp422(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode, int mbdc_mode) +{ + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1] = MACROBLK_UP_LP(image,ch,tx,mx,0); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[2] = MACROBLK_UP_LP(image,ch,tx,mx,1); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[4] = MACROBLK_UP_LP(image,ch,tx,mx,3); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[5] = MACROBLK_UP_LP(image,ch,tx,mx,4); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[6] = MACROBLK_UP_LP(image,ch,tx,mx,5); + +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Predicted:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP1(image,ch,tx,mx).pred_dclp[0]); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 45, ""); + } + DEBUG("\n"); + } +#endif + switch (mblp_mode) { + case 0: /* left */ + MACROBLK_UP_LP(image,ch,tx,mx,3) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[4]; + MACROBLK_UP_LP(image,ch,tx,mx,1) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[2]; + MACROBLK_UP_LP(image,ch,tx,mx,5) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[6]; + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,1), MACROBLK_CUR_LP(image,ch,tx,mx,5)); + break; + case 1: /* up */ + MACROBLK_UP_LP(image,ch,tx,mx,3) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[4]; + MACROBLK_UP_LP(image,ch,tx,mx,0) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[5]; + MACROBLK_UP_LP(image,ch,tx,mx,4) -= MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1]; + CHECK3(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,3), MACROBLK_CUR_LP(image,ch,tx,mx,0), MACROBLK_CUR_LP(image,ch,tx,mx,4)); + break; + case 2: + if (mbdc_mode == 1) { + MACROBLK_UP_LP(image,ch,tx,mx,4) -= MACROBLK_UP_LP(image,ch,tx,mx,0); + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,4)); + } + break; + } +#if defined(DETAILED_DEBUG) + { + int jdx; + DEBUG(" DC/LP (strip=%3d, mbx=%4d, ch=%d) Difference:", my, mx, ch); + DEBUG(" 0x%08x", MACROBLK_UP_DC(image,ch,tx,mx)); + for (jdx = 0; jdx < 7 ; jdx += 1) { + DEBUG(" 0x%08x", MACROBLK_UP_LP(image,ch,tx,mx,jdx)); + if ((jdx+1)%4 == 3 && jdx != 6) + DEBUG("\n%*s:", 46, ""); + } + DEBUG("\n"); + } +#endif +} + +static void w_predict_lp420(jxr_image_t image, int tx, int mx, int my, int ch, int mblp_mode) +{ + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[1] = MACROBLK_UP_LP(image,ch,tx,mx,0); + MACROBLK_UP1(image,ch,tx,mx).pred_dclp[2] = MACROBLK_UP_LP(image,ch,tx,mx,1); + + switch (mblp_mode) { + case 0: /* left */ + MACROBLK_UP_LP(image,ch,tx,mx,1) -= MACROBLK_UP1(image,ch,tx,mx-1).pred_dclp[2]; + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,1)); + break; + case 1: /* up */ + MACROBLK_UP_LP(image,ch,tx,mx,0) -= MACROBLK_CUR(image,ch,tx,mx).pred_dclp[1]; + CHECK1(image->lwf_test, MACROBLK_CUR_LP(image,ch,tx,mx,0)); + break; + } +} + +/* +* This calculations the HP CBP for the macroblock. It also calculates +* and saves the HP model_bits values for this block and stores them +* away in the macroblock for later use by the MB_HP formatter. +*/ +static void calculate_hpcbp_up1(jxr_image_t image, int tx, int ty, int mx) +{ + int use_my = image->cur_my + 1; + int lap_mean[2]; + int ch; + + /* make adjustments based on tiling */ + if (use_my == image->tile_row_height[ty]) { + use_my = 0; + ty += 1; + } + + if (_jxr_InitContext(image, tx, ty, mx, use_my)) { + _jxr_InitializeModelMB(&image->model_hp, 2/*band=HP*/); + } + + lap_mean[0] = 0; + lap_mean[1] = 0; + + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + int chroma_flag = (ch>0)? 1 : 0; + unsigned model_bits = image->model_hp.bits[chroma_flag]; + + int cbp_mask = 0; + + int blk_count = 16; + int blk; + if (chroma_flag && image->use_clr_fmt==2/*YUV422*/) + blk_count = 8; + if (chroma_flag && image->use_clr_fmt==1/*YUV420*/) + blk_count = 4; + + for (blk = 0 ; blk < blk_count ; blk += 1) { + int bpos = blk; + int idx; + if (blk_count==16) + bpos = _jxr_hp_scan_map[bpos]; + for (idx = 0 ; idx < 15 ; idx += 1) { + int value = MACROBLK_UP1_HP(image,ch,tx,mx,bpos,idx); + value = abs(value) >> model_bits; + if (value != 0) { + cbp_mask |= 1<<blk; + lap_mean[chroma_flag] += 1; + } + } + } + + MACROBLK_UP1_HPCBP(image, ch, tx, mx) = cbp_mask; + } + + MACROBLK_UP1(image,0,tx,mx).hp_model_bits[0] = image->model_hp.bits[0]; + MACROBLK_UP1(image,0,tx,mx).hp_model_bits[1] = image->model_hp.bits[1]; + + DEBUG(" MP_HP: lap_mean={%u, %u}, model_hp.bits={%u %u}, model_hp.state={%d %d}\n", + lap_mean[0], lap_mean[1], + image->model_hp.bits[0], image->model_hp.bits[1], + image->model_hp.state[0], image->model_hp.state[1]); + + _jxr_UpdateModelMB(image, lap_mean, &image->model_hp, 2/*band=HP*/); + + DEBUG(" MP_HP: Updated: lap_mean={%u, %u}, model_hp.bits={%u %u}, model_hp.state={%d %d}\n", + lap_mean[0], lap_mean[1], + image->model_hp.bits[0], image->model_hp.bits[1], + image->model_hp.state[0], image->model_hp.state[1]); + +} + +static void w_PredCBP(jxr_image_t image, unsigned tx, unsigned ty, unsigned mx) +{ + int use_my = image->cur_my+1; + int ch; + if (use_my == image->tile_row_height[ty]) { + use_my = 0; + ty += 1; + } + + if (_jxr_InitContext(image, tx, ty, mx, use_my)) { + _jxr_InitializeCBPModel(image); + } + + switch (image->use_clr_fmt) { + case 1: /* YUV420 */ + _jxr_w_PredCBP444(image, 0, tx, mx, use_my); + _jxr_w_PredCBP420(image, 1, tx, mx, use_my); + _jxr_w_PredCBP420(image, 2, tx, mx, use_my); + break; + case 2: /* YUV422 */ + _jxr_w_PredCBP444(image, 0, tx, mx, use_my); + _jxr_w_PredCBP422(image, 1, tx, mx, use_my); + _jxr_w_PredCBP422(image, 2, tx, mx, use_my); + break; + default: + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + DEBUG(" PredCBP: Predicted HPCBP[ch=%d]: 0x%04x\n", + ch, MACROBLK_UP1_HPCBP(image,ch,tx,mx)); + _jxr_w_PredCBP444(image, ch, tx, mx, use_my); + } + break; + } +} + + +/* +* $Log: w_strip.c,v $ +* Revision 1.50 2009/09/16 12:00:00 microsoft +* Reference Software v1.8 updates. +* +* Revision 1.49 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.48 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.47 2008/03/24 18:06:56 steve +* Imrpove DEBUG messages around quantization. +* +* Revision 1.46 2008/03/21 18:05:53 steve +* Proper CMYK formatting on input. +* +* Revision 1.45 2008/03/21 00:08:56 steve +* Handle missing LP/HP QP maps. +* +* Revision 1.44 2008/03/20 22:39:41 steve +* Fix various debug prints of QP data. +* +* Revision 1.43 2008/03/20 18:11:50 steve +* Clarify MBLPMode calculations. +* +* Revision 1.42 2008/03/19 00:35:28 steve +* Fix MBLPMode prediction during distributed QP +* +* Revision 1.41 2008/03/18 21:09:12 steve +* Fix distributed color prediction. +* +* Revision 1.40 2008/03/18 18:36:56 steve +* Support compress of CMYK images. +* +* Revision 1.39 2008/03/14 17:08:51 gus +* *** empty log message *** +* +* Revision 1.38 2008/03/14 16:10:47 steve +* Clean up some signed/unsigned warnings. +* +* Revision 1.37 2008/03/14 00:54:09 steve +* Add second prefilter for YUV422 and YUV420 encode. +* +* Revision 1.36 2008/03/14 00:12:00 steve +* Fix YUV420 UV subsampling at bottom of MB. +* +* Revision 1.35 2008/03/13 23:46:24 steve +* First level filter encoding. +* +* Revision 1.34 2008/03/13 21:23:27 steve +* Add pipeline step for YUV420. +* +* Revision 1.33 2008/03/13 18:56:37 steve +* Fix compile-time support for dumb 422-to-420 +* +* Revision 1.32 2008/03/13 18:52:01 steve +* Pipeline 422 to 420 handling. +* +* Revision 1.31 2008/03/13 18:37:45 steve +* Better YUV422 to YUV420 scaling +* +* Revision 1.30 2008/03/13 17:49:31 steve +* Fix problem with YUV422 CBP prediction for UV planes +* +* Add support for YUV420 encoding. +* +* Revision 1.29 2008/03/13 00:07:23 steve +* Encode HP of YUV422 +* +* Revision 1.28 2008/03/12 21:10:27 steve +* Encode LP of YUV422 +* +* Revision 1.27 2008/03/12 00:39:11 steve +* Rework yuv444_to_yuv422 to match WmpEncApp. +* +* Revision 1.26 2008/03/11 22:12:49 steve +* Encode YUV422 through DC. +* +* Revision 1.25 2008/03/06 02:05:49 steve +* Distributed quantization +* +* Revision 1.24 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.23 2008/03/03 02:04:05 steve +* Get encoding of BD16 correct. +* +* Revision 1.22 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.21 2008/02/04 19:21:36 steve +* Fix rounding of scaled chroma DC/LP values. +* +* Revision 1.20 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.19 2008/01/08 23:56:22 steve +* Add remaining 444 overlap filtering. +* +* Revision 1.18 2008/01/08 01:06:20 steve +* Add first pass overlap filtering. +* +* Revision 1.17 2008/01/05 01:19:55 steve +* Use secret-handshake version of quantization. +* +* Revision 1.16 2008/01/04 22:48:55 steve +* Quantization division rounds, not truncates. +* +* Revision 1.15 2008/01/04 17:07:36 steve +* API interface for setting QP values. +* +* Revision 1.14 2008/01/03 18:07:31 steve +* Detach prediction mode calculations from prediction. +* +* Revision 1.13 2008/01/01 01:07:26 steve +* Add missing HP prediction. +* +* Revision 1.12 2007/12/30 00:16:00 steve +* Add encoding of HP values. +* +* Revision 1.11 2007/12/17 23:02:57 steve +* Implement MB_CBP encoding. +* +* Revision 1.10 2007/12/14 17:10:39 steve +* HP CBP Prediction +* +* Revision 1.9 2007/12/12 00:38:07 steve +* Encode LP data. +* +* Revision 1.8 2007/12/07 16:34:52 steve +* Use repeat bytes to pad to MB boundary. +* +* Revision 1.7 2007/12/06 17:54:59 steve +* Fix input data block ordering. +* +* Revision 1.6 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.5 2007/11/26 01:47:16 steve +* Add copyright notices per MS request. +* +* Revision 1.4 2007/11/16 20:03:58 steve +* Store MB Quant, not qp_index. +* +* Revision 1.3 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +* Revision 1.2 2007/11/09 22:15:41 steve +* DC prediction for the encoder. +* +* Revision 1.1 2007/11/09 01:18:59 steve +* Stub strip input processing. +* +*/ + diff --git a/jpegxr/w_tile_frequency.c b/jpegxr/w_tile_frequency.c new file mode 100644 index 000000000..c379a0646 --- /dev/null +++ b/jpegxr/w_tile_frequency.c @@ -0,0 +1,306 @@ +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: w_tile_frequency.c,v 1.1 2009/03/09 12:00:00 dan Exp $") +#else +#ident "$Id: w_tile_frequency.c,v 1.1 2009/03/09 21:00:00 dan Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + +void _jxr_w_TILE_DC(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned tile_idx; + unsigned mx, my; + unsigned mb_height; + unsigned mb_width; + uint8_t bands_present; + DEBUG("START TILE_DC at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_wbitstream_bitpos(str)); + + bands_present = image->bands_present_of_primary; + + /* TILE_STARTCODE == 1 */ + DEBUG(" DC_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x01); + _jxr_wbitstream_uint8(str, 0x00); /* ARBITRARY_BYTE */ + + /* Write out the tile header (which includes sub-headers for + all the major passes). */ + + _jxr_w_TILE_HEADER_DC(image, str, 0, tx, ty); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_TILE_HEADER_DC(image->alpha, str, 1, tx, ty); + } + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + DEBUG(" TILE_DC at [%d %d] is %u x %u MBs\n", tx, ty, mb_width, mb_height); + for (my = 0 ; my < mb_height ; my += 1) { + + _jxr_wflush_mb_strip(image, tx, ty, my, 1); + + for (mx = 0 ; mx < mb_width ; mx += 1) { + + _jxr_w_MB_DC(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_MB_DC(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my); + } + } + } + + tile_idx = ty * image->tile_columns + tx; + + _jxr_wbitstream_syncbyte(str); + _jxr_wbitstream_flush(str); + DEBUG("END TILE_DC\n"); +} + +void _jxr_w_TILE_LP(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned tile_idx; + unsigned mx, my; + unsigned mb_height; + unsigned mb_width; + uint8_t bands_present; + DEBUG("START TILE_LP at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_wbitstream_bitpos(str)); + + bands_present = image->bands_present_of_primary; + + if (bands_present < 3 /* LOWPASS */) { + /* TILE_STARTCODE == 1 */ + DEBUG(" LP_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x01); + _jxr_wbitstream_uint8(str, 0x00); /* ARBITRARY_BYTE */ + + _jxr_w_TILE_HEADER_LOWPASS(image, str, 0, tx, ty); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty); + } + } + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + DEBUG(" TILE_LP at [%d %d] is %u x %u MBs\n", tx, ty, mb_width, mb_height); + for (my = 0 ; my < mb_height ; my += 1) { + + _jxr_wflush_mb_strip(image, tx, ty, my, 0); + + for (mx = 0 ; mx < mb_width ; mx += 1) { + + if (bands_present<3 /* LOWPASS */) { + if (image->num_lp_qps>1 && !image->lp_use_dc_qp) { + unsigned qp_index = _jxr_select_lp_index(image, tx,ty,mx,my); + DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", image->num_lp_qps, qp_index); + _jxr_w_ENCODE_QP_INDEX(image, str, tx, ty, mx, my, image->num_lp_qps, qp_index); + } + + _jxr_w_MB_LP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_MB_LP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my); + } + } + } + } + + tile_idx = ty * image->tile_columns + tx; + + _jxr_wbitstream_syncbyte(str); + _jxr_wbitstream_flush(str); + DEBUG("END TILE_LP\n"); +} + +void _jxr_w_TILE_HP_FLEX(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned tile_idx; + uint8_t bands_present ; + struct wbitstream strFP; + FILE*fdFP; + unsigned mx, my; + unsigned mb_height; + unsigned mb_width; + DEBUG("START TILE_HP_FLEX at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_wbitstream_bitpos(str)); + + bands_present = image->bands_present_of_primary; + + fdFP = fopen("fp.tmp", "wb"); + _jxr_wbitstream_initialize(&strFP, fdFP); + + if (bands_present < 2 /* HIGHPASS */) { + /* TILE_STARTCODE == 1 */ + DEBUG(" HP_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x01); + _jxr_wbitstream_uint8(str, 0x00); /* ARBITRARY_BYTE */ + + _jxr_w_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty); + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty); + } + } + + if (bands_present == 0 /* ALL */) { + /* TILE_STARTCODE == 1 */ + DEBUG(" FLEX_TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(&strFP)); + _jxr_wbitstream_uint8(&strFP, 0x00); + _jxr_wbitstream_uint8(&strFP, 0x00); + _jxr_wbitstream_uint8(&strFP, 0x01); + _jxr_wbitstream_uint8(&strFP, 0x00); /* ARBITRARY_BYTE */ + + if (TRIM_FLEXBITS_FLAG(image)) { + _jxr_wbitstream_uint4(&strFP, image->trim_flexbits); + } + } + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + DEBUG(" TILE_HP_FLEX at [%d %d] is %u x %u MBs\n", tx, ty, mb_width, mb_height); + for (my = 0 ; my < mb_height ; my += 1) { + + _jxr_wflush_mb_strip(image, tx, ty, my, 0); + + for (mx = 0 ; mx < mb_width ; mx += 1) { + + if (bands_present<2 /* HIGHPASS */) { + if (image->num_hp_qps>1 && !image->hp_use_lp_qp) { + unsigned qp_index = _jxr_select_hp_index(image, tx,ty,mx,my); + DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", image->num_hp_qps, qp_index); + _jxr_w_ENCODE_QP_INDEX(image, str, tx, ty, mx, my, image->num_hp_qps, qp_index); + } + + _jxr_w_MB_CBP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my); + if (bands_present == 0 /* ALL */) { + _jxr_w_MB_HP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my, &strFP); + } + else { + _jxr_w_MB_HP(image, str, 0 /* IsCurrPlaneAlphaFlag = FALSE */, tx, ty, mx, my, 0); + } + + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_MB_CBP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my); + if (bands_present == 0 /* ALL */) { + _jxr_w_MB_HP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my, &strFP); + } + else { + _jxr_w_MB_HP(image->alpha, str, 1 /* IsCurrPlaneAlphaFlag = TRUE */, tx, ty, mx, my, 0); + } + } + } + } + } + + tile_idx = ty * image->tile_columns + tx; + + _jxr_wbitstream_syncbyte(str); + _jxr_wbitstream_flush(str); + image->tile_index_table[tile_idx * (4 - bands_present) + 2] = str->write_count; + + _jxr_wbitstream_syncbyte(&strFP); + _jxr_wbitstream_flush(&strFP); + fclose(fdFP); + if (bands_present == 0 /* ALL */) { + struct rbitstream strFPRead; + FILE*fdFPRead = fopen("fp.tmp", "rb"); + size_t idx; + _jxr_rbitstream_initialize(&strFPRead, fdFPRead); + + for (idx = 0; idx < strFP.write_count; idx++) { + _jxr_wbitstream_uint8(str, _jxr_rbitstream_uint8(&strFPRead)); + } + fclose(fdFPRead); + _jxr_wbitstream_flush(str); + image->tile_index_table[tile_idx * (4 - bands_present) + 3] = str->write_count; + } + /* delete file associated with CodedTiles */ + remove("fp.tmp"); + + _jxr_wbitstream_flush(str); + DEBUG("END TILE_HP_FLEX\n"); +} + +/* +* $Log: w_tile_frequency.c,v $ +* Revision 1.2 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.1 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +*/ + diff --git a/jpegxr/w_tile_spatial.c b/jpegxr/w_tile_spatial.c new file mode 100644 index 000000000..fbc942d60 --- /dev/null +++ b/jpegxr/w_tile_spatial.c @@ -0,0 +1,306 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +**********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: w_tile_spatial.c,v 1.47 2008/03/20 18:11:25 steve Exp $") +#else +#ident "$Id: w_tile_spatial.c,v 1.47 2008/03/20 18:11:25 steve Exp $" +#endif + +# include "jxr_priv.h" +# include <stdlib.h> +# include <assert.h> + + +void _jxr_w_TILE_SPATIAL(jxr_image_t image, struct wbitstream*str, + unsigned tx, unsigned ty) +{ + unsigned mx, my; + unsigned plane_idx, num_planes; + unsigned mb_height; + unsigned mb_width; + DEBUG("START TILE_SPATIAL at tile=[%u %u] bitpos=%zu\n", tx, ty, _jxr_wbitstream_bitpos(str)); + + /* TILE_STARTCODE == 1 */ + DEBUG(" TILE_STARTCODE at bitpos=%zu\n", _jxr_wbitstream_bitpos(str)); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x00); + _jxr_wbitstream_uint8(str, 0x01); + _jxr_wbitstream_uint8(str, 0x00); /* ARBITRARY_BYTE */ + + if (TRIM_FLEXBITS_FLAG(image)) { + _jxr_wbitstream_uint4(str, image->trim_flexbits); + } + + /* Write out the tile header (which includes sub-headers for + all the major passes). */ + + _jxr_w_TILE_HEADER_DC(image, str, 0, tx, ty); + if (image->bands_present != 3 /* DCONLY */) { + _jxr_w_TILE_HEADER_LOWPASS(image, str, 0, tx, ty); + + if (image->bands_present != 2 /* NO_HIGHPASS */) { + _jxr_w_TILE_HEADER_HIGHPASS(image, str, 0, tx, ty); + } + } + + if (ALPHACHANNEL_FLAG(image)) { + _jxr_w_TILE_HEADER_DC(image->alpha, str, 1, tx, ty); + if (image->bands_present != 3 /* DCONLY */) { + _jxr_w_TILE_HEADER_LOWPASS(image->alpha, str, 1, tx, ty); + + if (image->bands_present != 2 /* NO_HIGHPASS */) { + _jxr_w_TILE_HEADER_HIGHPASS(image->alpha, str, 1, tx, ty); + } + } + } + + + /* Now form and write out all the compressed data for the + tile. This involves scanning the macroblocks, and the + blocks within the macroblocks, generating bits as we go. */ + + mb_height = EXTENDED_HEIGHT_BLOCKS(image); + mb_width = EXTENDED_WIDTH_BLOCKS(image); + + if (TILING_FLAG(image)) { + mb_height = image->tile_row_height[ty]; + mb_width = image->tile_column_width[tx]; + } + + DEBUG(" TILE_SPATIAL at [%d %d] is %u x %u MBs\n", tx, ty, mb_width, mb_height); + num_planes = ((ALPHACHANNEL_FLAG(image)) ? 2 : 1); + + for (my = 0 ; my < mb_height ; my += 1) { + + _jxr_wflush_mb_strip(image, tx, ty, my, 1); + + for (mx = 0 ; mx < mb_width ; mx += 1) + for (plane_idx = 0; plane_idx < num_planes; plane_idx ++) { + + jxr_image_t plane = (plane_idx == 0 ? image : image->alpha); + if (plane->bands_present!=3) { + if (plane->num_lp_qps>1 && !plane->lp_use_dc_qp) { + unsigned qp_index = _jxr_select_lp_index(plane, tx,ty,mx,my); + DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", plane->num_lp_qps, qp_index); + _jxr_w_ENCODE_QP_INDEX(plane, str, tx, ty, mx, my, plane->num_lp_qps, qp_index); + } + if (plane->bands_present!=2 && plane->num_hp_qps>1 && !plane->hp_use_lp_qp) { + unsigned qp_index = _jxr_select_hp_index(plane, tx,ty,mx,my); + DEBUG(" DECODE_QP_INDEX(%d) --> %u\n", plane->num_hp_qps, qp_index); + _jxr_w_ENCODE_QP_INDEX(plane, str, tx, ty, mx, my, plane->num_hp_qps, qp_index); + } + } + + _jxr_w_MB_DC(plane, str, 0, tx, ty, mx, my); + if (plane->bands_present != 3 /* DCONLY */) { + _jxr_w_MB_LP(plane, str, 0, tx, ty, mx, my); + if (plane->bands_present != 2 /* NOHIGHPASS */) { + _jxr_w_MB_CBP(plane, str, 0, tx, ty, mx, my); + _jxr_w_MB_HP(plane, str, 0, tx, ty, mx, my, 0); + + /* In SPATIAL mode, the MB_HP block + will include the FLEXBITS. DO NOT + include the MB_FLEXBITS separately. */ + } + } + } + } + + _jxr_wbitstream_syncbyte(str); + _jxr_wbitstream_flush(str); + DEBUG("END TILE_SPATIAL\n"); +} + + +/* +* $Log: w_tile_spatial.c,v $ +* Revision 1.49 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.48 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.47 2008/03/20 18:11:25 steve +* Handle case of NumLPQP==1 and NumHPQPS>1 +* +* Revision 1.46 2008/03/18 18:36:56 steve +* Support compress of CMYK images. +* +* Revision 1.45 2008/03/13 17:49:31 steve +* Fix problem with YUV422 CBP prediction for UV planes +* +* Add support for YUV420 encoding. +* +* Revision 1.44 2008/03/13 00:07:23 steve +* Encode HP of YUV422 +* +* Revision 1.43 2008/03/12 21:10:27 steve +* Encode LP of YUV422 +* +* Revision 1.42 2008/03/06 22:47:40 steve +* Clean up parsing/encoding of QP counts +* +* Revision 1.41 2008/03/06 19:21:59 gus +* *** empty log message *** +* +* Revision 1.40 2008/03/06 02:05:49 steve +* Distributed quantization +* +* Revision 1.39 2008/03/05 00:31:18 steve +* Handle UNIFORM/IMAGEPLANE_UNIFORM compression. +* +* Revision 1.38 2008/02/28 18:50:31 steve +* Portability fixes. +* +* Revision 1.37 2008/02/26 23:52:44 steve +* Remove ident for MS compilers. +* +* Revision 1.36 2008/02/24 17:42:33 steve +* Remove dead code. +* +* Revision 1.35 2008/02/23 01:55:52 steve +* CBP REFINE is more complex when CHR is involved. +* +* Revision 1.34 2008/02/22 23:54:15 steve +* Encode large NUM_BLKCBP values. +* +* Revision 1.33 2008/02/22 23:08:15 steve +* Remove dead code. +* +* Revision 1.32 2008/02/22 23:01:33 steve +* Compress macroblock HP CBP packets. +* +* Revision 1.31 2008/02/05 23:18:26 steve +* Fix cbplp encoding is backwards. +* +* Revision 1.30 2008/02/05 19:14:42 steve +* Encode LP values of YUV444 data. +* +* Revision 1.29 2008/02/01 22:49:53 steve +* Handle compress of YUV444 color DCONLY +* +* Revision 1.28 2008/01/07 16:18:54 steve +* Shift out trimmed flexbits. +* +* Revision 1.27 2008/01/06 01:29:28 steve +* Add support for TRIM_FLEXBITS in compression. +* +* Revision 1.26 2008/01/05 02:11:54 steve +* Add FLEXBITS support. +* +* Revision 1.25 2008/01/04 19:34:05 steve +* Fix DecNumBlkCBP table adaptation. +* +* Revision 1.24 2008/01/03 18:07:31 steve +* Detach prediction mode calculations from prediction. +* +* Revision 1.23 2008/01/02 21:13:58 steve +* Extract HP model bits accounts for sign. +* +* Revision 1.22 2008/01/02 21:02:55 steve +* Account for model_bits while encoding HP values. +* +* Revision 1.21 2008/01/01 23:13:00 steve +* Fix AdaptiveHPPermute totals counting. +* +* Revision 1.20 2008/01/01 01:07:26 steve +* Add missing HP prediction. +* +* Revision 1.19 2007/12/30 00:16:00 steve +* Add encoding of HP values. +* +* Revision 1.18 2007/12/17 23:02:57 steve +* Implement MB_CBP encoding. +* +* Revision 1.17 2007/12/14 21:33:39 steve +* Process LPInput values in sign-magnitude form. +* +* Revision 1.16 2007/12/14 17:10:39 steve +* HP CBP Prediction +* +* Revision 1.15 2007/12/13 19:27:36 steve +* Careful of small negative LP values that are all refinement. +* +* Revision 1.14 2007/12/13 18:01:09 steve +* Stubs for HP encoding. +* +* Revision 1.13 2007/12/12 00:38:07 steve +* Encode LP data. +* +* Revision 1.12 2007/12/07 01:20:34 steve +* Fix adapt not adapting on line ends. +* +* Revision 1.11 2007/12/06 23:12:41 steve +* Stubs for LP encode operations. +* +* Revision 1.10 2007/12/06 17:55:30 steve +* Fix AbsLevelInd tabel select and adaptation. +* +* Revision 1.9 2007/12/05 02:18:01 steve +* Formatting of nil LP values. +* +* Revision 1.8 2007/12/04 23:44:02 steve +* Calculation of encoded IS_DC_CH accounts for sign. +* +* Revision 1.7 2007/12/04 22:06:10 steve +* Infrastructure for encoding LP. +* +* Revision 1.6 2007/11/30 01:50:58 steve +* Compression of DCONLY GRAY. +* +* Revision 1.5 2007/11/26 01:47:16 steve +* Add copyright notices per MS request. +* +* Revision 1.4 2007/11/09 01:18:59 steve +* Stub strip input processing. +* +* Revision 1.3 2007/11/08 19:38:38 steve +* Get stub DCONLY compression to work. +* +* Revision 1.2 2007/11/08 02:52:33 steve +* Some progress in some encoding infrastructure. +* +* Revision 1.1 2007/06/06 17:19:13 steve +* Introduce to CVS. +* +*/ + diff --git a/jpegxr/x_strip.c b/jpegxr/x_strip.c new file mode 100644 index 000000000..6e047ec52 --- /dev/null +++ b/jpegxr/x_strip.c @@ -0,0 +1,86 @@ + +/************************************************************************* +* +* This software module was originally contributed by Microsoft +* Corporation in the course of development of the +* ITU-T T.832 | ISO/IEC 29199-2 ("JPEG XR") format standard for +* reference purposes and its performance may not have been optimized. +* +* This software module is an implementation of one or more +* tools as specified by the JPEG XR standard. +* +* ITU/ISO/IEC give You a royalty-free, worldwide, non-exclusive +* copyright license to copy, distribute, and make derivative works +* of this software module or modifications thereof for use in +* products claiming conformance to the JPEG XR standard as +* specified by ITU-T T.832 | ISO/IEC 29199-2. +* +* ITU/ISO/IEC give users the same free license to this software +* module or modifications thereof for research purposes and further +* ITU/ISO/IEC standardization. +* +* Those intending to use this software module in products are advised +* that its use may infringe existing patents. ITU/ISO/IEC have no +* liability for use of this software module or modifications thereof. +* +* Copyright is not released for products that do not conform to +* to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* Microsoft Corporation retains full right to modify and use the code +* for its own purpose, to assign or donate the code to a third party, +* and to inhibit third parties from using the code for products that +* do not conform to the JPEG XR standard as specified by ITU-T T.832 | +* ISO/IEC 29199-2. +* +* This copyright notice must be included in all copies or derivative +* works. +* +* Copyright (c) ITU-T/ISO/IEC 2008, 2009. +***********************************************************************/ + +#ifdef _MSC_VER +#pragma comment (user,"$Id: x_strip.c,v 1.4 2008/03/05 06:58:10 gus Exp $") +#else +#ident "$Id: x_strip.c,v 1.4 2008/03/05 06:58:10 gus Exp $" +#endif + +# include "jxr_priv.h" +# include <assert.h> + +void _jxr_clear_strip_cur(jxr_image_t image) +{ + int ch; + assert(image->num_channels > 0); + for (ch = 0 ; ch < image->num_channels ; ch += 1) { + unsigned idx; + for (idx = 0 ; idx < EXTENDED_WIDTH_BLOCKS(image) ; idx += 1) { + int jdx; + for (jdx = 0 ; jdx < 256 ; jdx += 1) + image->strip[ch].cur[idx].data[jdx] = 0; + } + } +} + +/* +* $Log: x_strip.c,v $ +* Revision 1.6 2009/05/29 12:00:00 microsoft +* Reference Software v1.6 updates. +* +* Revision 1.5 2009/04/13 12:00:00 microsoft +* Reference Software v1.5 updates. +* +* Revision 1.4 2008/03/05 06:58:10 gus +* *** empty log message *** +* +* Revision 1.3 2008/02/26 23:52:45 steve +* Remove ident for MS compilers. +* +* Revision 1.2 2007/11/26 01:47:16 steve +* Add copyright notices per MS request. +* +* Revision 1.1 2007/11/12 23:21:55 steve +* Infrastructure for frequency mode ordering. +* +*/ + |