diff --git a/CMakeLists.txt b/CMakeLists.txt index 01f622c0..ad098cba 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -1,6 +1,7 @@ cmake_minimum_required(VERSION 2.8) project( CTL ) +set( CMAKE_MACOSX_RPATH 1 ) set( CTL_MAJOR_VERSION 1 ) set( CTL_MINOR_VERSION 5 ) set( CTL_PATCH_VERSION 0 ) @@ -84,6 +85,7 @@ install( FILES "${PROJECT_BINARY_DIR}/CTLConfig.cmake" "${PROJECT_BINARY_DIR}/CTLConfigVersion.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) -install(FILES "${PROJECT_BINARY_DIR}/CTLLibraryDepends.cmake" DESTINATION - "${INSTALL_CMAKE_DIR}" COMPONENT dev) +# install(FILES "${PROJECT_BINARY_DIR}/CTLLibraryDepends.cmake" DESTINATION "${INSTALL_CMAKE_DIR}" COMPONENT dev) +install(EXPORT ctlrendertargets DESTINATION + "${INSTALL_CMAKE_DIR}" COMPONENT dev) diff --git a/ctlrender/CMakeLists.txt b/ctlrender/CMakeLists.txt index 9fced147..dfdd4a2c 100644 --- a/ctlrender/CMakeLists.txt +++ b/ctlrender/CMakeLists.txt @@ -17,7 +17,7 @@ include_directories( ${AcesContainer_INCLUDE_DIRS} ) link_directories( ${AcesContainer_LIBRARY_DIRS} ) endif() -include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/lib/IlmCtl" "${PROJECT_SOURCE_DIR}/lib/IlmCtlMath" "${PROJECT_SOURCE_DIR}/lib/IlmCtlSimd" "${PROJECT_SOURCE_DIR}/lib/dpx" ) +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" "${PROJECT_SOURCE_DIR}/lib/IlmCtl" "${PROJECT_SOURCE_DIR}/lib/IlmCtlMath" "${PROJECT_SOURCE_DIR}/lib/IlmCtlSimd" "${PROJECT_SOURCE_DIR}/lib/dpx" "${PROJECT_SOURCE_DIR}/lib/adx") add_executable( ctlrender main.cc @@ -25,13 +25,14 @@ add_executable( ctlrender usage.cc aces_file.cc dpx_file.cc + adx_file.cc exr_file.cc tiff_file.cc format.cc compression.cc ) -target_link_libraries( ctlrender IlmCtlSimd IlmCtlMath IlmCtl ctldpx ${IlmBase_LIBRARIES} ) +target_link_libraries( ctlrender IlmCtlSimd IlmCtlMath IlmCtl ctldpx ctladx ${IlmBase_LIBRARIES} ) target_link_libraries( ctlrender ${IlmBase_LDFLAGS_OTHER} ) if (TIFF_FOUND) target_link_libraries( ctlrender ${TIFF_LIBRARIES} ) @@ -47,3 +48,6 @@ target_link_libraries( ctlrender ${AcesContainer_LDFLAGS_OTHER} ) endif() install( TARGETS ctlrender DESTINATION bin ) +install( TARGETS ctlrender DESTINATION lib EXPORT ctlrendertargets) + + diff --git a/ctlrender/adx_file.cc b/ctlrender/adx_file.cc new file mode 100644 index 00000000..80abd01b --- /dev/null +++ b/ctlrender/adx_file.cc @@ -0,0 +1,294 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include "adx_file.hh" + +#include +#include +#include + +template +ctl::dpx::fb* prepareADX(const char *inputFile, + float input_scale, + ctl::dpx::fb *image_buffer, + format_t *image_format) +{ + // Looking for compatibility then print WARNING if necessary + std::map MI = dpx_read_details_for_adx_int(inputFile, input_scale, + image_buffer, image_format); + std::map MF = dpx_read_details_for_adx_float(inputFile, input_scale, + image_buffer, image_format); + + unsigned long nan_f = static_cast(ctl::adx::udf32f); + float32_t nan_vf = *(float32_t *)&nan_f; + + if (MI["18"] > 2 ) { + fprintf(stderr, + "WARNING: This Image May Contain More than 2 Elments\n" + "Elements Beyond the 2nd One Will be Removed! \n"); + } + + if (MI["18"] >= 1){ + if (MI["21.6"] != 50 + && MI["21.6"] != 51 + && MI["21.6"] != 52 + && MI["21.6"] != 53) { +// THROW(Iex::ArgExc, "Error: The Program does not Currently Support This Format.\n"); + fprintf(stderr, + "WARNING: The Program does not Currently Support This Format.\n"); + + } + else if(MI["21.6"] == 157){ + fprintf(stderr, + "WARNING: The Image is Currently in XYZ Space\n" + ", ctlrender will Treat and Process \n" + "it as it was in RGB Space.\n"); + + } + image_buffer->channelAdjust(uint8_t(MI["21.6"])); + } + + if (MI["21.1"] != 0x0 && MI["21.1"]) { + fprintf(stderr, + "WARNING: adx 21.1 Data Sign shall be Unsigned\n"); + } + if (MI["22.1"] != 0x0 && MI["22.1"]) { + fprintf(stderr, + "WARNING: adx 22.1 Data Sign shall be Unsigned\n"); + } + + if (MI["21.2"] != 0x0 && MI["21.2"]) { + fprintf(stderr, + "WARNING: adx 21.2 Reference Low Data code shall be 0\n"); + } + if (MI["22.2"] != 0x0 && MI["22.2"]) { + fprintf(stderr, + "WARNING: adx 22.2 Reference Low Data code shall be 0\n"); + } + + if (MF["21.3"] != nan_vf + && MF["21.3"]) { + fprintf(stderr, + "WARNING: adx 21.3 Reference Low Quality shall be Undefined\n"); + } + if (MF["22.3"] != nan_vf + && MF["22.3"]) { + fprintf(stderr, + "WARNING: adx 22.3 Reference Low Quality shall be Undefined\n"); + } + + if(MI["21.9"] != 16 && MI["21.9"] != 10) { +// THROW(Iex::ArgExc, "ERROR: The Program is Currently Supporting ADX with Bit Depth " +// "of 10 and 16 on the First Element) \n"); + fprintf(stderr, + "WARNING: The Program is Currently Supporting ADX with Bit Depth " + "of 10 and 16 on the First Element. \n"); + } + + if(MI["18"] > 1 + && MI["22.6"] != 4) { +// THROW(Iex::ArgExc, "ERROR: The Program is Currently Supporting Alpha/Matte " +// "on the Second Element. \n"); + fprintf(stderr, + "WARNING: The Program is Currently Supporting Alpha/Matte " + "on the Second Element. \n"); + } + else if(MI["18"] > 1 + && MI["22.6"] == 4 + && MI["22.9"] != 16 + && MI["22.9"] != 10 + && MI["22.9"] != 8 + && MI["22.9"] != 1){ + THROW(Iex::ArgExc, "ERROR: The Program is Currently Supporting ADX with Bit Depth of \n" + " 1, 8, 10 and 16 on the Second Element) \n"); + } + + if (MI["21.4"] + && MI["21.4"] != 65535 + && MI["21.9"] == 16) { + fprintf(stderr, + "WARNING: adx 21.4 Reference high data for ADX16 shall be 65535\n"); + } + if (MI["21.4"] + && MI["21.4"] != 1023 + && MI["21.9"] == 10) { + fprintf(stderr, + "WARNING: adx 21.4 Reference high data for ADX10 shall be 1023\n"); + } + + if (MI["18"] == 2) { + if( MI["22.9"] == 16 + && MI["22.4"] != 65535) { + fprintf(stderr, + "WARNING: adx 22.4 Reference high data for ADX16 shall be 65535\n"); + } + if ( MI["22.9"] == 10 + && MI["22.4"] != 1023) { + fprintf(stderr, + "WARNING: adx 22.4 Reference high data for ADX10 shall be 1023\n"); + } + if ( MI["22.9"] == 8 + && MI["22.4"] != 255) { + fprintf(stderr, + "WARNING: adx 22.4 Reference high data for ADX8 shall be 255\n"); + } + if ( MI["22.9"] == 1 + && MI["22.4"] != 1) { + fprintf(stderr, + "WARNING: adx 22.4 Reference high data for ADX1 shall be 1\n"); + } + } + + if (MF["21.5"] != nan_vf + && MF["21.5"]) { + fprintf(stderr, + "WARNING: adx 21.5 Reference high quality shall be Undefined\n"); + } + if (MF["22.5"] != nan_vf + && MF["22.5"]) { + fprintf(stderr, + "WARNING: adx 22.5 Reference high quality shall be Undefined\n"); + } + + if (MI["21.7"] != 13 && MI["21.7"]) { + fprintf(stderr, + "WARNING: adx 21.7 Transfer characteristic shall be ADX\n"); + } + if (MI["22.7"] != 0 && MI["22.7"]) { + fprintf(stderr, + "WARNING: adx 22.2 Transfer characteristic shall be User-defined\n"); + } + + if (MI["21.8"] != 13 && MI["21.8"]) { + fprintf(stderr, + "WARNING: adx 21.8 Colorimetric characteristic shall be ADX\n"); + } + if (MI["22.8"] != 0 && MI["22.8"]) { + fprintf(stderr, + "WARNING: adx 22.2 Colorimetric characteristic shall be User-defined\n"); + } + + if (MI["21.10"] + && MI["21.10"] != 0x0 + && MI["21.9"] == 16) { + fprintf(stderr, + "WARNING: adx 21.10 Packing for ADX16 shall be 0\n"); + } + else if (MI["21.10"] + && MI["21.10"] != 0x1 + && MI["21.9"] == 10) { + fprintf(stderr, + "WARNING: adx 21.10 Packing for ADX10 shall be 1\n"); + } + + if (MI["18"] == 2 + && MI["22.10"] != 0x0 + && (MI["22.9"] == 16 + || MI["22.9"] == 8 + || MI["22.9"] == 1)) { + fprintf(stderr, + "WARNING: adx 22.10 Packing for ADX16/8/1 shall be 0\n"); + } + else if (MI["18"] == 2 + && MF["22.10"] != 0x1 + && MF["22.9"] == 10) { + fprintf(stderr, + "WARNING: adx 22.10 Packing for ADX10 shall be 1\n"); + } + + fprintf(stderr, + "\n"); + + return image_buffer; +} + +template ctl::dpx::fb* prepareADX(const char *inputFile, + float input_scale, + ctl::dpx::fb *image_buffer, + format_t *image_format); + +bool adx_read(const char *name, float scale, ctl::dpx::fb *pixels, + format_t *format) { + std::ifstream file; + ctl::adx adxheader; + + file.open(name); + + if(!ctl::adx::check_magic(&file)) { + return 0; + } + + adxheader.read(&file); + adxheader.read(&file, 0, pixels, scale); + + format->src_bps=adxheader.elements[0].bits_per_sample; + pixels->swizzle(adxheader.elements[0].descriptor, FALSE); + + return 1; +} + +void adx_write(const char *name, float scale, const ctl::dpx::fb &pixels, + format_t *format) { + std::ofstream file; + ctl::adx adxheader; + + file.open(name); + + adxheader.elements[0].data_sign=0; + adxheader.elements[0].bits_per_sample=format->bps; + + adxheader.write(&file, 0, pixels, scale); + adxheader.write(&file); +} + diff --git a/ctlrender/adx_file.hh b/ctlrender/adx_file.hh new file mode 100644 index 00000000..784b3d10 --- /dev/null +++ b/ctlrender/adx_file.hh @@ -0,0 +1,73 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#if !defined(CTL_UTIL_CTLRENDER_ADX_INCLUDE) +#define CTL_UTIL_CTLRENDER_ADX_INCLUDE + +#include +#include +#include "main.hh" + +template +ctl::dpx::fb* prepareADX(const char *inputFile, + float input_scale, + ctl::dpx::fb *image_buffer, + format_t *image_format); +bool adx_read(const char *name, float scale, + ctl::dpx::fb *pixels, + format_t *format); +void adx_write(const char *name, float scale, + const ctl::dpx::fb &pixels, + format_t *format); +#endif diff --git a/ctlrender/dpx_file.cc b/ctlrender/dpx_file.cc index 978129fe..dc8b059f 100644 --- a/ctlrender/dpx_file.cc +++ b/ctlrender/dpx_file.cc @@ -77,6 +77,82 @@ bool dpx_read(const char *name, float scale, ctl::dpx::fb *pixels, return 1; } +std::map dpx_read_details_for_adx_int(const char *name, + float scale, + ctl::dpx::fb *pixels, + format_t *format) { + std::ifstream file; + ctl::dpx dpxheader; + std::map M; + + file.open(name); + + dpxheader.read(&file); +// dpxheader.read(&file, 0, pixels, scale); + + M["18"] = static_cast(dpxheader.number_of_elements); + M["21.1"] = static_cast(dpxheader.elements[0].data_sign); + M["21.2"] = static_cast(dpxheader.elements[0].ref_low_data_code); + M["21.4"] = static_cast(dpxheader.elements[0].ref_high_data_code); + M["21.6"] = static_cast(dpxheader.elements[0].descriptor); + M["21.7"] = static_cast(dpxheader.elements[0].transfer_characteristic); + M["21.8"] = static_cast(dpxheader.elements[0].colorimetric_characteristic); + M["21.9"] = static_cast(dpxheader.elements[0].bits_per_sample); + M["21.10"] = static_cast(dpxheader.elements[0].packing); + + if (static_cast(dpxheader.number_of_elements) > 1){ + M["22.1"] = static_cast(dpxheader.elements[1].data_sign); + M["21.2"] = static_cast(dpxheader.elements[1].ref_low_data_code); + M["21.4"] = static_cast(dpxheader.elements[1].ref_high_data_code); + M["22.6"] = static_cast(dpxheader.elements[1].descriptor); + M["22.7"] = static_cast(dpxheader.elements[1].transfer_characteristic); + M["22.8"] = static_cast(dpxheader.elements[1].colorimetric_characteristic); + M["22.9"] = static_cast(dpxheader.elements[1].bits_per_sample); + M["22.10"] = static_cast(dpxheader.elements[1].packing); + } + + M["60"] = static_cast(dpxheader.interlace); + M["61"] = static_cast(dpxheader.field_number); + M["62"] = static_cast(dpxheader.video_standard); + + return M; +} + +std::map dpx_read_details_for_adx_float(const char *name, + float scale, + ctl::dpx::fb *pixels, + format_t *format) { + std::ifstream file; + ctl::dpx dpxheader; + std::map M; + + file.open(name); + + dpxheader.read(&file); +// dpxheader.read(&file, 0, pixels, scale); + + M["21.3"] = static_cast(dpxheader.elements[0].ref_low_quantity); + M["21.5"] = static_cast(dpxheader.elements[0].ref_high_quantity); + + if (static_cast(dpxheader.number_of_elements) > 1){ + M["22.3"] = static_cast(dpxheader.elements[1].ref_low_quantity); + M["22.5"] = static_cast(dpxheader.elements[1].ref_high_quantity); + } + + M["64"] = static_cast(dpxheader.horizontal_sampling_rate); + M["65"] = static_cast(dpxheader.vertical_sampling_rate); + M["66"] = static_cast(dpxheader.temporal_sampling_rate); + M["67"] = static_cast(dpxheader.time_offset_sync_to_first_pixel); + M["68"] = static_cast(dpxheader.gamma); + M["69"] = static_cast(dpxheader.black_level_code); + M["70"] = static_cast(dpxheader.black_gain); + M["71"] = static_cast(dpxheader.breakpoint); + M["72"] = static_cast(dpxheader.white_level_code); + M["73"] = static_cast(dpxheader.integration_time); + + return M; +} + void dpx_write(const char *name, float scale, const ctl::dpx::fb &pixels, format_t *format) { std::ofstream file; @@ -86,6 +162,7 @@ void dpx_write(const char *name, float scale, const ctl::dpx::fb &pixels, dpxheader.elements[0].data_sign=0; dpxheader.elements[0].bits_per_sample=format->bps; + dpxheader.write(&file, 0, pixels, scale); dpxheader.write(&file); } diff --git a/ctlrender/dpx_file.hh b/ctlrender/dpx_file.hh index bcece35d..88386165 100644 --- a/ctlrender/dpx_file.hh +++ b/ctlrender/dpx_file.hh @@ -57,10 +57,18 @@ #include #include "main.hh" +#include +#include bool dpx_read(const char *name, float scale, ctl::dpx::fb *pixels, format_t *format); +std::map dpx_read_details_for_adx_int(const char *name, float scale, + ctl::dpx::fb *pixels, + format_t *format); +std::map dpx_read_details_for_adx_float(const char *name, float scale, + ctl::dpx::fb *pixels, + format_t *format); void dpx_write(const char *name, float scale, const ctl::dpx::fb &pixels, format_t *format); diff --git a/ctlrender/main.cc b/ctlrender/main.cc index 152bc13e..40f951db 100644 --- a/ctlrender/main.cc +++ b/ctlrender/main.cc @@ -139,6 +139,9 @@ file_format_t allowed_formats[] = { "dpx10", format_t("dpx", 10) }, { "dpx12", format_t("dpx", 12) }, { "dpx16", format_t("dpx", 16) }, + { "adx", format_t("adx", 10) }, + { "adx10", format_t("adx", 10) }, + { "adx16", format_t("adx", 16) }, { "tif", format_t("tif", 0) }, { "tiff", format_t("tiff", 0) }, { "tiff32", format_t("tiff", 32) }, @@ -293,8 +296,8 @@ int main(int argc, const char **argv) "the -format option requires an additional " "argument specifying the destination file\nformat. " "this may be one of the following: 'dpx10', 'dpx16', " - "'aces', 'tiff8',\n'tiff16', or 'exr'.\nSee '-help " - "format' for more details.\n"); + "'adx10', 'adx16', 'aces', 'tiff8', 'tiff16', " + "or 'exr'.\nSee '-help format' for more details.\n"); exit(1); } desired_format = find_format(argv[1]," for parameter '-format'.\nSee '-help format' for more details."); @@ -560,8 +563,13 @@ int main(int argc, const char **argv) // HACK aces format file type check const char *ext = desired_format.ext; static const char exrext[] = "exr"; + static const char dpxext[] = "dpx"; + if (!strcmp(ext, "aces")) ext = exrext; + if (!strcmp(ext, "adx")) + ext = dpxext; + if (strcmp(ext, dot + 1) && !force_overwrite_output_file) { fprintf(stderr, diff --git a/ctlrender/transform.cc b/ctlrender/transform.cc index e8f1a960..fbede270 100644 --- a/ctlrender/transform.cc +++ b/ctlrender/transform.cc @@ -54,10 +54,12 @@ #include "transform.hh" #include "dpx_file.hh" +#include "adx_file.hh" #include "tiff_file.hh" #include "exr_file.hh" #include "aces_file.hh" #include +#include #include #include #include @@ -334,7 +336,6 @@ void run_ctl_transform(const ctl_operation_t &ctl_operation, CTLResults *ctl_res try { - name = (char *) alloca(strlen(ctl_operation.filename)+1); memset(name, 0, strlen(ctl_operation.filename) + 1); strcpy(name, ctl_operation.filename); @@ -756,6 +757,7 @@ void transform(const char *inputFile, const char *outputFile, } if (!dpx_read(inputFile, input_scale, &image_buffer, image_format) && + !adx_read(inputFile, input_scale, &image_buffer, image_format) && !exr_read(inputFile, input_scale, &image_buffer, image_format) && !tiff_read(inputFile, input_scale, &image_buffer, image_format)) { @@ -827,21 +829,16 @@ void transform(const char *inputFile, const char *outputFile, image_buffer.swizzle(0, TRUE); } -// std::cout << image_format->ext << std::endl; - if (!strncmp(image_format->ext, "aces", 3)) - { - aces_write(outputFile, output_scale, - image_buffer.width(), image_buffer.height(), image_buffer.depth(), - image_buffer.ptr(), image_format); - } - else if (!strncmp(image_format->ext, "exr", 3)) + if (!strncmp(image_format->ext, "aces", 3)) + { + aces_write(outputFile, output_scale, + image_buffer.width(), image_buffer.height(), image_buffer.depth(), + image_buffer.ptr(), image_format); + } + else if (!strncmp(image_format->ext, "exr", 3)) { exr_write(outputFile, output_scale, image_buffer, image_format, compression); } - else if (!strncmp(image_format->ext, "adx", 3)) - { - dpx_write(outputFile, output_scale, image_buffer, image_format); - } else if (!strncmp(image_format->ext, "dpx", 3)) { dpx_write(outputFile, output_scale, image_buffer, image_format); @@ -850,6 +847,15 @@ void transform(const char *inputFile, const char *outputFile, { tiff_write(outputFile, output_scale, image_buffer, image_format); } + else if (!strncmp(image_format->ext, "adx", 3)) + { + // Preparing adx + ctl::dpx::fb* image_buffer_adx = prepareADX(inputFile, + input_scale, + &image_buffer, + image_format); + adx_write(outputFile, output_scale, *image_buffer_adx, image_format); + } else { fprintf(stderr, "unable to write a %s file (unknown format).\n", image_format->ext); diff --git a/ctlrender/usage.cc b/ctlrender/usage.cc index 0de7eace..c5471411 100644 --- a/ctlrender/usage.cc +++ b/ctlrender/usage.cc @@ -127,6 +127,11 @@ void usage(const char *section) { " dpx Produces a DPX file with the same bit depth as the source\n" " image\n" "\n" +" adx10 Produces a ADX file with a 10 bits per sample (32 bit \n" +" packed) format\n" +"\n" +" adx16 Produces a ADX file with a 16 bits per sample format\n" +"\n" " tiff8 Produces a TIFF file in the 8 bits per sample format\n" "\n" " tiff16 Produces a TIFF file in the 16 bits per sample format\n" diff --git a/lib/CMakeLists.txt b/lib/CMakeLists.txt index bb19a9ba..d99ef495 100644 --- a/lib/CMakeLists.txt +++ b/lib/CMakeLists.txt @@ -7,6 +7,8 @@ add_subdirectory( IlmImfCtl ) endif() add_subdirectory( dpx ) +add_subdirectory( adx ) + add_custom_target( CTL DEPENDS IlmCtl IlmCtlMath IlmCtlSimd ) diff --git a/lib/adx/CMakeLists.txt b/lib/adx/CMakeLists.txt new file mode 100644 index 00000000..eca2d931 --- /dev/null +++ b/lib/adx/CMakeLists.txt @@ -0,0 +1,13 @@ +include_directories( "${CMAKE_CURRENT_SOURCE_DIR}" ) + +add_library( ctladx + adx.cc + adx_raw.cc + adx_read.cc + adx_util.cc + adx_write.cc + adx_bits.cc + adx_validate.cc + adx_rw.cc +) + diff --git a/lib/adx/adx.cc b/lib/adx/adx.cc new file mode 100644 index 00000000..a62e17ab --- /dev/null +++ b/lib/adx/adx.cc @@ -0,0 +1,846 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include "adx.hh" +#include "adx_raw.hh" +#include "adx_bits.hh" +#include + +#if !defined(TRUE) +#define TRUE 1 +#endif +#if !defined(FALSE) +#define FALSE 0 +#endif + +namespace ctl +{ + +adx::adx() { + endian_mode=default_endian_mode; + compliance=automatic; + + clear(); + + header_start=0; + _need_byteswap=FALSE; + _constraint_ok=TRUE; + current_ostream=FALSE; + current_endian_mode=default_endian_mode; + current_compliance=automatic; +} + +adx::~adx() { +} + +void adx::clear(void) { + uint8_t i; + + nullify(&magic); + magic=0x53445058; + nullify(&data_offset); + memset(header_version, 0, sizeof(header_version)); + nullify(&total_file_size); + nullify(&ditto_key); + nullify(&generic_header_length); + nullify(&industry_header_length); + nullify(&user_header_length); + + memset(filename, 0, sizeof(filename)); + memset(creation_time, 0, sizeof(creation_time)); + memset(creator, 0, sizeof(creator)); + memset(project_name, 0, sizeof(project_name)); + memset(copyright, 0, sizeof(copyright)); + nullify(&encryption_key); + + nullify(&image_orientation); + nullify(&number_of_elements); + nullify(&pixels_per_line); + nullify(&lines_per_element); + + for(i=0; i<8; i++) { + nullify(&(elements[i].data_sign)); + nullify(&(elements[i].ref_low_data_code)); + nullify(&(elements[i].ref_low_quantity)); + nullify(&(elements[i].ref_high_data_code)); + nullify(&(elements[i].ref_high_quantity)); + nullify(&(elements[i].descriptor)); + nullify(&(elements[i].transfer_characteristic)); + nullify(&(elements[i].colorimetric_characteristic)); + nullify(&(elements[i].bits_per_sample)); + nullify(&(elements[i].packing)); + nullify(&(elements[i].actual_packing)); + nullify(&(elements[i].encoding)); + nullify(&(elements[i].offset_to_data)); + nullify(&(elements[i].eol_padding)); + nullify(&(elements[i].eoi_padding)); + memset(elements[i].description, 0, sizeof(elements[i].description)); + }; + + nullify(&x_offset); + nullify(&y_offset); + nullify(&x_center); + nullify(&y_center); + nullify(&x_origional_size); + nullify(&y_origional_size); + + memset(source_filename, 0, sizeof(source_filename)); + memset(source_creation_time, 0, sizeof(source_creation_time)); + memset(input_device, 0, sizeof(input_device)); + memset(input_device_serial_number, 0, sizeof(input_device_serial_number)); + + nullify(&xl_border_validity); + nullify(&xr_border_validity); + nullify(&yt_border_validity); + nullify(&yb_border_validity); + nullify(&horizonal_par); + nullify(&vertical_par); + + nullify(&x_scanned_size); + nullify(&y_scanned_size); + + memset(keycode_film_id, 0, sizeof(keycode_film_id)); + memset(keycode_film_type_char, 0, sizeof(keycode_film_type_char)); + memset(keycode_perf_offset_char, 0, sizeof(keycode_perf_offset_char)); + memset(keycode_prefix, 0, sizeof(keycode_prefix)); + memset(keycode_count_char, 0, sizeof(keycode_count_char)); + + memset(format, 0, sizeof(format)); + nullify(&frame_position_in_sequence); + nullify(&sequence_length); + nullify(&held_count); + nullify(&frame_rate); + nullify(&shutter_angle); + memset(frame_attribute, 0, sizeof(frame_attribute)); + memset(frame_slate_info, 0, sizeof(frame_slate_info)); +// nullify(&film_gague); +// nullify(&film_orientation); +// nullify(&film_perf_per_foot); +// nullify(&film_perf_per_frame); +// memset(film_manufacturer, 0, sizeof(film_manufacturer)); +// memset(film_stock_name, 0, sizeof(film_stock_name)); + + nullify(&smpte_timecode); + nullify(&smpte_userbits); + nullify(&interlace); + nullify(&field_number); + nullify(&video_standard); + nullify(&horizontal_sampling_rate); + nullify(&vertical_sampling_rate); + nullify(&temporal_sampling_rate); + nullify(&time_offset_sync_to_first_pixel); + nullify(&gamma); + nullify(&black_level_code); + nullify(&black_gain); + nullify(&breakpoint); + nullify(&white_level_code); + nullify(&integration_time); + + memset(user_id, 0, sizeof(user_id)); +} + +bool adx::check_magic(std::istream *io) { + uint32_t magic; + std::istream::pos_type start; + + start=io->tellg(); + io->read((char *)&magic, sizeof(magic)); + io->seekg(start); + + if(magic==0x53445058 || magic==0x58504453) { + return TRUE; + } + return FALSE; +} + +bool adx::check_constraint(void) { + if (this->_constraint_ok) { + return TRUE; + } + return FALSE; +} + +void adx::read(std::istream *is) { + std::istream::pos_type start; + bool cpu_is_little_endian; + int i; + + magic=0x01020304; + cpu_is_little_endian=FALSE; + if(((const char *)&magic)[0]==0x04) { + cpu_is_little_endian=TRUE; + } + + clear(); + + header_start=is->tellg(); + magic=adxi::read_uint32(is, 0); + if(magic==0x53445058) { + _need_byteswap=FALSE; + if(cpu_is_little_endian) { + endian_mode=little_endian; + } else { + endian_mode=big_endian; + } + } else { + is->seekg(header_start); + magic=adxi::read_uint32(is, 1); + if(magic!=0x53445058) { + // XXX This is bad... Need to fail nicely.. + } + _need_byteswap=TRUE; + if(cpu_is_little_endian) { + endian_mode=big_endian; + } else { + endian_mode=little_endian; + } + } + + data_offset=adxi::read_uint32(is, _need_byteswap); + adxi::read_string(is, header_version, sizeof(header_version)); + total_file_size=adxi::read_uint32(is, _need_byteswap); + ditto_key=adxi::read_uint32(is, _need_byteswap); + generic_header_length=adxi::read_uint32(is, _need_byteswap); + industry_header_length=adxi::read_uint32(is, _need_byteswap); + user_header_length=adxi::read_uint32(is, _need_byteswap); + + adxi::read_string(is, filename, sizeof(filename)); + adxi::read_string(is, creation_time, sizeof(creation_time)); + adxi::read_string(is, creator, sizeof(creator)); + adxi::read_string(is, project_name, sizeof(project_name)); + adxi::read_string(is, copyright, sizeof(copyright)); + encryption_key=adxi::read_uint32(is, _need_byteswap); + + is->ignore(104); + + image_orientation=adxi::read_uint16(is, _need_byteswap); + number_of_elements=adxi::read_uint16(is, _need_byteswap); + pixels_per_line=adxi::read_uint32(is, _need_byteswap); + lines_per_element=adxi::read_uint32(is, _need_byteswap); + + // just read the first two elements + for(i=0; i<2; i++) { + elements[i].data_sign=adxi::read_uint32(is, _need_byteswap); + elements[i].ref_low_data_code=adxi::read_uint32(is, _need_byteswap); + elements[i].ref_low_quantity=adxi::read_float32(is, _need_byteswap); + elements[i].ref_high_data_code=adxi::read_uint32(is, _need_byteswap); + elements[i].ref_high_quantity=adxi::read_float32(is, _need_byteswap); + elements[i].descriptor=adxi::read_uint8(is, _need_byteswap); + elements[i].transfer_characteristic=adxi::read_uint8(is, _need_byteswap); + elements[i].colorimetric_characteristic=adxi::read_uint8(is, _need_byteswap); + elements[i].bits_per_sample=adxi::read_uint8(is, _need_byteswap); + elements[i].packing=adxi::read_uint16(is, _need_byteswap); + elements[i].encoding=adxi::read_uint16(is, _need_byteswap); + elements[i].offset_to_data=adxi::read_uint32(is, _need_byteswap); + if(iignore(52); + + x_offset=adxi::read_uint32(is, _need_byteswap); + y_offset=adxi::read_uint32(is, _need_byteswap); + x_center=adxi::read_float32(is, _need_byteswap); + y_center=adxi::read_float32(is, _need_byteswap); + x_origional_size=adxi::read_uint32(is, _need_byteswap); + y_origional_size=adxi::read_uint32(is, _need_byteswap); + + adxi::read_string(is, source_filename, sizeof(source_filename)); + adxi::read_string(is, source_creation_time, sizeof(source_creation_time)); + adxi::read_string(is, input_device, sizeof(input_device)); + adxi::read_string(is, input_device_serial_number, + sizeof(input_device_serial_number)); + + xl_border_validity=adxi::read_uint16(is, _need_byteswap); + xr_border_validity=adxi::read_uint16(is, _need_byteswap); + yt_border_validity=adxi::read_uint16(is, _need_byteswap); + yb_border_validity=adxi::read_uint16(is, _need_byteswap); + horizonal_par=adxi::read_uint32(is, _need_byteswap); + vertical_par=adxi::read_uint32(is, _need_byteswap); + + x_scanned_size=adxi::read_float32(is, _need_byteswap); + y_scanned_size=adxi::read_float32(is, _need_byteswap); + + is->ignore(20); + + adxi::read_string(is, keycode_film_id, sizeof(keycode_film_id)); + adxi::read_string(is, keycode_film_type_char, + sizeof(keycode_film_type_char)); + adxi::read_string(is, keycode_perf_offset_char, + sizeof(keycode_perf_offset_char)); + adxi::read_string(is, keycode_prefix, sizeof(keycode_prefix)); + adxi::read_string(is, keycode_count_char, sizeof(keycode_count_char)); + + adxi::read_string(is, format, sizeof(format)); + frame_position_in_sequence=adxi::read_uint32(is, _need_byteswap); + sequence_length=adxi::read_uint32(is, _need_byteswap); + held_count=adxi::read_uint32(is, _need_byteswap); + frame_rate=adxi::read_float32(is, _need_byteswap); + shutter_angle=adxi::read_float32(is, _need_byteswap); + adxi::read_string(is, frame_attribute, sizeof(frame_attribute)); + adxi::read_string(is, frame_slate_info, sizeof(frame_slate_info)); + film_gague=adxi::read_float32(is, _need_byteswap); + film_orientation=adxi::read_uint8(is, _need_byteswap); + film_perf_per_foot=adxi::read_uint8(is, _need_byteswap); + film_perf_per_frame=adxi::read_uint8(is, _need_byteswap); + adxi::read_string(is, film_manufacturer, sizeof(film_manufacturer)); + adxi::read_string(is, film_stock_name, sizeof(film_stock_name)); + + is->ignore(21); + + smpte_timecode=adxi::read_uint32(is, _need_byteswap); + smpte_userbits=adxi::read_uint32(is, _need_byteswap); + interlace=adxi::read_uint8(is, _need_byteswap); + field_number=adxi::read_uint8(is, _need_byteswap); + video_standard=adxi::read_uint8(is, _need_byteswap); + is->ignore(1); + horizontal_sampling_rate=adxi::read_float32(is, _need_byteswap); + vertical_sampling_rate=adxi::read_float32(is, _need_byteswap); + temporal_sampling_rate=adxi::read_float32(is, _need_byteswap); + time_offset_sync_to_first_pixel=adxi::read_float32(is, _need_byteswap); + gamma=adxi::read_float32(is, _need_byteswap); + black_level_code=adxi::read_float32(is, _need_byteswap); + black_gain=adxi::read_float32(is, _need_byteswap); + breakpoint=adxi::read_float32(is, _need_byteswap); + white_level_code=adxi::read_float32(is, _need_byteswap); + integration_time=adxi::read_float32(is, _need_byteswap); + + is->ignore(76); + adxi::read_string(is, user_id, sizeof(user_id)); + + is->seekg(header_start); + // struct tm source_creation_time_tm; + // time_t source_creation_time_time; + // uint8_t keycode_perf_offset_int; + // uint16_t keycode_film_type_int; + // uint8_t keycode_prefix_int; + // uint16_t keycode_count_int; + // uint64_t keycode_absolute_perf_offset; + // struct tm creation_time_tm; + // time_t creation_time_time; +} + +void adx::write(std::ostream *os) +{ + uint32_t _magic; + bool cpu_is_little_endian; + int i; + + _magic=0x01020304; + cpu_is_little_endian=FALSE; + if(((const char *)&_magic)[0]==0x04) { + cpu_is_little_endian=TRUE; + } + + _need_byteswap=FALSE; + if(cpu_is_little_endian != little_endian) { + _need_byteswap=TRUE; + } + + // struct tm source_creation_time_tm; + // time_t source_creation_time_time; + // uint8_t keycode_perf_offset_int; + // uint16_t keycode_film_type_int; + // uint8_t keycode_prefix_int; + // uint16_t keycode_count_int; + // uint64_t keycode_absolute_perf_offset; + // struct tm creation_time_tm; + // time_t creation_time_time; + + os->seekp(header_start, std::ios::beg); + + if(header_version[0]==0) { + if(compliance==adx1) { + strcpy(header_version, "v1.0"); + } else if(compliance==adx3) { + strcpy(header_version, "v3.0"); + } else { + // XXX invalid validation_level + } + } + + magic=0x53445058; + adxi::write_uint32(os, magic, _need_byteswap); + adxi::write_uint32(os, data_offset, _need_byteswap); + adxi::write_string(os, header_version, sizeof(header_version)); + adxi::write_uint32(os, total_file_size, _need_byteswap); + adxi::write_uint32(os, ditto_key, _need_byteswap); + adxi::write_uint32(os, generic_header_length, _need_byteswap); + adxi::write_uint32(os, industry_header_length, _need_byteswap); + adxi::write_uint32(os, user_header_length, _need_byteswap); + + adxi::write_string(os, filename, sizeof(filename)); + adxi::write_string(os, creation_time, sizeof(creation_time)); + adxi::write_string(os, creator, sizeof(creator)); + adxi::write_string(os, project_name, sizeof(project_name)); + adxi::write_string(os, copyright, sizeof(copyright)); + adxi::write_uint32(os, encryption_key, _need_byteswap); + + adxi::write_fill(os, 0x00, 104); + + adxi::write_uint16(os, image_orientation, _need_byteswap); + + // adx field 18 -> Image Elements shall be 1 or 2 + // Don't change the actual data + if(static_cast(number_of_elements) != 1 + && static_cast(number_of_elements) != 2){ + this->_constraint_ok = FALSE; + } + + if (number_of_elements <= 0x1){ + adxi::write_uint16(os, 0x1, _need_byteswap); + } + else if (number_of_elements > 0x1) { + number_of_elements = 0x2; + adxi::write_uint16(os, 0x2, _need_byteswap); + } + + adxi::write_uint32(os, pixels_per_line, _need_byteswap); + adxi::write_uint32(os, lines_per_element, _need_byteswap); + + uint8_t alphaElement = 1; + bool hasAlphaElement = 0; + for(i=0; i<8; i++) { + if (static_cast(elements[i].descriptor) == 13) { + hasAlphaElement = 1; + alphaElement = i; + } + + break; + }; + + // the First Element + // adx 21.1 Data Sign shall be Unsigned + if (elements[0].data_sign != 0x0){ + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x0, _need_byteswap); + + // adx 21.2 Reference low data code shall be 0 + if (elements[0].ref_low_data_code != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x0, _need_byteswap); + + unsigned long nan_f = static_cast(udf32f); + float32_t nan_vf = *(float32_t *)&nan_f; + + // adx 21.3 Reference low quantity represented shall be Undefined + if (elements[0].ref_low_quantity != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + // adx 21.4 Reference high data code value for ADX16 shall be 65535 / 0xFFFF + // Reference high data code value for ADX10 shall be 1023 / 0x3FF + if (elements[0].ref_high_data_code != 0xFFFF + && elements[0].ref_high_data_code != 0x3FF) { + this->_constraint_ok = FALSE; + } + + if (static_cast(elements[0].bits_per_sample) == 10){ + adxi::write_uint32(os, 0x3FF, _need_byteswap); + } + else if (static_cast(elements[0].bits_per_sample) == 16){ + adxi::write_uint32(os, 0xFFFF, _need_byteswap); + } + else { + exit(1); + } + + // adx 21.5 Reference high quantity represented shall be Undefined + if (elements[0].ref_high_quantity != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + // adx 21.6 Channel Descriptor shall be R, G, B /50(0x32) + if (static_cast(elements[0].descriptor) != 0x32){ + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, 0x32, _need_byteswap); + + // adx 21.7 Transfer characteristic shall be ADX/13(0xD) + if (static_cast(elements[0].transfer_characteristic) != 0xD){ + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, 0xD, _need_byteswap); + + // adx 21.8 Colorimetric specification shall be ADX/13(0xD) + if (static_cast(elements[0].colorimetric_characteristic) != 0xD) { + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, 0xD, _need_byteswap); + + // adx 21.9 Bit Depth shall be 16 for ADX16 and 10 for ADX10 + if (static_cast(elements[0].bits_per_sample) == 10 + || static_cast(elements[0].bits_per_sample) == 16){ + adxi::write_uint8(os, elements[0].bits_per_sample, _need_byteswap); + } + + // adx 21.10 Packing shall be 0 for ADX16 and the datum shall be packed sequentially + // 16 bits per sample (i.e. no padding shall be used) Packing shall be 1 for ADX10 and + // the datum shall be packed three samples into a 32-bit word with 2 pad bits located in LSB. + if (static_cast(elements[0].bits_per_sample) == 16) { + if (elements[0].packing != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x0, _need_byteswap); + } + else if (static_cast(elements[0].bits_per_sample) == 10) { + if (elements[0].packing != 0x1) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x1, _need_byteswap); + } + else { + adxi::write_uint16(os, elements[0].packing, _need_byteswap); + } + + + adxi::write_uint16(os, elements[0].encoding, _need_byteswap); + adxi::write_uint32(os, elements[0].offset_to_data, _need_byteswap); + adxi::write_uint32(os, elements[0].eol_padding, _need_byteswap); + adxi::write_uint32(os, elements[0].eoi_padding, _need_byteswap); + adxi::write_string(os, elements[0].description, + sizeof(elements[0].description)); + + + // The Second Element + if (hasAlphaElement) { + // adx 22.1 Data Sign shall be Unsigned + if (elements[alphaElement].data_sign != 0x0){ + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x0, _need_byteswap); + + // adx 22.2 Reference low data code shall be 0 + if (elements[alphaElement].ref_low_data_code != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x0, _need_byteswap); + + // adx 22.3 Reference low quantity represented shall be Undefined + if (elements[alphaElement].ref_low_quantity != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + // adx 22.4 Reference high data code value for ADX16 shall be 65535 / 0xFFFF for 16 + // Reference high data code value for ADX10 shall be 1023 / 0x3FF for 10 + // Reference high data code value for ADX10 shall be 255 / 0xFF for 8 + // Reference high data code value for ADX10 shall be 1 / 0x1 for 1 + if (elements[alphaElement].bits_per_sample == 16){ + if (elements[alphaElement].ref_high_data_code != 0xFFFF) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0xFFFF, _need_byteswap); + } + else if (elements[alphaElement].bits_per_sample == 10){ + if (elements[alphaElement].ref_high_data_code != 0x3FF) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x3FF, _need_byteswap); + } + else if (elements[alphaElement].bits_per_sample == 8){ + if (elements[alphaElement].ref_high_data_code != 0xFF) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0xFF, _need_byteswap); + } + else if (elements[alphaElement].bits_per_sample == 1){ + if (elements[alphaElement].ref_high_data_code != 0x1) { + this->_constraint_ok = FALSE; + } + adxi::write_uint32(os, 0x1, _need_byteswap); + } + else { + this->_constraint_ok = FALSE; + } + + // adx 22.5 Reference high quantity represented shall be Undefined + if (elements[alphaElement].ref_high_quantity != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + // adx 22.6 Channel Descriptor shall be Alpha (matte) / 4 + if (static_cast(elements[alphaElement].descriptor) != 0x4){ + exit(1); + } + adxi::write_uint8(os, 0x4, _need_byteswap); + + // adx 22.7 Transfer characteristic shall be User defined/0 + if (static_cast(elements[alphaElement].transfer_characteristic) != 0x0){ + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, 0x0, _need_byteswap); + + // adx 22.8 Colorimetric specification shall be User defined/0 + if (static_cast(elements[alphaElement].colorimetric_characteristic) != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, 0x0, _need_byteswap); + + // adx 22.9 Bit Depth shall be 1, 8, 10, or 16 + if (elements[alphaElement].bits_per_sample == 16 + || elements[alphaElement].bits_per_sample == 10 + || elements[alphaElement].bits_per_sample == 8 + || elements[alphaElement].bits_per_sample == 1) { + adxi::write_uint8(os, elements[alphaElement].bits_per_sample, _need_byteswap); + } + else { + exit(1); + } + + // adx 22.10 Padding shall be 0 when the value of 22.9 is 1, 8, or 16. + // Padding shall be 1 when the value of 22.9 is 10 and the datum shall + // be packed three samples into a 32-bit word with 2 pad bits located in LSB. + if (static_cast(elements[alphaElement].bits_per_sample) == 16) { + if (elements[alphaElement].packing != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x0, _need_byteswap); + } + else if (static_cast(elements[alphaElement].bits_per_sample) == 8) { + if (elements[alphaElement].packing != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x0, _need_byteswap); + } + else if (static_cast(elements[alphaElement].bits_per_sample) == 1) { + if (elements[alphaElement].packing != 0x0) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x0, _need_byteswap); + } + else if (static_cast(elements[alphaElement].bits_per_sample) == 10) { + if (elements[alphaElement].packing != 0x1) { + this->_constraint_ok = FALSE; + } + adxi::write_uint16(os, 0x1, _need_byteswap); + } + + adxi::write_uint16(os, elements[alphaElement].encoding, _need_byteswap); + adxi::write_uint32(os, elements[alphaElement].offset_to_data, _need_byteswap); + adxi::write_uint32(os, elements[alphaElement].eol_padding, _need_byteswap); + adxi::write_uint32(os, elements[alphaElement].eoi_padding, _need_byteswap); + adxi::write_string(os, elements[alphaElement].description, + sizeof(elements[alphaElement].description)); + + } + + for(i=0; i<8; i++) { + nullify(&(elements[i].data_sign)); + nullify(&(elements[i].ref_low_data_code)); + nullify(&(elements[i].ref_low_quantity)); + nullify(&(elements[i].ref_high_data_code)); + nullify(&(elements[i].ref_high_quantity)); + nullify(&(elements[i].descriptor)); + nullify(&(elements[i].transfer_characteristic)); + nullify(&(elements[i].colorimetric_characteristic)); + nullify(&(elements[i].bits_per_sample)); + nullify(&(elements[i].packing)); + nullify(&(elements[i].encoding)); + nullify(&(elements[i].offset_to_data)); + nullify(&(elements[i].eol_padding)); + nullify(&(elements[i].eoi_padding)); + memset(elements[i].description, 0, + sizeof(elements[i].description)); + }; + + adxi::write_fill(os, 0x00, 52); + adxi::write_uint32(os, x_offset, _need_byteswap); + adxi::write_uint32(os, y_offset, _need_byteswap); + adxi::write_float32(os, x_center, _need_byteswap); + adxi::write_float32(os, y_center, _need_byteswap); + adxi::write_uint32(os, x_origional_size, _need_byteswap); + adxi::write_uint32(os, y_origional_size, _need_byteswap); + + adxi::write_string(os, source_filename, sizeof(source_filename)); + adxi::write_string(os, source_creation_time, sizeof(source_creation_time)); + adxi::write_string(os, input_device, sizeof(input_device)); + adxi::write_string(os, input_device_serial_number, + sizeof(input_device_serial_number)); + + adxi::write_uint16(os, xl_border_validity, _need_byteswap); + adxi::write_uint16(os, xr_border_validity, _need_byteswap); + adxi::write_uint16(os, yt_border_validity, _need_byteswap); + adxi::write_uint16(os, yb_border_validity, _need_byteswap); + adxi::write_uint32(os, horizonal_par, _need_byteswap); + adxi::write_uint32(os, vertical_par, _need_byteswap); + + adxi::write_float32(os, x_scanned_size, _need_byteswap); + adxi::write_float32(os, y_scanned_size, _need_byteswap); + + adxi::write_fill(os, 0x00, 20); + + adxi::write_string(os, keycode_film_id, sizeof(keycode_film_id)); + adxi::write_string(os, keycode_film_type_char, + sizeof(keycode_film_type_char)); + adxi::write_string(os, keycode_perf_offset_char, + sizeof(keycode_perf_offset_char)); + adxi::write_string(os, keycode_prefix, sizeof(keycode_prefix)); + adxi::write_string(os, keycode_count_char, sizeof(keycode_count_char)); + + adxi::write_string(os, format, sizeof(format)); + adxi::write_uint32(os, frame_position_in_sequence, _need_byteswap); + adxi::write_uint32(os, sequence_length, _need_byteswap); + adxi::write_uint32(os, held_count, _need_byteswap); + adxi::write_float32(os, frame_rate, _need_byteswap); + adxi::write_float32(os, shutter_angle, _need_byteswap); + adxi::write_string(os, frame_attribute, sizeof(frame_attribute)); + adxi::write_string(os, frame_slate_info, sizeof(frame_slate_info)); +// adxi::write_float32(os, film_gague, _need_byteswap); +// adxi::write_uint8(os, film_orientation, _need_byteswap); +// adxi::write_uint8(os, film_perf_per_foot, _need_byteswap); +// adxi::write_uint8(os, film_perf_per_frame, _need_byteswap); +// adxi::write_string(os, film_manufacturer, sizeof(film_manufacturer)); +// adxi::write_string(os, film_stock_name, sizeof(film_stock_name)); + adxi::write_fill(os, 0x00, 108); + + adxi::write_fill(os, 0x00, 21); + + adxi::write_uint32(os, smpte_timecode, _need_byteswap); + adxi::write_uint32(os, smpte_userbits, _need_byteswap); + + + // Constraints for ADX 60-62 + if (static_cast(interlace) != udf8) { + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, static_cast(udf8), _need_byteswap); + + if (static_cast(field_number) != udf8) { + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, static_cast(udf8), _need_byteswap); + + if (static_cast(video_standard) != udf8) { + this->_constraint_ok = FALSE; + } + adxi::write_uint8(os, static_cast(udf8), _need_byteswap); + + adxi::write_fill(os, 0x00, 1); + + // Constraints for ADX 64-73 + if (horizontal_sampling_rate != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (vertical_sampling_rate != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (temporal_sampling_rate != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (time_offset_sync_to_first_pixel != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (gamma != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (black_level_code != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (black_gain != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (breakpoint != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (white_level_code != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + if (integration_time != nan_vf) { + this->_constraint_ok = FALSE; + } + adxi::write_float32(os, nan_vf, _need_byteswap); + + adxi::write_fill(os, 0x00, 76); + adxi::write_string(os, user_id, sizeof(user_id)); + + current_ostream=NULL; +} + +} diff --git a/lib/adx/adx.hh b/lib/adx/adx.hh new file mode 100644 index 00000000..9cde0672 --- /dev/null +++ b/lib/adx/adx.hh @@ -0,0 +1,614 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#if !defined(AMPAS_CTL_ADX_INCLUDE) +#define AMPAS_CTL_ADX_INCLUDE + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include "../dpx/dpx.hh" + +#if !defined(TRUE) +#define TRUE 1 +#endif + +#if !defined(FALSE) +#define FALSE 0 +#endif + +typedef half float16_t; +typedef float float32_t; +typedef double float64_t; + +namespace ctl { + // The adxi namespace is for various internals that are not actually + // class methods to keep the adx header down to a sane size... + namespace adxi { + struct rwinfo; + }; + + struct adx : public dpx { + // This class can read and write DPX 1.0, 2.0, and 3.0 files (in so + // far as the DPX 3.0 specification is complete). It should have no + // difficulty reading any extant DPX file, and can write all common + // variants of DPX 1.0/2.0 and all reasonable variants of DPX 3.0. + // Please see the 'compliance' member (below) for details on how to + // change this behavior. + // + // Fields marked with a '*' have some additional notes on them towards + // the end of the include file. + // + // Fields below marked with a '**' indicate fields that are + // synthesized (on reads) from the character array header field + // they are associated with. If the associated character array field + // has not been set (i.e. first character is a numeric 0) on write, + // then the field is decomposed back into a character array. + public: // specification field number + struct element_t { + friend class adxi::rwinfo; + friend class adx; + uint32_t data_sign; // 21.1 * + uint32_t ref_low_data_code; // 21.2 * + float32_t ref_low_quantity; // 21.3 * + uint32_t ref_high_data_code; // 21.4 * + float32_t ref_high_quantity; // 21.5 * + uint8_t descriptor; // 21.6 * + uint8_t transfer_characteristic; // 21.7 * + uint8_t colorimetric_characteristic; // 21.8 * + uint8_t bits_per_sample; // 21.9 * + uint16_t packing; // 21.10 * + uint16_t encoding; // 21.11 * + uint32_t offset_to_data; // 21.12 + uint32_t eol_padding; // 21.13 * + uint32_t eoi_padding; // 21.14 * + char description[33]; // 21.15 + + private: + uint16_t actual_packing; // see adx_validate.cc + } elements[2]; // 21-28 + // elements[8] for dpx + + // skip 52 bytes // 29 + + uint32_t x_offset; // 30 * + uint32_t y_offset; // 31 * + float32_t x_center; // 32 * + float32_t y_center; // 33 * + uint32_t x_origional_size; // 34 * + uint32_t y_origional_size; // 35 * + + char source_filename[101]; // 36 + char source_creation_time[25]; // 37 + struct tm source_creation_time_tm; // 37a ** + char input_device[33]; // 38 + char input_device_serial_number[33]; // 39 + + uint16_t xl_border_validity; // 40a + uint16_t xr_border_validity; // 40b + uint16_t yt_border_validity; // 40c + uint16_t yb_border_validity; // 40d + uint32_t horizonal_par; // 41a + uint32_t vertical_par; // 41b + + float32_t x_scanned_size; // 42.1 + float32_t y_scanned_size; // 42.2 + + // skip 20 bytes // 42.3 + + // film information header... + char keycode_film_id[3]; // 43 + char keycode_film_type_char[3]; // 44 + char keycode_perf_offset_char[3]; // 45 * + char keycode_prefix[7]; // 47 (no field 46 in adx) + char keycode_count_char[5]; // 48 + + char format[33]; // 49 + uint32_t frame_position_in_sequence; // 50 + uint32_t sequence_length; // 51 + uint32_t held_count; // 52 + float32_t frame_rate; // 53 + float32_t shutter_angle; // 54 + char frame_attribute[33]; // 55 + char frame_slate_info[101]; // 56 + float32_t film_gague; // 57.0 * + uint8_t film_orientation; // 57.1 * + uint8_t film_perf_per_foot; // 57.2 * + uint8_t film_perf_per_frame; // 57.3 * + char film_manufacturer[17]; // 57.4 * + char film_stock_name[17]; // 57.5 * + struct keycode { + //enum film_id_type_kind { + // numeric=0, + // alpha=1 + //} film_id_type_kind; + uint8_t id; + uint8_t type; + float32_t film_gague; + enum film_orientation_e { + vistavision=1, + horizontal=1, + normal=0, + vertical=0 + }; + uint8_t perf_per_frame; + uint8_t perf_per_foot; + std::string manufacturer; + std::string stock_number; + uint32_t prefix; + uint16_t foot; + uint8_t perf; + // Add perf arithmatic operations... + } keycode; // 57a ** + + // skip 21 bytes (less than original, taken up by 57.x above) + + // video information header... + uint32_t smpte_timecode; // 58 + uint32_t smpte_userbits; // 59 + uint8_t interlace; // 60 + uint8_t field_number; // 61 + uint8_t video_standard; // 62 + // skip 1 byte // 63 + float32_t horizontal_sampling_rate; // 64 + float32_t vertical_sampling_rate; // 65 + float32_t temporal_sampling_rate; // 66 + float32_t time_offset_sync_to_first_pixel; // 67 + float32_t gamma; // 68 + float32_t black_level_code; // 69 + float32_t black_gain; // 70 + float32_t breakpoint; // 71 + float32_t white_level_code; // 72 + float32_t integration_time; // 73 + // skip 76 bytes // 74 + + // we should be at byte 2048 at this point... + char user_id[33]; // 75 + + // end of header + + + // This field is used to control any alternate interpretation + // of fields that may need to happen to read a file (or write a + // compatible file). On class construction this has a value of + // 0 (automatic). + // + enum compliance_e { + automatic =0, + adx1 =0x10000000, + adx3 =0x20000000, + } compliance; + + // Section 4.2 a group of "Undefined" values + enum undefine_v { + udf8 = 0xFF, + udf16 = 0xFFFF, + udf32 = 0xFFFFFFFF, + udf32f = 0xFFFFFFFF, + udfasc = NULL + } undefined; + + + // Some helper functions to determine if a field is 'NULL' or + // to set a field to NULL. + static bool isnull(uint64_t v); + static bool isnull(uint32_t v); + static bool isnull(uint16_t v); + static bool isnull(uint8_t v); + static bool isnull(float32_t v); + + static void nullify(uint16_t *v); + static void nullify(uint8_t *v); + static void nullify(uint32_t *v); + static void nullify(uint64_t *v); + static void nullify(float32_t *v); + + // mark all fields as NULL. + void clear(void); + + private: + bool _need_byteswap; + bool _constraint_ok; + friend class adxi::rwinfo; + std::ostream *current_ostream; + compliance_e current_compliance; + endian_mode_e current_endian_mode; + // std::vector consMsg; + + std::istream::streampos header_start; + + public: + virtual ~adx(); + adx(); + + // read and write only the header... + void read(std::istream *io); + void write(std::ostream *io); + // use this to check the complaints with the constraint + bool check_constraint(void); + + static bool check_magic(std::istream *io); + + // The framebuffer (fb) class that we use for putting image + // information into (and pulling out of) the file using the + // read(...) and write(...) methods. We can't use Imf::Array2D + // because that is part of the openexr libary, and we don't + // want a dependency on openexr for ctl (we *do* have a + // dependency on ilmbase, but that's OK). + // + template + class fb { + private: + T *_data; + uint32_t _width; + uint32_t _height; + uint32_t _depth; + uint64_t _length; + + public: + fb(); + ~fb(); + + void init(uint32_t width, uint32_t height, uint32_t depth); + + uint32_t width(void) const; + uint32_t height(void) const; + uint32_t depth(void) const; + + // the total number of bytes of storage + uint64_t length(void) const; + + // The total number of pixels + uint64_t pixels(void) const; + + // The total number of samples + uint64_t count(void) const; + + // Takes the stored pixels and treats them as if they + // were in the format described by the descriptor parameter + // (i.e. header field 21.6), and then move things about so + // the pixels are then ordered in a standard RGB(A) + // (or Y(A)) format. Optionally this will remove the alpha + // channel (set descriptor==0 if the data has already been + // formatted into RGBA or YA). + void swizzle(uint8_t descriptor, bool squish_alpha); + void channelAdjust(uint8_t descriptor); + + // Indicates if the data has an alpha channel. + bool alpha() const; + // Set the alpha channel to the specified value (creates + // alpha channel if it does not exist). + void alpha(const T &value); + std::vector getConsMsg(void); + + T *ptr(void); + const T *ptr(void) const; + operator T *(); + operator const T *() const; + + }; + + std::vector consMsg; + + // Exception classes... + class exception : std::exception {}; + class invalid : exception {}; + class outofrange : exception {}; + class badtemplate : exception {}; + + // + // These implicitly call read(std::istream *i); to get a + // copy of the header. + // + // If the file's packing or bpp (or whatever...) is sufficiently + // foreign that we can't handle it, we will thow an 'invalid' + // exception. + // + // If the parameter element is out of range for the image (i.e. + // greater than or equal to 'number_of_elements' then an + // exception will be thrown. + // + enum intmode_e { + normal=0, + unformatted=1 + }; + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0, intmode_e mode=normal); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0, intmode_e mode=normal); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0, intmode_e mode=normal); + void read(std::istream *io, uint8_t element, ctl::dpx::fb *buffer, + float64_t scale=0.0, intmode_e mode=normal); + + // + // If not filled out ahead of time (i.e. have 'null' values associated + // with them), then the following fields will be set based on + // the version of the write method called. The defaults chosen are + // affected by the value of the 'compliance' field (described above). + // If compliance is set to 'automatic', then it is silently changed + // on first write to 'dpx1'. + // + // Common across all values of 'compliance': + // + // field default + // ------ ---------------------------------------------------------- + // 17 0 (pixels arranged left to right, top to bottom). + // 19 width of provided framebuffer + // 20 height of provided framebuffer + // 21.9 sizeof()*8 + // 21.1 (see below) + // 21.6 based on depth of framebuffer: + // depth descriptor + // ----- ----------------------------- + // 1 6 (Luminance) + // 2 158 (Luminance Alpha) (proposed) (*) + // 3 50 (RGB) + // 4 51 (RGBA) + // 5 153 (user defined 5 channel image) + // 6 154 (user defined 6 channel image) + // 7 155 (user defined 7 channel image) + // 8 156 (user defined 8 channel image) + // 21.7 1 if bits_per_sample==10, otherwise 2 + // 21.8 set equal to 21.7 (transfer characteristic) + // 21.10 (**)(packing) + // vaheader field valubits_per_sample, packing, + // descriptor, colorimetric_characteristic, transfer_characteristic, + // and offset_to_data will have reasonable default values placed + // in them by the write(...) method. The default values are determined + // on via the following scheme: + // + // + // IMPORTANT NOTE: Unlike the read(...) methods, the write methods + // presume that the interleaved data in the framebuffer is in the + // same order as the descriptor. + // + // All of these fields do not need + // to be filled out prior to calling write(...), , defaults will only be used as needed, colorimetric, and and elements[n].offset_to_data will have + // reasonable defaults set based on the number of channels in the + // framebuffer to write, and the type of the framebuffer. + // + // If there is a reasonable disconnect between the are not specified (i.e. + // are not all 0xff) then appropriate values will be selected + // based on the type provided in the frame buffer. + // If values are provided and do not match the framebuffer type + // then a warning will be posted (see below) and an attempt will + // be made to perform a conversion. If no conversion can be + // performed then an exception is thrown. + // Specifying the elements[n].offset_to_data is particularly + // dangerous as it will will be used without any sort of sanity + // checking and you can easily overwrite critical parts of your + // file. + // + // The number_of_elements value *must* be set prior to the first + // call to write. Failure to do this will cause an exception. + // + // The compliance field (above) must also be set prior to the + // first call/ to write. + // + // Elements should be written (preferably in order), after the + // last element has been written the header should be written. + // + // Like all of the read(...) methods, this will rewind the osream + // to the point it was at when the write(...) method was called. + // + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0, + intmode_e mode=normal); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0, + intmode_e mode=normal); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0, + intmode_e mode=normal); + void write(std::ostream *o, uint8_t element, + const ctl::dpx::fb &buffer, float64_t scale=0.0, + intmode_e mode=normal); + + // Can perform pretty much perform every imaginable conversion + // between two types. While there are a number of functions, they + // all eventually call the same method at the base of things, and + // the variants are to give slightly cleaner interfaces. + // + // The current interface only supports the following types (as either + // inputs and outputs): + // uint8_t (unsigned char) + // uint16_t (unsigned short) + // uint32_t (unsigned int) + // uint64_t (unsigned long long int) + // float16_t (half) + // float32_t (float) + // float64_t (double) + // + // Adding support for signed types is left as an excercise to the + // user. + // + // The parameter meanings are identical across all functions. If + // you are calling a function variant *without* the parameter, it + // defaults to a zero value (the behavior is described below). + // + // O template parameter that is the output type. + // I template parameter that is the input type. + // isb input significant bits, only used when then input type + // is an integer type. Will cause the input to be clipped + // from 0 to (1< + static void convert(O *o, const I *i, uint64_t count); + template + static void convert(O *o, const I *i, float64_t scale, uint64_t count); + template + static void convert(O *o, uint8_t osb, const I *i, uint64_t count); + template + static void convert(O *o, uint8_t osb, const I *i, float64_t scale, + uint64_t count); + template + static void convert(O *o, const I *i, uint8_t isb, uint64_t count); + template + static void convert(O *o, const I *i, uint8_t isb, float64_t scale, + uint64_t count); + template + static void convert(O *o, uint8_t osb, const I *i, uint8_t isb, + uint64_t count); + // This is the actual function that does the work. All of the others + // just fill out default values... + template + static void convert(O *o, uint8_t osb, const I *i, uint8_t isb, + float64_t scale, uint64_t count); + + + // Some static methods to take de-enumerate some of the + // header values. + static std::string smpte_timecode_to_string(uint32_t tc); + static std::string colormetric_to_string(uint8_t id); + static std::string transfer_to_string(uint8_t id); + static std::string video_to_string(uint8_t id); + static std::string encoding_to_string(uint8_t id); + static std::string packing_to_string(uint8_t id); + static std::string bits_per_sample_to_string(uint8_t id); + static std::string orientation_to_string(uint8_t id); + static std::string descriptor_to_string(uint8_t id); +}; + +#include +} + + +#endif diff --git a/lib/adx/adx.tcc b/lib/adx/adx.tcc new file mode 100644 index 00000000..647d0541 --- /dev/null +++ b/lib/adx/adx.tcc @@ -0,0 +1,876 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + + +template +adx::fb::fb() { + _data=NULL; + _width=0; + _height=0; + _depth=0; + _length=0; +} + +template +adx::fb::~fb() { + delete [] _data; + _data=NULL; + _width=0; + _height=0; + _depth=0; + _length=0; +} + +template +void adx::fb::init(uint32_t width, uint32_t height, uint32_t depth) { + _width=width; + _height=height; + _depth=depth; + + delete [] _data; + + _length=_width*_height*_depth*sizeof(T); + + _data=new T[width*height*depth]; +} + +template +uint32_t adx::fb::width(void) const { + return _width; +} + +template +uint32_t adx::fb::height(void) const { + return _height; +} + +template +uint32_t adx::fb::depth(void) const { + return _depth; +} + +template +uint64_t adx::fb::length(void) const { + return _length; +} + +template +uint64_t adx::fb::count(void) const { + return _width*_height*_depth; +} + +template +uint64_t adx::fb::pixels(void) const { + return _width*_height; +} + +template +T *adx::fb::ptr(void) { + return _data; +} + +template +const T *adx::fb::ptr(void) const { + return _data; +} + +template +adx::fb::operator T *() { + return _data; +} + +template +adx::fb::operator const T *() const { + return _data; +} + +template +void adx::fb::swizzle(uint8_t descriptor, bool squish_alpha) { + uint64_t u, count; + T *i, *o; + T t; + + count=width()*height(); + + i=_data; + o=_data; + + switch(descriptor) { + case 0: + if(alpha() && squish_alpha) { + if(_depth==2) { + for(u=0; u +void ctl::adx::fb::channelAdjust(uint8_t descriptor){ + uint64_t u, count; + T *i, *o; + T t; + + count=width()*height(); + + i=_data; + o=_data; + + switch(descriptor) { + case 0: // user defined + case 6: // luminance + case 157: // XYZ + case 158: // luminance, alpha + break; + + case 50: + break; + + case 51: // RGBA + for(u=0; u +bool ctl::adx::fb::alpha() const { + return (_depth==2 || _depth==4); +} + +template +void ctl::adx::fb::alpha(const T &value) { + uint64_t u; + fb new_fb; + T *i, *o; + + if(alpha()) { + i=_data+_depth-1; + for(u=0; u +void convert(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale); + +template +void convert(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale, uint64_t count); + +template +void convertfb(dpx::fb *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale); + + +// Given input and output types, input and output signifcant bits, and +// a scale value, returns a function pointer that (effectively) matches +// the convert signature above. The function returned *may* be an optimized +// version the above with the osb, isb, and scale values 'cooked' into it. +// When using the returned function you *must* still supply the osb, isb +// and scale values (in the event that the returned type was not optimized). +// There is probably a better way to handle this optimization, but it's +// left as an excercise to the user. +typedef void (*convert_fn)(void *out, const uint8_t &osb, const void *in, + const uint8_t &isb, const float64_t &scale); + +template +convert_fn find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale); + +// The lower level functions: + +// Convert float to integer, optimized for scale==1.0 +template +void ftu_one(O *out, const uint8_t &osb, const I *_in, const uint8_t &isb, + const float64_t &scale) { + I in=*_in; + float64_t fmax; + uint64_t imax; + uint64_t result; + uint64_t msb; + + if(osb==64) { + imax=adxi::max_int_for_bits[osb-1]; + in=in/2.0; + } else { + imax=adxi::max_int_for_bits[osb]; + } + fmax=imax; + // We get to do this hinky scale by half thing here when dealing with + // 64 bit numbers because the only double to int conversion presumes + // the return int is signed (and there is no support for return values + // greater than 64 bits. + + if(in<0) { + *out=0; + return; + } else if(in>fmax) { + *out=imax; + return; + } + + result=llrint(in); + if(osb==64) { + msb=(result&(1ULL<<62))>>62; + result=result<<1 | msb; + } + + *out=result; +} + +// Convert float to integer, optimized for scale==0 +template +void ftu_zero(O *out, const uint8_t &osb, const I *_in, const uint8_t &isb, + const float64_t &scale) { + float64_t in=*_in; + float64_t fmax; + + fmax=adxi::max_int_for_bits[osb]; + + if(in<0) { + *out=0; + return; + } else if(in>1.0) { + *out=adxi::max_int_for_bits[osb]; + return; + } + + in=in*fmax; + + ftu_one(out, osb, &in, isb, scale); +} + +// convert float to integer non-optimized +template +void ftu(O *out, const uint8_t &osb, const I *_in, const uint8_t &isb, + const float64_t &scale) { + I in=*_in; + + in=in*scale; + + ftu_one(out, osb, &in, isb, scale); +} + +// convert float to float, with scale==0 or scale==1 +template +void ftf_one(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + *out=*in; +} + +// convert float to float, any scale +template +void ftf(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + *out=*in*scale; +} + +// convert int to float, scale==0.0 +template +void utf_zero(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + uint64_t imax; + float64_t fmax; + + imax=adxi::max_int_for_bits[isb]; + fmax=imax; + + if((*in)>imax) { + *out=1.0; + } + + *out=((float64_t)(*in))/fmax; +} + +// convert int to float, scale==1.0 +template +void utf_one(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + uint64_t imax; + float64_t fmax; + + imax=adxi::max_int_for_bits[isb]; + fmax=imax; + + if((*in)>imax) { + *out=fmax; + } + + *out=*in; +} + +// convert from float to int +template +void utf(O *out, const uint8_t &osb, const I *_in, const uint8_t &isb, + const float64_t &scale) { + float64_t in; + + in=(*_in)*scale; + + utf_one(out, osb, &in, isb, scale); +} + +// convert integer to integer, scale=0.0 +template +void utu_zero(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + uint8_t count; + uint8_t sigbits; + uint8_t deltabits; + uint8_t shift; + O result; + O bits; + + if(osb>shift); + if((*out)>=adxi::max_int_for_bits[osb]) { + *out=adxi::max_int_for_bits[osb]; + } + return; + } else { + sigbits=isb; + count=sigbits-osb; + + result=*in; + if(result>=adxi::max_int_for_bits[isb]) { + result=adxi::max_int_for_bits[isb]; + } + // When we scale up we do it in such a way that we don't leave + // all of the LSB zero by copying parts out of the MSB. For some + // conversions this needs to be iteratively done (since there + // aren't enough MSB to copy if the conversion is large). We + // do a quickie pass that the optimizer will take care of + // since it can be determined at compile time, failing that + // the looping version is used. + if(count<=sigbits) { + deltabits=count; + bits=adxi::max_int_for_bits[deltabits]; + bits=bits<<(sigbits-deltabits); + bits=result&bits; + bits=bits>>(sigbits-deltabits); + result=result<sigbits) { + deltabits=sigbits; + } + + bits=adxi::max_int_for_bits[deltabits]; + bits=bits<<(sigbits-deltabits); + bits=result&bits; + bits=bits>>(sigbits-deltabits); + result=result< +void utu_one(O *out, const uint8_t &osb, const I *in, const uint8_t &isb, + const float64_t &scale) { + uint8_t shift; + + if(osb>shift; + + if(*out>=adxi::max_int_for_bits[osb]) { + *out=adxi::max_int_for_bits[osb]; + } +} + +// convert integer to integer +template +void utu(O *out, const uint8_t &osb, const I *_in, const uint8_t &isb, + const float64_t &scale) { + float64_t in; + + in=*_in*scale; + + ftu_one(out, osb, &in, isb, scale); +} + +#define VOIDIFY(X) \ +template \ +void v_##X(void *out, const uint8_t &osb, const void *in, \ + const uint8_t &isb, const float64_t &scale) { \ + X((O *)out, osb, (const I *)in, isb, scale); \ +} + +VOIDIFY(ftu_one); +VOIDIFY(ftu_zero); +VOIDIFY(ftu); +VOIDIFY(utf_one); +VOIDIFY(utf_zero); +VOIDIFY(utf); +VOIDIFY(utu_one); +VOIDIFY(utu_zero); +VOIDIFY(utu); +VOIDIFY(ftf_one); +VOIDIFY(ftf); + +struct true_type {}; +struct false_type {}; + +template +struct isfloatish : false_type {}; + +template <> +struct isfloatish : true_type {}; +template <> +struct isfloatish : true_type {}; +template <> +struct isfloatish : true_type {}; + + +//template +//convert_fn _find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale); + +template +convert_fn _find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale, + const O &_o, const I &_i, const false_type &_it, + const false_type &_ot) { + if(scale==0.0) { + return v_utu_zero; + } else if(scale==1.0) { + return v_utu_one; + } else { + return v_utu; + } +} + +template +convert_fn _find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale, + const O &_o, const I &_i, const true_type &_it, + const false_type &_ot) { + if(scale==0.0) { + return v_ftu_zero; + } else if(scale==1.0) { + return v_ftu_one; + } else { + return v_ftu; + } +} + +template +convert_fn _find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale, + const O &_o, const I &_i, const false_type &_it, + const true_type &_ot) { + if(scale==0.0) { + return v_utf_zero; + } else if(scale==1.0) { + return v_utf_one; + } else { + return v_utf; + } +} + +template +convert_fn _find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale, + const O &_o, const I &_i, const true_type &_it, + const true_type &_ot) { + if(scale==0.0 || scale==1.0) { + return v_ftf_one; + } else { + return v_ftf; + } +} + +template +convert_fn find_convert_fn(uint8_t osb, uint8_t isb, float64_t scale) { + convert_fn fn; + + fn=_find_convert_fn(osb, isb, scale, O(), I(), + isfloatish(), isfloatish()); + return fn; +} + +template +void convertlut(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale, uint64_t count); + +template +void _convertfblut(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale, uint64_t count); + +template +void _convertlut(O *o, uint8_t osb, const I *in, uint8_t isb, + float64_t scale, uint64_t count) { + convert_fn fn; + O lut[1<<16]; + uint32_t u; + + fn=find_convert_fn(osb, isb, scale); + for(u=0; u<(1<<16); u++) { + fn(lut+u, osb, &u, isb, scale); + } + for(u=0; u +void convertlut(O *o, uint8_t osb, const uint8_t *in, uint8_t isb, + float64_t scale, uint64_t count) { + _convertlut(o, osb, in, isb, scale, count); +} + +template +void convertlut(O *o, uint8_t osb, const uint16_t *in, uint8_t isb, + float64_t scale, uint64_t count) { + _convertlut(o, osb, in, isb, scale, count); +} + +template +void convertlut(O *o, uint8_t osb, const float16_t *in, uint8_t isb, + float64_t scale, uint64_t count) { + convert_fn fn; + O lut[1<<16]; + uint64_t u; + uint16_t b; + half h; + + fn=find_convert_fn(osb, isb, scale); + for(u=0; u<((1<<16)-1); u++) { + h.setBits(u); + // Just running everything as-is for right now... + if(h.isNan()) { + lut[u]=0; + } else if(h.isInfinity() && h.isNegative()) { + lut[u]=adxi::max_int_for_bits[osb]; + } else if(h.isInfinity() && !h.isNegative()) { + lut[u]=0; + } else { + fn(lut+u, osb, &h, isb, scale); + } + } + + for(u=0; ubits(); + *o=lut[b]; + in++; o++; + } +} + +template +void convertlut(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale, uint64_t count) { + // Do nothing unless we have a partial implimentation; + // XXX +} + +template +void convert(O *o, uint8_t osb, const I *in, uint8_t isb, float64_t scale, + uint64_t count) { + convert_fn fn; + uint64_t u; + + if(sizeof(I)<=2) { + convertlut(o, osb, in, isb, scale, count); + } else { + fn=find_convert_fn(osb, isb, scale); + for(u=0; u +void convert(O *out, uint8_t osb, const I *in, uint8_t isb, + float64_t scale) { + convert_fn fn; + + fn=find_convert_fn(osb, isb, scale); + + fn(out, osb, in, isb, scale); +} + +template +void convertfb(dpx::fb *out, uint8_t osb, const I *in, + uint8_t isb, float64_t scale) { + convert(out->ptr(), osb, in, isb, scale, out->count()); +} + +} + +template +void adx::convert(O *o, uint8_t osb, const I *i, uint8_t isb, + float64_t scale, uint64_t count) { + adxi::convert(o, osb, i, isb, scale, count); +} + +template +void adx::convert(O *o, const I *i, uint64_t count) { + adxi::convert(o, sizeof(O)*8, i, sizeof(I)*8, 0.0, count); +} + +template +void adx::convert(O *o, const I *i, float64_t scale, uint64_t count) { + adxi::convert(o, sizeof(O)*8, i, sizeof(I)*8, scale, count); +} + +template +void adx::convert(O *o, uint8_t osb, const I *i, uint64_t count) { + adxi::convert(o, osb, i, sizeof(I)*8, 0.0, count); +} + +template +void adx::convert(O *o, uint8_t osb, const I *i, float64_t scale, + uint64_t count) { + adxi::convert(o, osb, i, sizeof(I)*8, scale, count); +} + +template +void adx::convert(O *o, const I *i, uint8_t isb, uint64_t count) { + adxi::convert(o, sizeof(O)*8, i, isb, 0.0, count); +} + +template +void adx::convert(O *o, const I *i, uint8_t isb, float64_t scale, + uint64_t count) { + adxi::convert(o, sizeof(O)*8, i, isb, scale, count); +} + +template +void adx::convert(O *o, uint8_t osb, const I *i, uint8_t isb, + uint64_t count) { + adxi::convert(o, osb, i, isb, 0.0, count); +} + diff --git a/lib/adx/adx_bits.cc b/lib/adx/adx_bits.cc new file mode 100644 index 00000000..fbd36659 --- /dev/null +++ b/lib/adx/adx_bits.cc @@ -0,0 +1,135 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include "adx_bits.hh" + +// namespace ctl { +// namespace adxi { + +// } +// } + +namespace ctl { +namespace adxi { + +const uint64_t max_int_for_bits[]={ 0x0000000000000000ULL, + 0x0000000000000001ULL, + 0x0000000000000003ULL, + 0x0000000000000007ULL, + 0x000000000000000fULL, + 0x000000000000001fULL, + 0x000000000000003fULL, + 0x000000000000007fULL, + 0x00000000000000ffULL, + 0x00000000000001ffULL, + 0x00000000000003ffULL, + 0x00000000000007ffULL, + 0x0000000000000fffULL, + 0x0000000000001fffULL, + 0x0000000000003fffULL, + 0x0000000000007fffULL, + 0x000000000000ffffULL, + 0x000000000001ffffULL, + 0x000000000003ffffULL, + 0x000000000007ffffULL, + 0x00000000000fffffULL, + 0x00000000001fffffULL, + 0x00000000003fffffULL, + 0x00000000007fffffULL, + 0x0000000000ffffffULL, + 0x0000000001ffffffULL, + 0x0000000003ffffffULL, + 0x0000000007ffffffULL, + 0x000000000fffffffULL, + 0x000000001fffffffULL, + 0x000000003fffffffULL, + 0x000000007fffffffULL, + 0x00000000ffffffffULL, + 0x00000001ffffffffULL, + 0x00000003ffffffffULL, + 0x00000007ffffffffULL, + 0x0000000fffffffffULL, + 0x0000001fffffffffULL, + 0x0000003fffffffffULL, + 0x0000007fffffffffULL, + 0x000000ffffffffffULL, + 0x000001ffffffffffULL, + 0x000003ffffffffffULL, + 0x000007ffffffffffULL, + 0x00000fffffffffffULL, + 0x00001fffffffffffULL, + 0x00003fffffffffffULL, + 0x00007fffffffffffULL, + 0x0000ffffffffffffULL, + 0x0001ffffffffffffULL, + 0x0003ffffffffffffULL, + 0x0007ffffffffffffULL, + 0x000fffffffffffffULL, + 0x001fffffffffffffULL, + 0x003fffffffffffffULL, + 0x007fffffffffffffULL, + 0x00ffffffffffffffULL, + 0x01ffffffffffffffULL, + 0x03ffffffffffffffULL, + 0x07ffffffffffffffULL, + 0x0fffffffffffffffULL, + 0x1fffffffffffffffULL, + 0x3fffffffffffffffULL, + 0x7fffffffffffffffULL, + 0xffffffffffffffffULL + }; + +}; + +}; diff --git a/lib/adx/adx_bits.hh b/lib/adx/adx_bits.hh new file mode 100644 index 00000000..10f2d167 --- /dev/null +++ b/lib/adx/adx_bits.hh @@ -0,0 +1,69 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#if !defined(AMPAS_CTL_ADX_BITS_INCLUDE) +#define AMPAS_CTL_ADX_BITS_INCLUDE + +#include +#include +#include +namespace ctl { +namespace adxi { + +extern const uint64_t max_int_for_bits[]; + +} +} + +#endif diff --git a/lib/adx/adx_enum.cc b/lib/adx/adx_enum.cc new file mode 100644 index 00000000..9c200acf --- /dev/null +++ b/lib/adx/adx_enum.cc @@ -0,0 +1,444 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include +#include "adx_util.hh" + +namespace ctl { + +std::string adx::descriptor_to_string(uint8_t id) { + if(id==0) { + return std::string("user defined single channel (0)"); + } else if(id==5) { + return std::string("not specified"); + } else if(id>=10 && id<=49) { + return adxi::strprintf("reserved single component (%u)", id); + } else if(id>=53 && id<=99) { + return adxi::strprintf("reserved RGB format (%u)", id); + } else if(id>=104 && id<=149) { + return adxi::strprintf("reserved cbYcr format (%u)", id); + } else if(id>=157) { + return adxi::strprintf("reserved future format (%u)", id); + } + + switch(id) { + case 1: + return std::string("red (R)"); + + case 2: + return std::string("green (G)"); + + case 3: + return std::string("blue (B)"); + + case 4: + return std::string("alpha (matte)"); + + case 6: + return std::string("luma (Y)"); + + case 7: + return std::string("color difference (Cb, Cr)"); + + case 8: + return std::string("depth (Z)"); + + case 9: + return std::string("composite video"); + + case 50: + return std::string("RGB (note 2)"); + + case 51: + return std::string("RGBA (note 2)"); + + case 52: + return std::string("ABGR (note 3)"); + + case 100: + return std::string("CbYCrY (4:2:2) SMPTE 125M"); + + case 101: + return std::string("CbYACrYA (4:2:2:4)"); + + case 102: + return std::string("CbYCr (4:4:4)"); + + case 103: + return std::string("CbYCrA (4:4:4:4)"); + + case 150: + case 151: + case 152: + case 153: + case 154: + case 155: + case 156: + return adxi::strprintf("user defined %u component element", id-150+2); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("ARRRGH something outside of case (%u)", id); +} + +std::string adx::orientation_to_string(uint8_t id) { + switch(id) { + case 0: + return std::string("left to right, top to bottom"); + + case 1: + return std::string("right to left, top to bottom"); + + case 2: + return std::string("left to right, bottom to top"); + + case 3: + return std::string("right to left, bottom to top"); + + case 4: + return std::string("top to bottom, left to right"); + + case 5: + return std::string("top to bottom, right to left"); + + case 6: + return std::string("bottom to top, left to right"); + + case 7: + return std::string("bottom to top, right to left"); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved for future use (%u)", id); +} + +std::string adx::bits_per_sample_to_string(uint8_t id) { + switch(id) { + case 1: + return std::string("1 bit"); + + case 8: + case 10: + case 12: + case 16: + return adxi::strprintf("%u bits", id); + + case 32: + return std::string("32 bit FP"); + + case 64: + return std::string("64 bit FP"); + + case 255: + return std::string("unset"); + } + + return adxi::strprintf("invalid bit depth (%u)", id); +} + +std::string adx::packing_to_string(uint8_t id) { + switch(id) { + case 0: + return std::string("32 bit word packed"); + + case 1: + return std::string("32 bit word filled (method A)"); + + case 2: + return std::string("32 bit word filled (method B)"); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved component packing (%u)", id); +} + +std::string adx::encoding_to_string(uint8_t id) { + switch(id) + { + case 0: + return std::string("no encoding"); + + case 1: + return std::string("RLE encoding"); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved component encoding (%u)", id); +} + +std::string adx::video_to_string(uint8_t id) { + if(id>=5 && id<=49) { + return adxi::strprintf("reserved composite video (%u)", id); + } else if(id>=52 && id<=99) { + return adxi::strprintf("reserved component video (%u)", id); + } else if(id>=102 && id<=149) { + return adxi::strprintf("reserved widescreen (%u)", id); + } else if(id>=154 && id<=199) { + return adxi::strprintf("reserved high definition interlace (%u)", id); + } else if(id>=204 && id<=254) { + return adxi::strprintf("reserved high definition progressive (%u)", id); + } + + switch(id) { + case 0: + return std::string("undefined"); + + case 1: + return std::string("NTSC"); + + case 2: + return std::string("PAL"); + + case 3: + return std::string("PAL-M"); + + case 4: + return std::string("SECAM"); + + case 50: + return std::string("YCbCr ITU-R 601-5 525 line 2:1 interlace, " + "4:3 aspect"); + + case 51: + return std::string("YCbCr ITU-R 601-5 625 line 2:1 interlace, " + "4:3 aspect"); + + case 100: + return std::string("YCbCr ITU-R 601-5 525 line 2:1 interlace, " + "4:3 aspect"); + + case 101: + return std::string("YCbCr ITU-R 601-5 625 line 2:1 interlace, " + "4:3 aspect"); + + case 150: + return std::string("YCbCr 1050 line 2:1 interlace, 16:9 aspect"); + + case 151: + return std::string("YCbCr 1125 line 2:1 interlace, 16:9 aspect " + "SMPTE 274M"); + + case 152: + return std::string("YCbCr 1250 line 2:1 interlace, 16:9 aspect"); + + case 153: + return std::string("YCbCr 1125 line 2:1 interlace, 16:9 aspect " + "SMPTE 240M"); + + case 200: + return std::string("YCbCr 525 line 1:1 progressive, 16:9 aspect"); + + case 201: + return std::string("YCbCr 625 line 1:1 progressive, 16:9 aspect"); + + case 202: + return std::string("YCbCr 750 line 1:1 progressive, 16:9 aspect " + "SMPTE 296M"); + + case 203: + return std::string("YCbCr 1125 line 1:1 progressive, 16:9 aspect " + "SMPTE 274M"); + + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved video format %u", id); +} + +std::string adx::transfer_to_string(uint8_t id) { + switch(id) { + case 0: + return std::string("user defined"); + + case 1: + return std::string("printing density"); + + case 2: + return std::string("linear"); + + case 3: + return std::string("logarithmic (SMPTE I23)"); + + case 4: + return std::string("unspecified video"); + + case 5: + return std::string("SMPTE 274M"); + + case 6: + return std::string("ITU-R 709-4"); + + case 7: + return std::string("ITU-R 601-5 sytstem B or G"); + + case 8: + return std::string("ITU-R 601-5 sytstem M"); + + case 9: + return std::string("composite video (NTSC) SMPTE 170M"); + + case 10: + return std::string("composite video (PAL) ITU-R 624-4"); + + case 11: + return std::string("Z (depth) - linear"); + + case 12: + return std::string("Z (depth) - homogeneous"); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved transfer characteristic %u", id); +} + +std::string adx::colormetric_to_string(uint8_t id) { + switch(id) { + case 0: + return std::string("user defined"); + + case 1: + return std::string("printing density"); + + case 4: + return std::string("unspecified video"); + + case 5: + return std::string("SMPTE 274M"); + + case 6: + return std::string("ITU-R 709-4"); + + case 7: + return std::string("ITU-R 601-5 sytstem B or G"); + + case 8: + return std::string("ITU-R 601-5 sytstem M"); + + case 9: + return std::string("composite video (NTSC) SMPTE 170M"); + + case 10: + return std::string("composite video (PAL) ITU-R 624-4"); + + case 2: + case 3: + case 11: + case 12: + return adxi::strprintf("not applicable (%u)", id); + + case 255: + return std::string("unset"); + + default: + break; + } + + return adxi::strprintf("reserved transfer characteristic (%u)", id); +} + +std::string adx::smpte_timecode_to_string(uint32_t tc) { + char h[2]; + char m[2]; + char s[2]; + char f[2]; + + if(tc==0xffffffff) + { + return std::string(""); + } + + h[0]=(tc&0xf0000000) >> 28; + h[1]=(tc&0x0f000000) >> 24; + m[0]=(tc&0x00f00000) >> 20; + m[1]=(tc&0x000f0000) >> 16; + s[0]=(tc&0x0000f000) >> 12; + s[1]=(tc&0x00000f00) >> 8; + f[0]=(tc&0x000000f0) >> 4; + f[1]=(tc&0x0000000f) >> 0; + + return adxi::strprintf("%d%d:%d%d:%d%d:%d%d", h[0], h[1], m[0], m[1], + s[0], s[1], f[0], f[1]); +} + +}; diff --git a/lib/adx/adx_raw.cc b/lib/adx/adx_raw.cc new file mode 100644 index 00000000..3190d482 --- /dev/null +++ b/lib/adx/adx_raw.cc @@ -0,0 +1,218 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include +#include "adx_raw.hh" +#include + +namespace ctl { + +namespace adxi { + +uint32_t read_uint32(std::istream *is, bool need_byteswap) { + uint32_t i; + + is->read((char *)&i, sizeof(i)); + + if(need_byteswap) { + swap32(&i); + } + + // if (i != 0){ + // std::stringstream errMsg = "The Data Sign Shall be Unsigned"; + // throw std::exception(this->errMsg.str()); + // } + + return i; +} + +uint16_t read_uint16(std::istream *is, bool need_byteswap) { + uint16_t i; + + is->read((char *)&i, sizeof(i)); + + if(need_byteswap) { + swap16(&i); + } + return i; +} + +uint8_t read_uint8(std::istream *is, bool need_byteswap) { + uint8_t i; + + is->read((char *)&i, sizeof(i)); + + return i; +} + +float32_t read_float32(std::istream *is, bool need_byteswap) { + float32_t f; + + is->read((char *)&f, sizeof(f)); + + if(need_byteswap) { + swap32(&f); + } + return f; +} + +void read_string(std::istream *is, char *bytes, int len_plus_one) +{ + char *c; + + memset(bytes, 0, len_plus_one); + is->read(bytes, len_plus_one-1); + + c=bytes; + while(c<(bytes+len_plus_one)) { + if(*c==0) { + memset(c, 0, len_plus_one-(c-bytes)); + break; + } + c++; + } +} + +void write_uint32(std::ostream *os, uint32_t i, bool need_byteswap) { + if(need_byteswap) { + swap32(&i); + } + + os->write((char *)&i, sizeof(i)); +} + +void write_uint16(std::ostream *os, uint16_t i, bool need_byteswap) { + if(need_byteswap) { + swap16(&i); + } + + os->write((char *)&i, sizeof(i)); +} + +void write_uint8(std::ostream *os, uint8_t i, bool need_byteswap) { + os->write((char *)&i, sizeof(i)); +} + +void write_float32(std::ostream *os, float32_t f, bool need_byteswap) { + if(need_byteswap) { + swap32(&f); + } + + os->write((char *)&f, sizeof(f)); +} + +void write_string(std::ostream *os, char *bytes, int len_plus_one) { + char *c; + c=bytes; + // Don't need null termiate fields, but we make sure that + // if there's a null everything after it is zero. + while(c<(bytes+len_plus_one)) { + if(*c==0) { + memset(c, 0, len_plus_one-(c-bytes)); + break; + } + c++; + } + os->write(bytes, len_plus_one-1); +} + +void write_fill(std::ostream *os, char b, int count) { + while(count-->0) { + os->write((char *)&b, 1); + } +} + +} + +void adx::nullify(float32_t *v) { + *((uint32_t *)v)=(uint32_t)-1; +} + +void adx::nullify(uint8_t *v) { + *v=(uint8_t)-1; +} + +void adx::nullify(uint16_t *v) { + *v=(uint16_t)-1; +} + +void adx::nullify(uint32_t *v) { + *v=(uint32_t)-1; +} + +void adx::nullify(uint64_t *v) { + *v=(uint64_t)-1; +} + +bool adx::isnull(uint64_t v) { + return v==(uint64_t)-1; +} + +bool adx::isnull(uint32_t v) { + return v==(uint32_t)-1; +} + +bool adx::isnull(uint16_t v) { + return v==(uint16_t)-1; +} + +bool adx::isnull(uint8_t v) { + return v==(uint8_t)-1; +} + +bool adx::isnull(float32_t v) { + return *((uint32_t *)&v)==(uint32_t)-1; +} + +} diff --git a/lib/adx/adx_raw.hh b/lib/adx/adx_raw.hh new file mode 100644 index 00000000..9a3793e0 --- /dev/null +++ b/lib/adx/adx_raw.hh @@ -0,0 +1,171 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#if !defined(CTL_ADX_RAW_INTERNAL_INCLUDE) +#define CTL_ADX_RAW_INTERNAL_INCLUDE + +#include "../dpx/dpx.hh" + +namespace ctl { + +namespace adxi { + +inline void swap64(void *_s) { + uint64_t s=*((uint64_t*)_s); + + s=(((s&0xffffffff00000000LL)>>32) | ((s&0x00000000ffffffffLL)<<32)); + s=(((s&0xffff0000ffff0000LL)>>16) | ((s&0x0000ffff0000ffffLL)<<16)); + s=(((s&0xff00ff00ff00ff00LL)>>8) | ((s&0x00ff00ff00ff00ffLL)<<8)); + + *((uint64_t*)_s)=s; +} + +inline void swap32(void *_s) { + uint32_t s=*((uint32_t*)_s); + + s=(((s&0xffff0000)>>16) | ((s&0x0000ffff)<<16)); + s=(((s&0xff00ff00)>>8) | ((s&0x00ff00ff)<<8)); + + *((uint32_t*)_s)=s; +} + +inline void swap16(void *_s) { + uint16_t s=*((uint16_t*)_s); + + s=(((s&0xff00)>>8) | ((s&0x00ff)<<8)); + + *((uint16_t*)_s)=s; +} + +template +void read_ptr(std::istream *i, T *data, uint64_t count, bool swap) { + uint64_t u; + T *s; + + s=data; + + i->read((char *)s, sizeof(T)*count); + + if(swap && sizeof(T)==2) { + for(u=0; u +void write_ptr(std::ostream *o, const T *_data, uint64_t count, bool swap) { + uint64_t u; + ctl::dpx::fb data; + T *s; + + data.init(count*sizeof(T), 1, 1); + + if(swap && sizeof(T)!=1) { + data.init(count*sizeof(T), 1, 1); + memcpy(data, _data, count*sizeof(T)); + s=(T *)data.ptr(); + switch(sizeof(T)) { + case 2: + for(u=0; uwrite((const char *)_data, count*sizeof(T)); +} + +uint8_t read_uint8(std::istream *is, bool need_byteswap); +uint16_t read_uint16(std::istream *is, bool need_byteswap); +uint32_t read_uint32(std::istream *is, bool need_byteswap); +float32_t read_float32(std::istream *is, bool need_byteswap); +void read_string(std::istream *is, char *bytes, int len_plus_one); + +void write_uint8(std::ostream *os, uint8_t i, bool need_byteswap); +void write_uint16(std::ostream *os, uint16_t i, bool need_byteswap); +void write_uint32(std::ostream *os, uint32_t i, bool need_byteswap); +void write_float32(std::ostream *os, float32_t f, bool need_byteswap); +void write_string(std::ostream *os, char *bytes, int len_plus_one); +void write_fill(std::ostream *os, char b, int count); + +} + +} + +#endif diff --git a/lib/adx/adx_read.cc b/lib/adx/adx_read.cc new file mode 100644 index 00000000..2ee09756 --- /dev/null +++ b/lib/adx/adx_read.cc @@ -0,0 +1,336 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include +#include "adx_raw.hh" +#include +#include +#include "adx_bits.hh" +#include "adx_rw.hh" + +namespace ctl { +namespace adxi { + +// To handle the reads in raw mode (integer types only)... +// T needs to be the same type as indicated by the packing field. +template +void read_data(std::istream *i, ctl::dpx::fb *buffer, const rwinfo &ri) { + buffer->init(ri.words_for_raw(), 1, 1); + + read_ptr(i, buffer->ptr(), buffer->count(), ri.need_byteswap); +} + +// When we know that the read type and buffer will align with what is on +// the disk. +template +void read_fb(std::istream *i, ctl::dpx::fb *buffer, const rwinfo &ri) { + buffer->init(ri.width, ri.height, ri.channels); + + read_ptr(i, buffer->ptr(), buffer->count(), ri.need_byteswap); +} + +// Perform bit unpacking... +template +void unpack(ctl::dpx::fb *out, const I *i, const rwinfo &ri) { + uint64_t u, v, count; + uint64_t pad, onbit, down; + I mask; + I t; + O *o; + + out->init(ri.width, ri.height, ri.channels); + + o=out->ptr(); + +#if 1 + count=out->count(); + if(ri.bps==10) { + if(ri.pack==1) { + for(u=0; upixels(); u++) { + t=*(i++); + t=t>>2; + o[2]=(t&0x3ff); t=t>>10; + o[1]=(t&0x3ff); t=t>>10; + o[0]=(t&0x3ff); + o=o+3; + } + return; + } else if(ri.pack==2) { + for(u=0; upixels(); u++) { + t=*(i++); + o[2]=(t&0x3ff); t=t>>10; + o[1]=(t&0x3ff); t=t>>10; + o[0]=(t&0x3ff); + o=o+3; + } + return; + } + } +#endif + + // Yes... We shift off the *top* since we need to keep the pixels in + // an 'big endian' order (in relationship to the bytestream). + down=(sizeof(I)*8-ri.bps); + mask=max_int_for_bits[ri.bps]; + mask=mask<width()*out->depth(); + for(u=0; uheight(); u++) { + onbit=0; + for(v=0; v>down; + t=t< +void read(ctl::dpx::fb *out, const I *in, const rwinfo &ri) { + ctl::dpx::fb upfbu64; + ctl::dpx::fb upfbu32; + ctl::dpx::fb upfbu16; + ctl::dpx::fb upfbu8; + + if(ri.bps<=sizeof(I)*8) { + // not good... + } + if(ri.datatype==0) { + if(((ri.pack&0x7)==1 || (ri.pack&0x7)==2) && ((sizeof(I)*8)%ri.bps)!=0) { + if(ri.bps<=8) { + unpack(&upfbu8, in, ri); + convertfb(out, sizeof(O)*8, upfbu8.ptr(), ri.bps, ri.scale); + } else if(ri.bps<=16) { + unpack(&upfbu16, in, ri); + convertfb(out, sizeof(O)*8, upfbu16.ptr(), ri.bps, ri.scale); + } else if(ri.bps<=32) { + unpack(&upfbu32, in, ri); + convertfb(out, sizeof(O)*8, upfbu32.ptr(), ri.bps, ri.scale); + } else if(ri.bps<=64) { + unpack(&upfbu64, in, ri); + convertfb(out, sizeof(O)*8, upfbu64.ptr(), ri.bps, ri.scale); + } else { + // XXX badness... + } + } else if((ri.pack&0x7)>=0 && (ri.pack&0x7)<=2 && + sizeof(I)*8%ri.bps==0) { + convertfb(out, sizeof(O)*8, in, ri.bps, ri.scale); + } else { + // XXX + } + } else if(ri.datatype==2) { + switch(ri.bps) { + case 16: + convertfb(out, sizeof(O)*8, (float16_t *)in, ri.bps, ri.scale); + break; + + case 32: + convertfb(out, sizeof(O)*8, (float32_t *)in, ri.bps, ri.scale); + break; + + case 64: + convertfb(out, sizeof(O)*8, (float64_t *)in, ri.bps, ri.scale); + break; + + default: + // XXX + break; + } + } else { + // XXX + } +} + +// Catch-all super-transforming read. +template +void read(std::istream *i, ctl::dpx::fb *out, const rwinfo &ri) { + ctl::dpx::fb fbu64; + ctl::dpx::fb fbu32; + ctl::dpx::fb fbu16; + ctl::dpx::fb fbu8; + rwinfo new_ri; + + // ri.datatype==0 unsigned integer + // ri.datatype==1 signed integer (unsupported) + // ri.datatype==2 floating point + + if(ri.version==0x30) { + // read size determined by packing... + if(ri.pack<8) { + read_data(i, &fbu32, ri); + read(out, fbu32.ptr(), ri); + } else if(ri.pack<16) { + read_data(i, &fbu16, ri); + read(out, fbu16.ptr(), ri); + } else if(ri.pack<24) { + read_data(i, &fbu8, ri); + read(out, fbu8.ptr(), ri); + } else if(ri.pack<32) { + read_data(i, &fbu64, ri); + read(out, fbu64.ptr(), ri); + } else { + // XXX + } + } else { + // read size determined by bps... + new_ri=ri; + // should be redundant... But you never know... + new_ri.pack=ri.pack&0x07; + if(ri.bps<=8) { + read_data(i, &fbu8, new_ri); + read(out, fbu8.ptr(), new_ri); + } else if(ri.bps<=10) { + read_data(i, &fbu32, new_ri); + read(out, fbu32.ptr(), new_ri); + } else if(ri.pack<=16) { + read_data(i, &fbu16, new_ri); + read(out, fbu16.ptr(), new_ri); + } else { + // XXX + } + } +} + +// This is what all of the 'normal' class read methods call. +template +void read(std::istream *i, uint8_t element, ctl::dpx::fb *buffer, + const rwinfo &ri) { + std::istream::pos_type start; + + start=i->tellg(); + + i->seekg(ri.offset_to_data+start); + + if(ri.mode==adx::unformatted) { + read_data(i, buffer, ri); + } else { + buffer->init(ri.width, ri.height, ri.channels); + + if(ri.direct) { + read_fb(i, buffer, ri); + } else { + read(i, buffer, ri); + } + } + + i->seekg(start); +} + +}; + +void adx::read(std::istream *i, uint8_t e, + ctl::dpx::fb *buffer, float64_t scale) { + adxi::rwinfo ri(this, e, scale, normal, FALSE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, + ctl::dpx::fb *buffer, float64_t scale) { + adxi::rwinfo ri(this, e, scale, normal, FALSE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, + ctl::dpx::fb *buffer, float64_t scale) { + adxi::rwinfo ri(this, e, scale, normal, FALSE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, ctl::dpx::fb *buffer, + float64_t scale, intmode_e mode) { + adxi::rwinfo ri(this, e, scale, mode, TRUE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, ctl::dpx::fb *buffer, + float64_t scale, intmode_e mode) { + adxi::rwinfo ri(this, e, scale, mode, TRUE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, ctl::dpx::fb *buffer, + float64_t scale, intmode_e mode) { + adxi::rwinfo ri(this, e, scale, mode, TRUE); + + adxi::read(i, e, buffer, ri); +} + +void adx::read(std::istream *i, uint8_t e, ctl::dpx::fb *buffer, + float64_t scale, intmode_e mode) { + adxi::rwinfo ri(this, e, scale, mode, TRUE); + + adxi::read(i, e, buffer, ri); +} + +}; diff --git a/lib/adx/adx_rw.cc b/lib/adx/adx_rw.cc new file mode 100644 index 00000000..2eba652d --- /dev/null +++ b/lib/adx/adx_rw.cc @@ -0,0 +1,327 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + + +#include "adx_rw.hh" +#include + +namespace ctl { +namespace adxi { + +rwinfo::rwinfo() { + clear(); +} + +rwinfo::rwinfo(const adx *that, uint8_t e, float64_t _scale, + adx::intmode_e _mode, bool is_integer) { + set(that, e, _scale, _mode, is_integer); +} + +void rwinfo::clear(void) { + bps=0; + datatype=0; + pack=0; + descriptor=0; + offset_to_data=0; + width=0; + height=0; + channels=0; + bytes_per_swap=0; + aligned=0; + direct=0; + scale=0; + need_byteswap=0; + mode=adx::normal; +} + +void rwinfo::set(const adx *that, uint8_t e, float64_t _scale, + adx::intmode_e _mode, bool is_integer) { + bps=that->elements[e].bits_per_sample; + pack=that->elements[e].actual_packing; + descriptor=that->elements[e].descriptor; + offset_to_data=that->elements[e].offset_to_data; + need_byteswap=that->_need_byteswap; + width=that->pixels_per_line; + height=that->lines_per_element; + scale=_scale; + + datatype=that->elements[e].data_sign; + + if(descriptor<50) { + // I don't quite get how the Color difference is supposed to work. + channels=1; + } else if(descriptor==50 || descriptor==53 || descriptor==157) { + channels=3; + } else if(descriptor==51 || descriptor==52) { + channels=4; + } else if(descriptor<100) { + channels=3; // Probably... There can be RGBA variants in this space. + } else if(descriptor==102) { + channels=3; + } else if(descriptor==101 || descriptor==103) { + channels=4; + } else if(descriptor==101) { + channels=5; + } else if(descriptor<150) { + channels=3; // Probably... There can be YCrCbA variants in this space. + } else if(descriptor>=150 && descriptor<=156) { + channels=2+descriptor-150; + } else if(descriptor==157) { + channels=3; + } else if(descriptor==158) { + channels=2; + } else { + channels=0; + // who knows... + } + + if(!strncasecmp(that->header_version, "V3.0", 2)) { + version=0x30; + } else if(!strncasecmp(that->header_version, "V2.0", 2)) { + version=0x20; + } else { + // If we don't recognize the header version string we assume + // That we're version 0x10. Note that we put the version number + // in the top 4 bits, in case we have to later add some other + // subtype information. + version=0x10; + } + + if(adx::isnull(pack)) { + // This happens on read (since on write the actual_packing is set + // by the validate function for writes) + if(version==0x30) { + pack=that->elements[e].packing; + } else { + packing_for_bps(that->elements[e].bits_per_sample, &pack, NULL); + // We need to maintain the same lower 2 bits as the packing + // in the file so that we don't shift in the wrong direction. + pack=(pack&~0x3)|(that->elements[e].packing&0x3); + } + } + + aligned=FALSE; + if((pack&0x7)==0) { + aligned=TRUE; + } + if(pack<8) { + bytes_per_swap=4; + } else if(pack<16) { + bytes_per_swap=2; + } else if(pack<24) { + bytes_per_swap=1; + } else if(pack<32) { + bytes_per_swap=8; + } else { + // XXX + } + + + direct=FALSE; + if((scale==0.0 || scale==1.0) && (bytes_per_swap*8)==bps) { + if((is_integer && datatype==0) || (!is_integer && datatype==2)) { + direct=TRUE; + } + } + + scale=_scale; + mode=_mode; +} + +uint64_t rwinfo::words_for_raw(uint8_t swap_boundary) const { + uint32_t samples_per_word; + uint64_t samples; + + samples_per_word=(swap_boundary*8)/bps; + samples=channels*width; + + return ((samples+samples_per_word-1)/samples_per_word)*height; +} + +uint64_t rwinfo::bytes_for_raw(void) const { + return words_for_raw(bytes_per_swap)*bytes_per_swap; +} + +void rwinfo::write_init(std::ostream *o, adx *h) { + uint32_t foo; + bool arch_is_little_endian; + + foo=0x01020304; + arch_is_little_endian=FALSE; + if(((uint8_t *)&foo)[0]==0x04) { + arch_is_little_endian=TRUE; + } + + if(o==NULL) { + h->current_ostream=NULL; + return; + } + + if(h->current_ostream==NULL) { + h->current_ostream=o; + if(h->compliance==adx::automatic) { + h->compliance=adx::adx1; + } + if(h->endian_mode==adx::default_endian_mode) { + h->endian_mode=adx::big_endian; + } + h->current_compliance=h->compliance; + h->current_endian_mode=h->endian_mode; + h->_need_byteswap=FALSE; + switch(h->endian_mode) { + case adx::default_endian_mode: + h->endian_mode=adx::big_endian; + // FALL THROUGH + + case adx::big_endian: + if(arch_is_little_endian) { + h->_need_byteswap=TRUE; + } + break; + + case adx::little_endian: + if(!arch_is_little_endian) { + h->_need_byteswap=TRUE; + } + break; + + case adx::native: + break; + + case adx::swapped: + h->_need_byteswap=TRUE; + break; + } + // WHY OH WHY OH WHY DO THEY HAVE THESE FIELDS BUT MARK THEM AS + // NON-CORE? + h->total_file_size=0; + h->generic_header_length=1664; + h->industry_header_length=384; + adx::nullify(&(h->data_offset)); + } + + if(h->current_ostream!=o) { + // XXX very, very bad... Wrote a plane, then tried to write another + // plane on a different ostream. + } + if(h->current_compliance!=h->compliance) { + // XXX changed validation level... This will probably end in tears... + } + if(h->current_endian_mode!=h->current_endian_mode) { + // XXX byteswap changed. this will probably end in tears... + } +} + +void rwinfo::find_home(adx *h, uint8_t element, uint64_t size) { + uint8_t i; + rwinfo info; + uint64_t eof; + uint64_t actual_eof; + uint64_t element_eod; + uint64_t actual_element_eod; + uint64_t actual_lengths[8]; + uint64_t lengths[8]; + + memset(actual_lengths, 0, sizeof(actual_lengths)); + memset(lengths, 0, sizeof(lengths)); + + if(!adx::isnull(h->elements[element].offset_to_data) && + h->elements[element].offset_to_data!=0) { + // The user set this himself... He gets to slit his own throat... + return; + } + + // If the offset to data has not been set. Same as above. The user + // should only set this if he *really* knows what he's doing. + if(adx::isnull(h->data_offset)) { + h->data_offset=1<<14; + } + + for(i=0; inumber_of_elements; i++) { + // The last three parameters are only used for determining + // conversion attributes. We just want to get the size. + info.set(h, element, 0.0, adx::normal, 0); + + actual_lengths[i]=info.bytes_for_raw(); + // And round things up to 16k boundaries. + lengths[i]=actual_lengths[i]+(1<<14)-1; + lengths[i]=lengths[i]&(~((1<<14)-1)); + } + + eof=h->data_offset; + actual_eof=h->data_offset; + for(i=0; inumber_of_elements; i++) { + if(i==element) { + continue; + } + element_eod=h->elements[i].offset_to_data+lengths[i]; + actual_element_eod=h->elements[i].offset_to_data+actual_lengths[i]; + + if(element_eod>eof) { + eof=element_eod; + } + + if(actual_element_eod>actual_eof) { + actual_eof=actual_element_eod; + } + } + + h->elements[element].offset_to_data=eof; + actual_eof=eof+actual_lengths[element]; + h->total_file_size=actual_eof; +} + +}; + +}; diff --git a/lib/adx/adx_rw.hh b/lib/adx/adx_rw.hh new file mode 100644 index 00000000..d240ed23 --- /dev/null +++ b/lib/adx/adx_rw.hh @@ -0,0 +1,154 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + + +#if !defined(AMPAS_CTL_ADX_RW_INCLUDE) +#define AMPAS_CTL_ADX_RW_INCLUDE + +#include + +namespace ctl { +namespace adxi { + +// The story behind readinfo_t: Because there large number of auxilliary +// functions to handle all of the potential conversions in reads and writes, +// and we don't want to have a gigantic friend section of the adx header, +// we build this (which only contains the required parameters, as well as +// a little bit of pre-processing) and pass it to all of the myriad functions +// that actually read and write things. +struct rwinfo { + rwinfo(); + rwinfo(const adx *that, uint8_t e, float64_t scale, adx::intmode_e mode, + bool is_integer); + + void clear(void); + void set(const adx *that, uint8_t e, float64_t scale, adx::intmode_e mode, + bool is_integer); + + // from the header + uint8_t bps; + uint8_t datatype; + uint16_t pack; + uint8_t descriptor; + uint32_t offset_to_data; + uint32_t width; + uint32_t height; + + // synthesized. + uint8_t channels; + uint8_t bytes_per_swap; + bool aligned; + uint8_t version; + + // True if our buffer is of the same type and alignment that we + // can just read the bits off the disk and put them in our buffer. + bool direct; + + // user options to top level read functions. + float64_t scale; + bool need_byteswap; + adx::intmode_e mode; + + // If writing into type 'T', given the bps, width, and height + // how many words of type 'T' will be needed to actually store + // with packing. + template + uint64_t words_for_raw(void) const; + + uint64_t words_for_raw(uint8_t swap_boundary) const; + uint64_t bytes_for_raw(void) const; + + // Some various helper functions. We might as well put them + // here because this struct is a friend of adx, and they + // have to modify the header. + // + // 1) If not already set in the header, fill out some basically sane + // parameters to be able to fit . + // 2) Makes sure that the user hasn't specified something completely out + // of whack in the header (we can't possibly write). + // + static void validate(adx *h, uint8_t element, uint8_t datatype, + uint8_t bps, uint8_t channels, uint64_t width, + uint64_t height); + + void validate_adx(adx *h, uint8_t element); + void validate_adx_strict(adx *h, uint8_t element); + // void validate_dpx(dpx *h, uint8_t element); + // void validate_dpx3(dpx *h, uint8_t element); + + // Used for adx 1.0 fields to set up the packing in the header vs + // what the actual packing is. + static void packing_for_bps(uint8_t bps, uint16_t *actual, + uint16_t *header); + + // Set up / check state variables when we start writing to try + // to prevent the user from doing anything *too* foolish when + // writing files. + static void write_init(std::ostream *o, adx *h); + + // Given an block of data of bytes 'size', find a place in the + // file that it will fit. Not the smartest search in the world. + static void find_home(adx *h, uint8_t element, uint64_t size); +}; + +template +uint64_t rwinfo::words_for_raw(void) const { + return words_for_raw(sizeof(T)); +} + +}; + +}; + +#endif diff --git a/lib/adx/adx_util.cc b/lib/adx/adx_util.cc new file mode 100644 index 00000000..63264bc0 --- /dev/null +++ b/lib/adx/adx_util.cc @@ -0,0 +1,92 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include "adx_util.hh" +#include +#include +#include +#include + +namespace ctl { + +namespace adxi { + +std::string strprintf(const char *fmt, ...) { + char *ptr; + int length=1024; + int need_len; + va_list ap; + + while(1) { + va_start(ap, fmt); + ptr=(char *)alloca(length); + memset(ptr, 0, length); + need_len=vsnprintf(ptr, length, fmt, ap); + va_end(ap); + if(need_len + +namespace ctl { + +namespace adxi { + +std::string strprintf(const char *fmt, ...); + +}; + +}; diff --git a/lib/adx/adx_validate.cc b/lib/adx/adx_validate.cc new file mode 100644 index 00000000..d3f95444 --- /dev/null +++ b/lib/adx/adx_validate.cc @@ -0,0 +1,387 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + + +#include "adx_rw.hh" + +namespace ctl { +namespace adxi { + +void rwinfo::packing_for_bps(uint8_t bps, uint16_t *actual, uint16_t *header) { + if(bps==8) { + if(header!=NULL) { + *header=0; + } + if(actual!=NULL) { + *actual=16; + } + } else if(bps==16) { + if(header!=NULL) { + *header=0; + } + if(actual!=NULL) { + *actual=8; + } + } else if(bps>=11 && bps<17) { + if(header!=NULL) { + *header=1; + } + if(actual!=NULL) { + *actual=9; + } + } else if(bps==10) { + if(header!=NULL) { + *header=1; + } + if(actual!=NULL) { + *actual=1; + } + } else { + // XXX + } +} + +void rwinfo::validate(adx *h, uint8_t element, uint8_t datatype, + uint8_t bps, uint8_t channels, uint64_t width, + uint64_t height) { + + unsigned long nan_f = static_cast(adx::udf32f); + float32_t nan_vf = *(float32_t *)&nan_f; + + // Make sure that all of the fields are filled out correctly... + if(adx::isnull(h->image_orientation)) { + h->image_orientation=0; + } + + if(adx::isnull(h->pixels_per_line)) { + h->pixels_per_line=width; + } + + if(adx::isnull(h->lines_per_element)) { + h->lines_per_element=height; + } + + if(adx::isnull(h->number_of_elements) + || h->number_of_elements<=element) { + h->number_of_elements=element+1; + } + + if(h->number_of_elements>2) { + // XXX too many elements... + h->_constraint_ok = FALSE; + fprintf(stderr, + "WARNING: adx field 18 -> Image Elements shall be" + "1 or 2. \n"); + h->number_of_elements = 2; + } + + if(adx::isnull(h->elements[element].bits_per_sample)) { + h->elements[element].bits_per_sample=bps; + } + else { + if(element == 0) { + if (h->elements[element].bits_per_sample != 16 + && h->elements[element].bits_per_sample != 10){ + THROW(Iex::ArgExc, + "Error: The Program does not Currently Support This Format"); + exit(1); + } + } + else if(element == 1) { + if (h->elements[element].bits_per_sample != 16 + && h->elements[element].bits_per_sample != 10 + && h->elements[element].bits_per_sample != 8 + && h->elements[element].bits_per_sample != 1){ + THROW(Iex::ArgExc, + "Error: The Program does not Currently Support This Format"); + exit(1); } + } + } + + h->elements[element].data_sign = 0x0; + h->elements[element].ref_low_data_code = 0x0; + h->elements[element].ref_low_quantity = nan_vf; + + if (adx::isnull(h->elements[element].ref_high_data_code)){ + if(h->elements[element].bits_per_sample == 16){ + h->elements[element].ref_high_data_code = 0xFFFF; + } + else if(h->elements[element].bits_per_sample == 10){ + h->elements[element].ref_high_data_code = 0x3FF; + } + else if(element == 1 && h->elements[element].bits_per_sample == 8){ + h->elements[element].ref_high_data_code = 0xFF; + } + else if(element == 1 && h->elements[element].bits_per_sample == 1){ + h->elements[element].ref_high_data_code = 0x1; + } + } + else { + if(element == 0) { + if(h->elements[element].ref_high_data_code != 0xFFFF + && h->elements[element].bits_per_sample == 16) { + h->elements[element].ref_high_data_code = 0xFFFF; + } + else if(h->elements[element].ref_high_data_code != 0x3FF + && h->elements[element].bits_per_sample == 10){ + h->elements[element].ref_high_data_code = 0x3FF; + } + } + else if (element == 1){ + if(h->elements[element].ref_high_data_code != 0xFFFF + && h->elements[element].bits_per_sample == 16) { + h->elements[element].ref_high_data_code = 0xFFFF; + } + else if(h->elements[element].ref_high_data_code != 0x3FF + && h->elements[element].bits_per_sample == 10){ + h->elements[element].ref_high_data_code = 0x3FF; + } + else if(h->elements[element].ref_high_data_code != 0xFF + && h->elements[element].bits_per_sample == 8){ + h->elements[element].ref_high_data_code = 0xFF; + } + else if(h->elements[element].ref_high_data_code != 0x1 + && h->elements[element].bits_per_sample == 1){ + h->elements[element].ref_high_data_code = 0x1; + } + } + } + + h->elements[element].ref_high_quantity = nan_vf; + + if(adx::isnull(h->elements[element].descriptor)) { + switch(channels) { + case 1: + if (element == 1) { + h->elements[element].descriptor = 4; // Alpha + } + break; + + case 3: + case 4: + if (element == 0) { + h->elements[element].descriptor = 50; // RGB + } + break; + + default: + fprintf(stderr, + "The Program does not Currently Support This Format"); + break; + } + } + else { + if(static_cast(element) == 0 + && static_cast(h->elements[element].descriptor) != 0x32) { + THROW(Iex::ArgExc, "The Program does not Currently Support This Format"); + exit(1); + } + else if(static_cast(element) == 1 + && static_cast(h->elements[element].descriptor) != 0x4) { + THROW(Iex::ArgExc, "The Program does not Currently Support This Format"); + exit(1); + } + } + + if(adx::isnull(h->elements[element].transfer_characteristic)) { + if(element == 0) { + h->elements[element].transfer_characteristic = 0xD; + } + else if(element == 1) { + h->elements[element].transfer_characteristic = 0x0; + } + } + else { + if(element == 0 + && static_cast(h->elements[element].transfer_characteristic) != 0xD) { + h->elements[element].transfer_characteristic = 0xD; + } + else if(element == 1 + && static_cast(h->elements[element].transfer_characteristic) != 0x0) { + h->elements[element].transfer_characteristic = 0x0; + } + } + + h->elements[element].colorimetric_characteristic= + h->elements[element].transfer_characteristic; + + // We have an 'actual_packing'Field which drives the writer to + // specify where the byte swaps occur, and a 'packing' field which + // is what is put in the header. We can thank the excessively vague + // adx 1.0 standard for this. + if(adx::isnull(h->elements[element].packing)) { + if(h->compliance==adx::adx1) { + packing_for_bps(h->elements[element].bits_per_sample, + &(h->elements[element].actual_packing), + &(h->elements[element].packing)); + } + } + else if(h->elements[element].bits_per_sample==16) { + // historic reasons... If we don't do this we'll + // break every dpx 1.0 reader known to man + h->elements[element].packing=0; + } else if(h->elements[element].bits_per_sample==10) { + h->elements[element].packing=1; + } else if(h->elements[element].bits_per_sample==8 + && element == 1) { + h->elements[element].packing=0; + } else if(h->elements[element].bits_per_sample==1 + && element == 1) { + h->elements[element].packing=0; + } else { + // XXX + } + + if(adx::isnull(h->elements[element].actual_packing)) { + h->elements[element].actual_packing=h->elements[element].packing; + } + + if(adx::isnull(h->elements[element].encoding)) { + h->elements[element].encoding=0; + } + + if(adx::isnull(h->elements[element].eol_padding)) { + h->elements[element].eol_padding=0; + } + + if(adx::isnull(h->elements[element].eoi_padding)) { + h->elements[element].eoi_padding=0; + } + + // Now we start doing general validation (i.e. things that won't + // possibly fly no mater what the validation_level is) + rwinfo info(h, element, 0, adx::normal, FALSE); + + if(h->image_orientation>=8) { + // XXX invalid image_orientation + } + + if(h->pixels_per_line!=width) { + // XXX invalid width + } + + if(h->lines_per_element!=height) { + // XXX invalid height + } + + if(info.channels!=channels) { + // XXX descriptor doesn't match channel count. + } + + if(bps>(info.bytes_per_swap*8)) { + // sample doesn't fit in swap boundary. + } + + if((info.bytes_per_swap*8)%bps) { + if((h->elements[element].packing&0x7)==0) { + // Invalid packing + } + } else { + if((h->elements[element].packing&0x7)>=3) { + // Invalid packing + } + } + + if(h->elements[element].eol_padding!=0) { + // EOL padding must be 0 + } + + if(h->elements[element].eoi_padding!=0) { + // EOI padding must be 0 + } + + if(h->elements[element].encoding!=0) { + // encoding must be 0 + } + + if(h->elements[element].data_sign!=0 && + h->elements[element].data_sign!=2) { + // invalid data_sign + } + + // Constraints for ADX 60-62 + + h->interlace = static_cast(adx::udf8); + h->field_number = static_cast(adx::udf8); + h->video_standard = static_cast(adx::udf8); + + // Constraints for ADX 64-73 + h->horizontal_sampling_rate = nan_vf; + h->temporal_sampling_rate = nan_vf; + h->time_offset_sync_to_first_pixel = nan_vf; + h->gamma = nan_vf; + h->black_level_code = nan_vf; + h->black_gain = nan_vf; + h->breakpoint = nan_vf; + h->white_level_code = nan_vf; + h->integration_time = nan_vf; +} + +void rwinfo::validate_adx_strict(adx *h, uint8_t element) { + // We don't do full validation yet... + validate_adx(h, element); +} + +void rwinfo::validate_adx(adx *h, uint8_t element) { +} + +// void rwinfo::validate_dpx(dpx *h, uint8_t element) { +// } + +// void rwinfo::validate_dpx3(dpx *h, uint8_t element) { +// } + +}; + +}; diff --git a/lib/adx/adx_write.cc b/lib/adx/adx_write.cc new file mode 100644 index 00000000..89828a3d --- /dev/null +++ b/lib/adx/adx_write.cc @@ -0,0 +1,330 @@ +/////////////////////////////////////////////////////////////////////////// +// Copyright (c) 2013 Academy of Motion Picture Arts and Sciences +// ("A.M.P.A.S."). Portions contributed by others as indicated. +// All rights reserved. +// +// A worldwide, royalty-free, non-exclusive right to copy, modify, create +// derivatives, and use, in source and binary forms, is hereby granted, +// subject to acceptance of this license. Performance of any of the +// aforementioned acts indicates acceptance to be bound by the following +// terms and conditions: +// +// * Copies of source code, in whole or in part, must retain the +// above copyright notice, this list of conditions and the +// Disclaimer of Warranty. +// +// * Use in binary form must retain the above copyright notice, +// this list of conditions and the Disclaimer of Warranty in the +// documentation and/or other materials provided with the distribution. +// +// * Nothing in this license shall be deemed to grant any rights to +// trademarks, copyrights, patents, trade secrets or any other +// intellectual property of A.M.P.A.S. or any contributors, except +// as expressly stated herein. +// +// * Neither the name "A.M.P.A.S." nor the name of any other +// contributors to this software may be used to endorse or promote +// products derivative of or based on this software without express +// prior written permission of A.M.P.A.S. or the contributors, as +// appropriate. +// +// This license shall be construed pursuant to the laws of the State of +// California, and any disputes related thereto shall be subject to the +// jurisdiction of the courts therein. +// +// Disclaimer of Warranty: THIS SOFTWARE IS PROVIDED BY A.M.P.A.S. AND +// CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, +// BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS +// FOR A PARTICULAR PURPOSE, AND NON-INFRINGEMENT ARE DISCLAIMED. IN NO +// EVENT SHALL A.M.P.A.S., OR ANY CONTRIBUTORS OR DISTRIBUTORS, BE LIABLE +// FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, RESITUTIONARY, +// OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF +// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS +// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN +// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) +// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF +// THE POSSIBILITY OF SUCH DAMAGE. +// +// WITHOUT LIMITING THE GENERALITY OF THE FOREGOING, THE ACADEMY +// SPECIFICALLY DISCLAIMS ANY REPRESENTATIONS OR WARRANTIES WHATSOEVER +// RELATED TO PATENT OR OTHER INTELLECTUAL PROPERTY RIGHTS IN THE ACADEMY +// COLOR ENCODING SYSTEM, OR APPLICATIONS THEREOF, HELD BY PARTIES OTHER +// THAN A.M.P.A.S., WHETHER DISCLOSED OR UNDISCLOSED. +/////////////////////////////////////////////////////////////////////////// + +#include + +#include +#include "adx_raw.hh" +#include +#include +#include "adx_bits.hh" +#include "adx_rw.hh" + +namespace ctl { +namespace adxi { + +template +void pack(ctl::dpx::fb *out, const ctl::dpx::fb &in, const rwinfo &ri) { + uint64_t u, v; + uint8_t pad, onbit; + O mask; + O t; + O *o; + const I *i=in.ptr(); + + out->init(ri.words_for_raw(), 1, 1); + + o=out->ptr(); + +#if 1 + if(ri.bps==10) { + if(ri.pack==1) { + for(u=0; upixels(); u++) { + *o=i[0]&0x3ff; + *o=*o<<10; + *o=*o|(i[1]&0x3ff); + *o=*o<<10; + *o=*o|(i[2]&0x3ff); + *o=*o<<2; + i=i+3; + o++; + } + return; + } else if(ri.pack==2) { + for(u=0; upixels(); u++) { + *o=i[0]&0x3ff; + *o=*o<<10; + *o=*o|(i[1]&0x3ff); + *o=*o<<10; + *o=*o|(i[2]&0x3ff); + i=i+3; + o++; + } + return; + } + } +#endif + + mask=max_int_for_bits[ri.bps]; + + if((ri.pack&0x7)==0) { + // XXX not supported + } else if((ri.pack&0x7)==1) { + pad=(sizeof(I)*8)%ri.bps; + } else if((ri.pack&0x7)==2) { + pad=0; + } else { + // XXX not supported + } + + onbit=sizeof(O)*8; + t=0; + for(u=0; uheight(); u++) { + if(onbit!=sizeof(O)*8) { + t=t<width(); v++) { + if(onbit +void write_fb(std::ostream *o, const ctl::dpx::fb &buf, const rwinfo &wi) { + ctl::dpx::fb fbu64; + ctl::dpx::fb fbu32; + ctl::dpx::fb fbu16; + ctl::dpx::fb fbu8; + + if(wi.pack<8) { + if(wi.bps==32) { + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else if(wi.datatype==0 && (wi.pack==1 || wi.pack==2)) { + pack(&fbu32, buf, wi); + write_ptr(o, fbu32.ptr(), fbu32.count(), wi.need_byteswap); + } else { + // XXX + } + } else if(wi.pack<16) { + if(wi.bps==16) { + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else if(wi.datatype==0 && (wi.pack==9 || wi.pack==10)) { + pack(&fbu16, buf, wi); + write_ptr(o, fbu16.ptr(), fbu16.count(), wi.need_byteswap); + } else { + // XXX + } + } else if(wi.pack<24) { + if(wi.bps==8) { + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else if(wi.datatype==0 && (wi.pack==17 || wi.pack==18)) { + pack(&fbu32, buf, wi); + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else { + // XXX + } + } else if(wi.pack<32) { + if(wi.bps==64) { + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else if(wi.datatype==0 && (wi.pack==25 || wi.pack==26)) { + pack(&fbu64, buf, wi); + write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap); + } else { + // XXX + } + } else { + // XXX + } +} + +template +void write(std::ostream *o, const ctl::dpx::fb &buf, const rwinfo &wi) { + ctl::dpx::fb fbu64; + ctl::dpx::fb fbu32; + ctl::dpx::fb fbu16; + ctl::dpx::fb fbu8; + ctl::dpx::fb fbf16; + ctl::dpx::fb fbf32; + ctl::dpx::fb fbf64; + + + if(wi.datatype==0) { + if(wi.bps<=8) { + fbu8.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbu8, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + write_fb(o, fbu8, wi); + } else if(wi.bps<=16) { + fbu16.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbu16, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + write_fb(o, fbu16, wi); + } else if(wi.bps<=32) { + fbu32.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbu32, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + write_fb(o, fbu32, wi); + } else if(wi.bps<=64) { + fbu64.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbu64, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + write_fb(o, fbu64, wi); + } else { + // XXX + } + } else if(wi.datatype==2) { + if(wi.bps==16) { + fbf16.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbf16, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + if(wi.pack>=8 && wi.pack<=10) { + write_ptr(o, fbf64.ptr(), fbf64.count(), wi.need_byteswap); + } + } else if(wi.bps==32) { + fbf32.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbf32, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + if(/*wi.pack>=0 &&*/ wi.pack<=2) { + write_ptr(o, fbf32.ptr(), fbf32.count(), wi.need_byteswap); + } + } else if(wi.bps==64) { + fbf64.init(buf.width(), buf.height(), buf.depth()); + convertfb(&fbf64, wi.bps, buf.ptr(), sizeof(T)*8, wi.scale); + if(wi.pack>=24 && wi.pack<=26) { + write_ptr(o, fbf64.ptr(), fbf64.count(), wi.need_byteswap); + } + } else { + // XXX + } + } else { + // XXX + } +} + +template +void write(std::ostream *o, adx *h, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale, adx::intmode_e mode) { + std::ostream::pos_type start; + rwinfo wi; + + start=o->tellp(); + + rwinfo::write_init(o, h); + + if (element >=2 ) { + fprintf(stderr, + "Existing ........\n" + "The ADX format should have \n" + "at most two elements\n"); + exit(1); + } + + if(mode!=adx::unformatted) { + rwinfo::validate(h, element, 2*!(std::numeric_limits::is_integer), + sizeof(T)*8, buffer.depth(), buffer.width(), + buffer.height()); + } + + wi.set(h, element, scale, mode, FALSE); + + if(mode==adx::unformatted || wi.direct) { + rwinfo::find_home(h, element, buffer.length()); + o->seekp(start+((std::streamoff)h->elements[element].offset_to_data)); + adxi::write_ptr(o, buffer.ptr(), buffer.count(), wi.need_byteswap); + } else { + rwinfo::find_home(h, element, wi.bytes_for_raw()); + o->seekp(start+((std::streamoff)h->elements[element].offset_to_data)); + adxi::write(o, buffer, wi); + + } + + o->seekp(start); +} +}; + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale) { + adxi::write(o, this, element, buffer, scale, adx::normal); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale) { + adxi::write(o, this, element, buffer, scale, adx::normal); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale) { + adxi::write(o, this, element, buffer, scale, adx::normal); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale, intmode_e mode) { + adxi::write(o, this, element, buffer, scale, mode); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale, intmode_e mode) { + adxi::write(o, this, element, buffer, scale, mode); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale, intmode_e mode) { + adxi::write(o, this, element, buffer, scale, mode); +} + +void adx::write(std::ostream *o, uint8_t element, const ctl::dpx::fb &buffer, + float64_t scale, intmode_e mode) { + adxi::write(o, this, element, buffer, scale, mode); +} + +}; diff --git a/lib/dpx/dpx.cc b/lib/dpx/dpx.cc index 67cbc430..13462dd4 100644 --- a/lib/dpx/dpx.cc +++ b/lib/dpx/dpx.cc @@ -480,6 +480,8 @@ void dpx::write(std::ostream *os) dpxi::write_uint16(os, elements[i].packing, _need_byteswap); } dpxi::write_uint16(os, elements[i].encoding, _need_byteswap); + + // offset to the image data dpxi::write_uint32(os, elements[i].offset_to_data, _need_byteswap); dpxi::write_uint32(os, elements[i].eol_padding, _need_byteswap); dpxi::write_uint32(os, elements[i].eoi_padding, _need_byteswap); diff --git a/lib/dpx/dpx.hh b/lib/dpx/dpx.hh index 02ae8331..bb1f7e92 100644 --- a/lib/dpx/dpx.hh +++ b/lib/dpx/dpx.hh @@ -352,6 +352,7 @@ struct dpx { // channel (set descriptor==0 if the data has already been // formatted into RGBA or YA). void swizzle(uint8_t descriptor, bool squish_alpha); + void channelAdjust(uint8_t descriptor); // Indicates if the data has an alpha channel. bool alpha() const; @@ -624,8 +625,8 @@ struct dpx { static std::string descriptor_to_string(uint8_t id); }; -#include - +//#include +#include "dpx.tcc" } diff --git a/lib/dpx/dpx.tcc b/lib/dpx/dpx.tcc index 8d5b5008..c3095755 100644 --- a/lib/dpx/dpx.tcc +++ b/lib/dpx/dpx.tcc @@ -209,6 +209,8 @@ void dpx::fb::swizzle(uint8_t descriptor, bool squish_alpha) { t=i[2]; o[2]=i[1]; o[1]=t; + i=i+4; + o=o+4; } _depth=3; } else { @@ -226,6 +228,74 @@ void dpx::fb::swizzle(uint8_t descriptor, bool squish_alpha) { break; } } +template +void ctl::dpx::fb::channelAdjust(uint8_t descriptor){ + uint64_t u, count; + T *i, *o; + T t; + + count=width()*height(); + + i=_data; + o=_data; + + switch(descriptor) { + case 0: // user defined + case 6: // luminance + case 157: // XYZ + case 158: // luminance, alpha + break; + + case 50: + break; + + case 51: // RGBA + for(u=0; u bool ctl::dpx::fb::alpha() const { diff --git a/lib/dpx/dpx_rw.cc b/lib/dpx/dpx_rw.cc index 9c7b2d62..35cd93c9 100644 --- a/lib/dpx/dpx_rw.cc +++ b/lib/dpx/dpx_rw.cc @@ -182,9 +182,10 @@ void rwinfo::set(const dpx *that, uint8_t e, float64_t _scale, uint64_t rwinfo::words_for_raw(uint8_t swap_boundary) const { uint32_t samples_per_word; uint64_t samples; - + samples_per_word=(swap_boundary*8)/bps; samples=channels*width; + return ((samples+samples_per_word-1)/samples_per_word)*height; } diff --git a/lib/dpx/dpx_write.cc b/lib/dpx/dpx_write.cc index 683638fd..4de32083 100644 --- a/lib/dpx/dpx_write.cc +++ b/lib/dpx/dpx_write.cc @@ -74,7 +74,7 @@ void pack(dpx::fb *out, const dpx::fb &in, const rwinfo &ri) { const I *i=in.ptr(); out->init(ri.words_for_raw(), 1, 1); - + o=out->ptr(); #if 1 @@ -151,7 +151,12 @@ void write_fb(std::ostream *o, const dpx::fb &buf, const rwinfo &wi) { dpx::fb fbu32; dpx::fb fbu16; dpx::fb fbu8; - + +// std::cout << "I am here." << std::endl; +// std::cout << fbu32.count() << std::endl; +// std::cout << (uint32_t)wi.bps << std::endl; +// std::cout << (uint32_t)wi.pack << std::endl; + if(wi.pack<8) { if(wi.bps==32) { write_ptr(o, buf.ptr(), buf.count(), wi.need_byteswap);