├── .github └── workflows │ └── main.yml ├── .gitignore ├── .gitmodules ├── CMakeLists.txt ├── LICENSE ├── README.md └── src ├── main ├── CodestreamSequence.cpp ├── CodestreamSequence.h ├── J2KProfileULMap.h ├── jid-reader.cpp └── jid-writer.cpp └── test └── resources ├── README.md ├── crowdrun-lowlatency.1920x1080-422-10bit-50p.mjc ├── j2c-sequence ├── mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000000.j2c └── mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000001.j2c ├── part1.j2c ├── part1.mjc ├── part15.j2c ├── part15.mjc └── yuv422_10b_p15.j2c /.github/workflows/main.yml: -------------------------------------------------------------------------------- 1 | name: build and test 2 | 3 | on: push 4 | 5 | jobs: 6 | build: 7 | runs-on: ubuntu-latest 8 | 9 | steps: 10 | - name: install dependencies 11 | run: | 12 | sudo apt-get install libboost-all-dev 13 | sudo apt-get install libxerces-c-dev 14 | sudo apt-get install libssl-dev 15 | sudo apt-get install cmake 16 | 17 | - name: checkout repo 18 | uses: actions/checkout@v2 19 | 20 | - name: checkout submodules 21 | run: git submodule update --init --recursive 22 | 23 | - name: cmake initialization 24 | run: | 25 | mkdir build 26 | cd build 27 | cmake .. 28 | 29 | - name: build 30 | run: | 31 | cd build 32 | make 33 | 34 | - name: test 35 | run: | 36 | cd build 37 | ctest 38 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /build 2 | /.vscode 3 | /.devcontainer -------------------------------------------------------------------------------- /.gitmodules: -------------------------------------------------------------------------------- 1 | [submodule "lib/asdcplib"] 2 | path = lib/asdcplib 3 | url = https://github.com/sandflow/asdcplib.git 4 | -------------------------------------------------------------------------------- /CMakeLists.txt: -------------------------------------------------------------------------------- 1 | cmake_minimum_required (VERSION 2.8) 2 | project(jid) 3 | 4 | # import boost 5 | 6 | set(Boost_USE_STATIC_LIBS ON) 7 | set(Boost_USE_MULTITHREADED ON) 8 | find_package(Boost REQUIRED COMPONENTS program_options) 9 | include_directories(${Boost_INCLUDE_DIR}) 10 | 11 | # import asdcplib 12 | 13 | add_subdirectory(lib/asdcplib) 14 | include_directories(lib/asdcplib/src) 15 | 16 | if(WIN32) 17 | add_definitions(/DKM_WIN32 /D_CONSOLE /DASDCP_PLATFORM=\"win32\" /D_CRT_SECURE_NO_WARNINGS /D_CRT_NONSTDC_NO_WARNINGS) 18 | set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} /SAFESEH:NO") 19 | elseif(UNIX) 20 | add_definitions(/DASDCP_PLATFORM=\"unix\") 21 | endif(WIN32) 22 | 23 | # coomon includes 24 | 25 | include_directories(src/main) 26 | 27 | # jid-writer 28 | 29 | set(JID_WRITER "jid-writer") 30 | add_executable(${JID_WRITER} src/main/jid-writer.cpp src/main/CodestreamSequence.cpp) 31 | target_link_libraries(${JID_WRITER} ${Boost_LIBRARIES} libas02) 32 | 33 | # jid-reader 34 | 35 | set(JID_READER "jid-reader") 36 | add_executable(${JID_READER} src/main/jid-reader.cpp) 37 | target_link_libraries(${JID_READER} ${Boost_LIBRARIES} libas02) 38 | 39 | # tests 40 | 41 | enable_testing() 42 | 43 | add_test(NAME "part1-j2c-wrapping" COMMAND ${JID_WRITER} --in "${PROJECT_SOURCE_DIR}/src/test/resources/part1.j2c" --format J2C --out part1-j2c.mxf) 44 | 45 | add_test(NAME "part15-j2c-wrapping" COMMAND ${JID_WRITER} --in "${PROJECT_SOURCE_DIR}/src/test/resources/part15.j2c" --format J2C --out part15-j2c.mxf) 46 | 47 | add_test(NAME "part1-mjc-wrapping" COMMAND ${JID_WRITER} --in "${PROJECT_SOURCE_DIR}/src/test/resources/part1.mjc" --format MJC --out part1-mjc.mxf) 48 | 49 | add_test(NAME "mjc-cbr-wrapping" COMMAND ${JID_WRITER} --in "${PROJECT_SOURCE_DIR}/src/test/resources/crowdrun-lowlatency.1920x1080-422-10bit-50p.mjc" --color COLOR.3 --quantization QE.1 --components YCbCr --format MJC --out part15-mjc-cbr.mxf) 50 | 51 | add_test(NAME "part15-mjc-wrapping" COMMAND ${JID_WRITER} --in "${PROJECT_SOURCE_DIR}/src/test/resources/part15.mjc" --format MJC --out part15-mjc.mxf) 52 | 53 | add_test(NAME "yuv422_10b_p15-wrapping" COMMAND ${JID_WRITER} --color COLOR.3 --quantization QE.1 --components YCbCr --format J2C --in "${PROJECT_SOURCE_DIR}/src/test/resources/yuv422_10b_p15.j2c" --out yuv422_10b_p15.mxf) 54 | 55 | add_test(NAME "j2c-seq-wrapping" COMMAND ${JID_WRITER} --color COLOR.3 --quantization QE.1 --components YCbCr --format J2C --in "${PROJECT_SOURCE_DIR}/src/test/resources/j2c-sequence" --out j2c-seq.mxf) 56 | 57 | add_test(NAME "j2c-wrapping-with-areas" COMMAND ${JID_WRITER} 58 | --in "${PROJECT_SOURCE_DIR}/src/test/resources/part1.j2c" 59 | --out j2c-wrapping-with-areas.mxf 60 | --format J2C 61 | --display_area 10 20 1000 1010 62 | --active_area 10 20 500 510 63 | ) 64 | 65 | add_test(NAME "j2c-wrapping-with-color-volume" COMMAND ${JID_WRITER} 66 | --in "${PROJECT_SOURCE_DIR}/src/test/resources/part1.j2c" 67 | --out j2c-wrapping-with-color-volume.mxf 68 | --format J2C 69 | --color COLOR.3 70 | --mastering_display_primaries 35400 14600 8500 39850 6550 2300 71 | --mastering_display_white_point_chroma 15635 16450 72 | --mastering_display_max_luminance 10000000 73 | --mastering_display_min_luminance 50 74 | ) 75 | 76 | set(J2C_OUT_DIR ${CMAKE_CURRENT_BINARY_DIR}/j2c-out) 77 | 78 | file(MAKE_DIRECTORY ${J2C_OUT_DIR}) 79 | 80 | add_test(NAME "unwrapping-j2c" COMMAND ${JID_READER} --in part1-mjc.mxf --format J2C --out ${J2C_OUT_DIR}) 81 | 82 | add_test(NAME "unwrapping-mjc-file" COMMAND ${JID_READER} --in part1-mjc.mxf --format MJC --out "out.mjc") 83 | 84 | # compiler settings 85 | 86 | set_property(DIRECTORY PROPERTY CXX_STANDARD 11) 87 | set_property(DIRECTORY PROPERTY LINKER_LANGUAGE CXX) 88 | 89 | # force warnings to be treated as errors 90 | 91 | if ( CMAKE_COMPILER_IS_GNUCC ) 92 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wall") 93 | endif ( CMAKE_COMPILER_IS_GNUCC ) 94 | 95 | if ( MSVC ) 96 | set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} /W4") 97 | endif ( MSVC ) -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | BSD 2-Clause License 2 | 3 | Copyright (c) 2020, Sandflow Consulting 4 | All rights reserved. 5 | 6 | Redistribution and use in source and binary forms, with or without 7 | modification, are permitted provided that the following conditions are met: 8 | 9 | 1. Redistributions of source code must retain the above copyright notice, this 10 | list of conditions and the following disclaimer. 11 | 12 | 2. Redistributions in binary form must reproduce the above copyright notice, 13 | this list of conditions and the following disclaimer in the documentation 14 | and/or other materials provided with the distribution. 15 | 16 | THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 17 | AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 18 | IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 19 | DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE 20 | FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 21 | DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 22 | SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER 23 | CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 | OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 25 | OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 26 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # JPEG 2000 to IMF DCDM (jid) 2 | 3 | _THIS IS EXPERIMENTAL SOFTWARE_ 4 | 5 | Wraps/unwraps JPEG 2000 codestreams to/from an Image Track File as specified in SMPTE ST 2067-21 (App 2E) and (proposed) SMPTE ST 2067-40 (App 4) 6 | 7 | ## Prerequisites 8 | 9 | * xerces (required by asdcplib) 10 | * openssl (required by asdcplib) 11 | * boost::program_options 12 | * cmake 13 | 14 | ## Known limitations 15 | 16 | * Does not support interlaced images 17 | * Supported input/output formats: 18 | * MJC codestream sequence 19 | * individual J2C codestreams 20 | 21 | ## Examples uses 22 | 23 | ### Coding/wrapping performance testing 24 | 25 | The following use the demonstration encoder/decoder available at . 26 | 27 | #### JPEG 2000 Part 1 28 | 29 | ``` 30 | time ( kdu_v_compress -i ~/Downloads/tiff-files/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+100 -o - \ 31 | Simf="{6,0,rev}" -in_prec 12M -num_threads 1 \ 32 | | jid-writer --format MJC --out ~/Downloads/part1-r.mxf ) 33 | ``` 34 | 35 | #### High-throughput JPEG 2000 36 | 37 | ``` 38 | time ( kdu_v_compress -i ~/Downloads/tiff-files/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+100 -o - Corder="CPRL" Clevels="{6}" \ 39 | Cprecincts="{256,256},{256,256},{256,256},{256,256},{256,256},{256,256},{128,128}" ORGgen_tlm="{3}" ORGtparts=C Cblk="{32,32}" \ 40 | -num_threads 1 Creversible=yes Cmodes=HT -in_prec 12M | jid-writer --format MJC --out ~/Downloads/part15-r.mxf ) 41 | ``` 42 | 43 | ### Coding/wrapping typical use 44 | 45 | #### JPEG 2000 Part 1 46 | 47 | ``` 48 | kdu_v_compress -i ~/Downloads/tiff-files/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+100 -o - Simf="{6,0,rev}" -in_prec 12M \ 49 | | jid-writer --format MJC --out ~/Downloads/part1-r.mxf 50 | ``` 51 | 52 | #### High-throughput JPEG 2000 53 | 54 | ``` 55 | kdu_v_compress -i ~/Downloads/tiff-files/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+100 -o - Corder="CPRL" Clevels="{6}" \ 56 | Cprecincts="{256,256},{256,256},{256,256},{256,256},{256,256},{256,256},{128,128}" ORGgen_tlm="{3}" ORGtparts=C Cblk="{32,32}" Creversible=yes Cmodes=HT -in_prec 12M \ 57 | | jid-writer --format MJC --out ~/Downloads/part15-r.mxf 58 | ``` 59 | 60 | ### Unwrapping example use 61 | 62 | ``` 63 | mkdir ~/Downloads/j2c-out 64 | jid-reader --in ~/Downloads/part15-r.mxf --format J2C --out ~/Downloads/j2c-out 65 | ``` 66 | 67 | ## Ubuntu build instructions 68 | 69 | ``` 70 | sudo apt-get install libboost-all-dev 71 | sudo apt-get install libxerces-c-dev 72 | sudo apt-get install libssl-dev 73 | sudo apt-get install cmake 74 | 75 | git clone --recurse-submodules https://github.com/sandflow/jid.git 76 | cd jid 77 | mkdir build 78 | cd build 79 | cmake -DCMAKE_BUILD_TYPE=Release .. 80 | make 81 | 82 | #tests 83 | 84 | ctest 85 | ``` 86 | 87 | ## MacOS build instructions 88 | 89 | ``` 90 | brew install boost 91 | brew install xerces-c 92 | brew install openssl 93 | brew install cmake 94 | 95 | git clone --recurse-submodules https://github.com/sandflow/jid.git 96 | cd jid 97 | mkdir build 98 | cd build 99 | cmake -DCMAKE_BUILD_TYPE=Release -DOpenSSLLib_include_DIR=/usr/local/opt/openssl@1.1/include \ 100 | -DOpenSSLLib_PATH=/usr/local/opt/openssl@1.1/lib/libcrypto.dylib .. 101 | make 102 | 103 | #tests 104 | 105 | ctest 106 | ``` 107 | 108 | ## Microsoft Visual Studio build instructions (MSVC) 109 | 110 | * install OpenSSL v1.0.2u binaries from https://slproweb.com/products/Win32OpenSSL.html 111 | * install boost binaries from 112 | https://sourceforge.net/projects/boost/files/boost-binaries/1.72.0/ 113 | * download xerces c++ from http://xerces.apache.org/mirrors.cgi and 114 | build using MSVC 115 | * configure and generate an MSVC project using [CMake GUI](https://cmake.org/runningcmake/), setting: 116 | * `Boost_INCLUDE_DIR`, e.g. `"C:/bin/boost_1_72_0"` 117 | * `XercescppLib_PATH`, e.g. `"C:/bin/xerces-c/lib/xerces-c_3.lib"` 118 | * `XercescppLib_Debug_PATH`, e.g. `"C:/bin/xerces-c/lib/xerces-c_3D.lib"` 119 | * `XercescppLib_include_DIR`, e.g. `"C:/bin/xerces-c/include"` 120 | * `OpenSSLLib_PATH`, e.g. `"C:/bin/OpenSSL-Win64/lib/libeay32.lib"` 121 | * `OpenSSLLib_include_DIR`, e.g. `"C:/bin/OpenSSL-Win64/include"` 122 | -------------------------------------------------------------------------------- /src/main/CodestreamSequence.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), Pierre-Anthony Lemieux (pal@palemieux.com) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include "CodestreamSequence.h" 28 | #include 29 | #include 30 | 31 | /* J2CFile */ 32 | 33 | J2CFile::J2CFile(FILE *fp, 34 | std::vector::size_type initial_buf_sz, 35 | std::vector::size_type read_buf_sz) : 36 | good_(true), 37 | codestream_(), 38 | file_paths_stack_(), 39 | initial_buf_sz_(initial_buf_sz), 40 | read_buf_sz_(read_buf_sz) 41 | { 42 | this->_fill_from_fp(fp); 43 | }; 44 | 45 | J2CFile::J2CFile(const std::vector& file_paths, 46 | std::vector::size_type initial_buf_sz, 47 | std::vector::size_type read_buf_sz) : 48 | good_(true), 49 | codestream_(), 50 | file_paths_stack_(file_paths.rbegin(), file_paths.rend()), 51 | initial_buf_sz_(initial_buf_sz), 52 | read_buf_sz_(read_buf_sz) 53 | { 54 | this->next(); 55 | }; 56 | 57 | void J2CFile::_fill_from_fp(FILE* fp) { 58 | 59 | this->codestream_.reserve(this->initial_buf_sz_); 60 | this->codestream_.resize(0); 61 | 62 | while (true) { 63 | 64 | std::vector::size_type old_sz = this->codestream_.size(); 65 | 66 | this->codestream_.resize(old_sz + this->read_buf_sz_); 67 | 68 | size_t sz = fread(this->codestream_.data() + old_sz, 1, this->read_buf_sz_, fp); 69 | 70 | if (sz != this->read_buf_sz_) { 71 | 72 | this->codestream_.resize(old_sz + sz); 73 | 74 | break; 75 | } 76 | } 77 | } 78 | 79 | void J2CFile::next() { 80 | 81 | if (this->file_paths_stack_.size() == 0) { 82 | 83 | this->good_ = false; 84 | 85 | return; 86 | 87 | } 88 | 89 | FILE* fp = fopen(file_paths_stack_.back().c_str(), "rb"); 90 | 91 | 92 | if (!fp) { 93 | throw std::runtime_error("Cannot open file: " + file_paths_stack_.back()); 94 | } 95 | 96 | this->_fill_from_fp(fp); 97 | 98 | fclose(fp); 99 | 100 | file_paths_stack_.pop_back(); 101 | 102 | }; 103 | 104 | bool J2CFile::good() const { return this->good_; }; 105 | 106 | void J2CFile::fill(ASDCP::JP2K::FrameBuffer &fb) 107 | { 108 | ASDCP::Result_t result = ASDCP::RESULT_OK; 109 | 110 | result = fb.SetData(this->codestream_.data(), (uint32_t)this->codestream_.size()); 111 | 112 | if (ASDCP_FAILURE(result)) { 113 | throw std::runtime_error("Frame buffer allocation failed"); 114 | } 115 | 116 | assert(ASDCP_SUCCESS(result)); 117 | 118 | uint32_t sz = fb.Size((uint32_t)this->codestream_.size()); 119 | 120 | if (sz != this->codestream_.size()) { 121 | throw std::runtime_error("Frame buffer resizing failed"); 122 | } 123 | 124 | }; 125 | 126 | /* MJCFile */ 127 | 128 | MJCFile::MJCFile(FILE *fp) : good_(true), codestream_len_(0), codestream_(), fp_(fp) 129 | { 130 | 131 | uint8_t header[16]; 132 | 133 | size_t sz = fread(header, 1, sizeof header, this->fp_); 134 | 135 | if (sz != sizeof header || header[0] != 'M' || header[1] != 'J' || header[2] != 'C' || header[3] != '2') 136 | { 137 | throw std::runtime_error("Bad MJC file"); 138 | } 139 | 140 | this->is_cbr_ = header[15] & 4; 141 | 142 | this->next(); 143 | } 144 | 145 | void MJCFile::next() 146 | { 147 | 148 | size_t rd_sz; 149 | 150 | /* get codestream length */ 151 | 152 | uint32_t len; 153 | 154 | if (!this->is_cbr_ || this->codestream_len_ == 0) { 155 | 156 | /* read the codestream length for every codestream if in vbr mode 157 | * otherwise read it from the first codestream only 158 | */ 159 | 160 | uint8_t be_len[4]; 161 | 162 | rd_sz = fread(be_len, 1, sizeof be_len, this->fp_); 163 | 164 | if (rd_sz != sizeof be_len) { 165 | this->good_ = false; 166 | return; 167 | } 168 | 169 | len = (be_len[0] << 24) + (be_len[1] << 16) + (be_len[2] << 8) + be_len[3]; 170 | 171 | if (this->is_cbr_) { 172 | 173 | if (len == 0) { 174 | throw std::runtime_error("MJC CBR length is 0"); 175 | } 176 | 177 | this->codestream_len_ = len; 178 | } 179 | 180 | } else { 181 | 182 | len = this->codestream_len_; 183 | 184 | } 185 | 186 | /* read codestream */ 187 | 188 | this->codestream_.resize(len); 189 | 190 | rd_sz = fread(this->codestream_.data(), 1, len, this->fp_); 191 | 192 | if (rd_sz != len) 193 | { 194 | this->good_ = false; 195 | return; 196 | } 197 | 198 | /* trim codestream to EOC if CBR */ 199 | 200 | if (this->is_cbr_) { 201 | auto it = std::find(this->codestream_.rbegin(), this->codestream_.rend(), 0xd9); 202 | 203 | if (it == this->codestream_.rend()) { 204 | throw std::runtime_error("Codestream is missing an EOC marker"); 205 | } 206 | 207 | this->codestream_.resize(std::distance(it, this->codestream_.rend())); 208 | } 209 | 210 | }; 211 | 212 | bool MJCFile::good() const { return this->good_; }; 213 | 214 | void MJCFile::fill(ASDCP::JP2K::FrameBuffer &fb) 215 | { 216 | ASDCP::Result_t result = ASDCP::RESULT_OK; 217 | 218 | result = fb.SetData(this->codestream_.data(), (uint32_t)this->codestream_.size()); 219 | 220 | if (ASDCP_FAILURE(result)) { 221 | throw std::runtime_error("Frame buffer allocation failed"); 222 | } 223 | 224 | uint32_t sz = fb.Size((uint32_t)this->codestream_.size()); 225 | 226 | if (sz != this->codestream_.size()) { 227 | throw std::runtime_error("Frame buffer resizing failed"); 228 | } 229 | }; 230 | 231 | /* FakeSequence */ 232 | 233 | FakeSequence::FakeSequence(uint32_t frame_count, uint32_t frame_size) : 234 | frame_count_(frame_count), cur_frame_(0), codestream_(frame_size) 235 | { 236 | std::copy(CODESTREAM_HEADER_, CODESTREAM_HEADER_ + sizeof CODESTREAM_HEADER_, codestream_.begin()); 237 | 238 | std::fill(codestream_.begin() + sizeof CODESTREAM_HEADER_, codestream_.end(), (uint8_t)0x00); 239 | }; 240 | 241 | void FakeSequence::next() 242 | { 243 | this->cur_frame_++; 244 | }; 245 | 246 | bool FakeSequence::good() const { return this->cur_frame_ < this->frame_count_; }; 247 | 248 | void FakeSequence::fill(ASDCP::JP2K::FrameBuffer &fb) 249 | { 250 | 251 | ASDCP::Result_t result = ASDCP::RESULT_OK; 252 | 253 | result = fb.SetData(this->codestream_.data(), (uint32_t)this->codestream_.size()); 254 | 255 | assert(ASDCP_SUCCESS(result)); 256 | 257 | uint32_t sz = fb.Size((uint32_t)this->codestream_.size()); 258 | 259 | if (sz != this->codestream_.size()) { 260 | throw std::runtime_error("Frame buffer resizing failed"); 261 | } 262 | }; 263 | 264 | 265 | const uint8_t FakeSequence::CODESTREAM_HEADER_[236] = { 266 | 0xFF, 0x4F, 0xFF, 0x51, 0x00, 0x2F, 0x40, 0x00, 0x00, 0x00, 0x0F, 0x00, 267 | 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 268 | 0x00, 0x00, 0x0F, 0x00, 0x00, 0x00, 0x08, 0x70, 0x00, 0x00, 0x00, 0x00, 269 | 0x00, 0x00, 0x00, 0x00, 0x00, 0x03, 0x0F, 0x01, 0x01, 0x0F, 0x01, 0x01, 270 | 0x0F, 0x01, 0x01, 0xFF, 0x50, 0x00, 0x08, 0x00, 0x02, 0x00, 0x00, 0x00, 271 | 0x0C, 0xFF, 0x52, 0x00, 0x12, 0x01, 0x02, 0x00, 0x01, 0x01, 0x05, 0x03, 272 | 0x03, 0x40, 0x01, 0x77, 0x88, 0x88, 0x88, 0x88, 0x88, 0xFF, 0x5C, 0x00, 273 | 0x13, 0x20, 0x90, 0x98, 0x98, 0xA0, 0x98, 0x98, 0xA0, 0x98, 0x98, 0xA0, 274 | 0x98, 0x98, 0x98, 0x90, 0x90, 0x98, 0xFF, 0x64, 0x00, 0x18, 0x00, 0x01, 275 | 0x4B, 0x61, 0x6B, 0x61, 0x64, 0x75, 0x2D, 0x76, 0x78, 0x74, 0x37, 0x2E, 276 | 0x31, 0x31, 0x2D, 0x42, 0x65, 0x74, 0x61, 0x34, 0xFF, 0x64, 0x00, 0x5C, 277 | 0x00, 0x01, 0x4B, 0x64, 0x75, 0x2D, 0x4C, 0x61, 0x79, 0x65, 0x72, 0x2D, 278 | 0x49, 0x6E, 0x66, 0x6F, 0x3A, 0x20, 0x6C, 0x6F, 0x67, 0x5F, 0x32, 0x7B, 279 | 0x44, 0x65, 0x6C, 0x74, 0x61, 0x2D, 0x44, 0x28, 0x73, 0x71, 0x75, 0x61, 280 | 0x72, 0x65, 0x64, 0x2D, 0x65, 0x72, 0x72, 0x6F, 0x72, 0x29, 0x2F, 0x44, 281 | 0x65, 0x6C, 0x74, 0x61, 0x2D, 0x4C, 0x28, 0x62, 0x79, 0x74, 0x65, 0x73, 282 | 0x29, 0x7D, 0x2C, 0x20, 0x4C, 0x28, 0x62, 0x79, 0x74, 0x65, 0x73, 0x29, 283 | 0x0A, 0x2D, 0x31, 0x39, 0x32, 0x2E, 0x30, 0x2C, 0x20, 0x20, 0x33, 0x2E, 284 | 0x37, 0x65, 0x2B, 0x30, 0x37, 0x0A, 0xFF, 0x90, 0x00, 0x0A, 0x00, 0x00, 285 | 0x02, 0x2D, 0x2F, 0xD0, 0x00, 0x01, 0xFF, 0x93 286 | }; -------------------------------------------------------------------------------- /src/main/CodestreamSequence.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), Pierre-Anthony Lemieux (pal@palemieux.com) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef COM_SANDFLOW_CODESTREAMSEQUENCE_H 28 | #define COM_SANDFLOW_CODESTREAMSEQUENCE_H 29 | 30 | #include 31 | #include 32 | #include 33 | 34 | class CodestreamSequence { 35 | 36 | public: 37 | 38 | virtual void next() = 0; 39 | virtual bool good() const = 0; 40 | virtual void fill(ASDCP::JP2K::FrameBuffer& fb) = 0; 41 | virtual ~CodestreamSequence() {}; 42 | }; 43 | 44 | class J2CFile : public CodestreamSequence { 45 | 46 | public: 47 | 48 | J2CFile(FILE* fp, 49 | std::vector::size_type initial_buf_sz = 50 * 1024 * 1024, 50 | std::vector::size_type read_buf_sz = 64 * 1024); 51 | 52 | J2CFile(const std::vector& file_paths, 53 | std::vector::size_type initial_buf_sz = 50 * 1024 * 1024, 54 | std::vector::size_type read_buf_sz = 64 * 1024); 55 | 56 | virtual void next(); 57 | 58 | virtual bool good() const; 59 | 60 | virtual void fill(ASDCP::JP2K::FrameBuffer& fb); 61 | 62 | protected: 63 | 64 | bool good_; 65 | std::vector codestream_; 66 | std::vector file_paths_stack_; 67 | std::vector::size_type initial_buf_sz_; 68 | std::vector::size_type read_buf_sz_; 69 | 70 | void _fill_from_fp(FILE* fp); 71 | }; 72 | 73 | class MJCFile : public CodestreamSequence { 74 | 75 | public: 76 | 77 | MJCFile(FILE* fp); 78 | 79 | virtual void next(); 80 | 81 | virtual bool good() const; 82 | 83 | virtual void fill(ASDCP::JP2K::FrameBuffer& fb); 84 | 85 | protected: 86 | 87 | bool good_; 88 | std::vector codestream_; 89 | FILE* fp_; 90 | bool is_cbr_; 91 | uint32_t codestream_len_; 92 | }; 93 | 94 | class FakeSequence : public CodestreamSequence { 95 | 96 | public: 97 | 98 | FakeSequence(uint32_t frame_count = 360, uint32_t frame_size = 5 * 1024 * 1024); 99 | 100 | virtual void next(); 101 | 102 | virtual bool good() const; 103 | 104 | virtual void fill(ASDCP::JP2K::FrameBuffer& fb); 105 | 106 | protected: 107 | 108 | uint32_t frame_count_; 109 | uint32_t cur_frame_; 110 | std::vector codestream_; 111 | 112 | const static uint8_t CODESTREAM_HEADER_[236]; 113 | 114 | 115 | }; 116 | 117 | #endif -------------------------------------------------------------------------------- /src/main/J2KProfileULMap.h: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), Pierre-Anthony Lemieux (pal@palemieux.com) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #ifndef COM_SANDFLOW_J2KPROFILEULMAP_H 28 | #define COM_SANDFLOW_J2KPROFILEULMAP_H 29 | 30 | #include 31 | #include 32 | 33 | std::map> J2KPROFILE_UL_MAP = { 34 | {1024, { 2, 1 } }, 35 | { 1025, {2, 2} }, 36 | { 1041, {2, 3} }, 37 | { 1026, {2, 4} }, 38 | { 1042, {2, 5} }, 39 | { 1027, {2, 6} }, 40 | { 1043, {2, 7} }, 41 | { 1028, {2, 8} }, 42 | { 1044, {2, 9} }, 43 | { 1060, {2, 10} }, 44 | { 1029, {2, 11} }, 45 | { 1045, {2, 12} }, 46 | { 1061, {2, 13} }, 47 | { 1077, {2, 14} }, 48 | { 1030, {2, 15} }, 49 | { 1046, {2, 16} }, 50 | { 1062, {2, 17} }, 51 | { 1078, {2, 18} }, 52 | { 1094, {2, 19} }, 53 | { 1031, {2, 20} }, 54 | { 1047, {2, 21} }, 55 | { 1063, {2, 22} }, 56 | { 1079, {2, 23} }, 57 | { 1095, {2, 24} }, 58 | { 1111, {2, 25} }, 59 | { 1032, {2, 26} }, 60 | { 1048, {2, 27} }, 61 | { 1064, {2, 28} }, 62 | { 1080, {2, 29} }, 63 | { 1096, {2, 30} }, 64 | { 1112, {2, 31} }, 65 | { 1128, {2, 32} }, 66 | { 1033, {2, 33} }, 67 | { 1049, {2, 34} }, 68 | { 1065, {2, 35} }, 69 | { 1081, {2, 36} }, 70 | { 1097, {2, 37} }, 71 | { 1113, {2, 38} }, 72 | { 1129, {2, 39} }, 73 | { 1145, {2, 40} }, 74 | { 1034, {2, 41} }, 75 | { 1050, {2, 42} }, 76 | { 1066, {2, 43} }, 77 | { 1082, {2, 44} }, 78 | { 1098, {2, 45} }, 79 | { 1114, {2, 46} }, 80 | { 1130, {2, 47} }, 81 | { 1146, {2, 48} }, 82 | { 1162, {2, 49} }, 83 | { 1035, {2, 50} }, 84 | { 1051, {2, 51} }, 85 | { 1067, {2, 52} }, 86 | { 1083, {2, 53} }, 87 | { 1099, {2, 54} }, 88 | { 1115, {2, 55} }, 89 | { 1131, {2, 56} }, 90 | { 1147, {2, 57} }, 91 | { 1163, {2, 58} }, 92 | { 1179, {2, 59} }, 93 | { 1280, {3, 1} }, 94 | { 1281, {3, 2} }, 95 | { 1297, {3, 3} }, 96 | { 1282, {3, 4} }, 97 | { 1298, {3, 5} }, 98 | { 1283, {3, 6} }, 99 | { 1299, {3, 7} }, 100 | { 1284, {3, 8} }, 101 | { 1300, {3, 9} }, 102 | { 1316, {3, 10} }, 103 | { 1285, {3, 11} }, 104 | { 1301, {3, 12} }, 105 | { 1317, {3, 13} }, 106 | { 1333, {3, 14} }, 107 | { 1286, {3, 15} }, 108 | { 1302, {3, 16} }, 109 | { 1318, {3, 17} }, 110 | { 1334, {3, 18} }, 111 | { 1350, {3, 19} }, 112 | { 1287, {3, 20} }, 113 | { 1303, {3, 21} }, 114 | { 1319, {3, 22} }, 115 | { 1335, {3, 23} }, 116 | { 1351, {3, 24} }, 117 | { 1367, {3, 25} }, 118 | { 1288, {3, 26} }, 119 | { 1304, {3, 27} }, 120 | { 1320, {3, 28} }, 121 | { 1336, {3, 29} }, 122 | { 1352, {3, 30} }, 123 | { 1368, {3, 31} }, 124 | { 1384, {3, 32} }, 125 | { 1289, {3, 33} }, 126 | { 1305, {3, 34} }, 127 | { 1321, {3, 35} }, 128 | { 1337, {3, 36} }, 129 | { 1353, {3, 37} }, 130 | { 1369, {3, 38} }, 131 | { 1385, {3, 39} }, 132 | { 1401, {3, 40} }, 133 | { 1290, {3, 41} }, 134 | { 1306, {3, 42} }, 135 | { 1322, {3, 43} }, 136 | { 1338, {3, 44} }, 137 | { 1354, {3, 45} }, 138 | { 1370, {3, 46} }, 139 | { 1386, {3, 47} }, 140 | { 1402, {3, 48} }, 141 | { 1418, {3, 49} }, 142 | { 1291, {3, 50} }, 143 | { 1307, {3, 51} }, 144 | { 1323, {3, 52} }, 145 | { 1339, {3, 53} }, 146 | { 1355, {3, 54} }, 147 | { 1371, {3, 55} }, 148 | { 1387, {3, 56} }, 149 | { 1403, {3, 57} }, 150 | { 1419, {3, 58} }, 151 | { 1435, {3, 59} }, 152 | { 1536, {4, 1} }, 153 | { 1537, {4, 2} }, 154 | { 1553, {4, 3} }, 155 | { 1538, {4, 4} }, 156 | { 1554, {4, 5} }, 157 | { 1539, {4, 6} }, 158 | { 1555, {4, 7} }, 159 | { 1540, {4, 8} }, 160 | { 1556, {4, 9} }, 161 | { 1572, {4, 10} }, 162 | { 1541, {4, 11} }, 163 | { 1557, {4, 12} }, 164 | { 1573, {4, 13} }, 165 | { 1589, {4, 14} }, 166 | { 1542, {4, 15} }, 167 | { 1558, {4, 16} }, 168 | { 1574, {4, 17} }, 169 | { 1590, {4, 18} }, 170 | { 1606, {4, 19} }, 171 | { 1543, {4, 20} }, 172 | { 1559, {4, 21} }, 173 | { 1575, {4, 22} }, 174 | { 1591, {4, 23} }, 175 | { 1607, {4, 24} }, 176 | { 1623, {4, 25} }, 177 | { 1544, {4, 26} }, 178 | { 1560, {4, 27} }, 179 | { 1576, {4, 28} }, 180 | { 1592, {4, 29} }, 181 | { 1608, {4, 30} }, 182 | { 1624, {4, 31} }, 183 | { 1640, {4, 32} }, 184 | { 1545, {4, 33} }, 185 | { 1561, {4, 34} }, 186 | { 1577, {4, 35} }, 187 | { 1593, {4, 36} }, 188 | { 1609, {4, 37} }, 189 | { 1625, {4, 38} }, 190 | { 1641, {4, 39} }, 191 | { 1657, {4, 40} }, 192 | { 1546, {4, 41} }, 193 | { 1562, {4, 42} }, 194 | { 1578, {4, 43} }, 195 | { 1594, {4, 44} }, 196 | { 1610, {4, 45} }, 197 | { 1626, {4, 46} }, 198 | { 1642, {4, 47} }, 199 | { 1658, {4, 48} }, 200 | { 1674, {4, 49} }, 201 | { 1547, {4, 50} }, 202 | { 1563, {4, 51} }, 203 | { 1579, {4, 52} }, 204 | { 1595, {4, 53} }, 205 | { 1611, {4, 54} }, 206 | { 1627, {4, 55} }, 207 | { 1643, {4, 56} }, 208 | { 1659, {4, 57} }, 209 | { 1675, {4, 58} }, 210 | { 1691, {4, 59} }, 211 | { 1792, {5, 1} }, 212 | { 1793, {5, 2} }, 213 | { 1809, {5, 3} }, 214 | { 1794, {5, 4} }, 215 | { 1810, {5, 5} }, 216 | { 1795, {5, 6} }, 217 | { 1811, {5, 7} }, 218 | { 1796, {5, 8} }, 219 | { 1812, {5, 9} }, 220 | { 1828, {5, 10} }, 221 | { 1797, {5, 11} }, 222 | { 1813, {5, 12} }, 223 | { 1829, {5, 13} }, 224 | { 1845, {5, 14} }, 225 | { 1798, {5, 15} }, 226 | { 1814, {5, 16} }, 227 | { 1830, {5, 17} }, 228 | { 1846, {5, 18} }, 229 | { 1862, {5, 19} }, 230 | { 1799, {5, 20} }, 231 | { 1815, {5, 21} }, 232 | { 1831, {5, 22} }, 233 | { 1847, {5, 23} }, 234 | { 1863, {5, 24} }, 235 | { 1879, {5, 25} }, 236 | { 1800, {5, 26} }, 237 | { 1816, {5, 27} }, 238 | { 1832, {5, 28} }, 239 | { 1848, {5, 29} }, 240 | { 1864, {5, 30} }, 241 | { 1880, {5, 31} }, 242 | { 1896, {5, 32} }, 243 | { 1801, {5, 33} }, 244 | { 1817, {5, 34} }, 245 | { 1833, {5, 35} }, 246 | { 1849, {5, 36} }, 247 | { 1865, {5, 37} }, 248 | { 1881, {5, 38} }, 249 | { 1897, {5, 39} }, 250 | { 1913, {5, 40} }, 251 | { 1802, {5, 41} }, 252 | { 1818, {5, 42} }, 253 | { 1834, {5, 43} }, 254 | { 1850, {5, 44} }, 255 | { 1866, {5, 45} }, 256 | { 1882, {5, 46} }, 257 | { 1898, {5, 47} }, 258 | { 1914, {5, 48} }, 259 | { 1930, {5, 49} }, 260 | { 1803, {5, 50} }, 261 | { 1819, {5, 51} }, 262 | { 1835, {5, 52} }, 263 | { 1851, {5, 53} }, 264 | { 1867, {5, 54} }, 265 | { 1883, {5, 55} }, 266 | { 1899, {5, 56} }, 267 | { 1915, {5, 57} }, 268 | { 1931, {5, 58} }, 269 | { 1947, {5, 59} }, 270 | { 2048, {6, 1} }, 271 | { 2049, {6, 2} }, 272 | { 2065, {6, 3} }, 273 | { 2050, {6, 4} }, 274 | { 2066, {6, 5} }, 275 | { 2051, {6, 6} }, 276 | { 2067, {6, 7} }, 277 | { 2052, {6, 8} }, 278 | { 2068, {6, 9} }, 279 | { 2084, {6, 10} }, 280 | { 2053, {6, 11} }, 281 | { 2069, {6, 12} }, 282 | { 2085, {6, 13} }, 283 | { 2101, {6, 14} }, 284 | { 2054, {6, 15} }, 285 | { 2070, {6, 16} }, 286 | { 2086, {6, 17} }, 287 | { 2102, {6, 18} }, 288 | { 2118, {6, 19} }, 289 | { 2055, {6, 20} }, 290 | { 2071, {6, 21} }, 291 | { 2087, {6, 22} }, 292 | { 2103, {6, 23} }, 293 | { 2119, {6, 24} }, 294 | { 2135, {6, 25} }, 295 | { 2056, {6, 26} }, 296 | { 2072, {6, 27} }, 297 | { 2088, {6, 28} }, 298 | { 2104, {6, 29} }, 299 | { 2120, {6, 30} }, 300 | { 2136, {6, 31} }, 301 | { 2152, {6, 32} }, 302 | { 2057, {6, 33} }, 303 | { 2073, {6, 34} }, 304 | { 2089, {6, 35} }, 305 | { 2105, {6, 36} }, 306 | { 2121, {6, 37} }, 307 | { 2137, {6, 38} }, 308 | { 2153, {6, 39} }, 309 | { 2169, {6, 40} }, 310 | { 2058, {6, 41} }, 311 | { 2074, {6, 42} }, 312 | { 2090, {6, 43} }, 313 | { 2106, {6, 44} }, 314 | { 2122, {6, 45} }, 315 | { 2138, {6, 46} }, 316 | { 2154, {6, 47} }, 317 | { 2170, {6, 48} }, 318 | { 2186, {6, 49} }, 319 | { 2059, {6, 50} }, 320 | { 2075, {6, 51} }, 321 | { 2091, {6, 52} }, 322 | { 2107, {6, 53} }, 323 | { 2123, {6, 54} }, 324 | { 2139, {6, 55} }, 325 | { 2155, {6, 56} }, 326 | { 2171, {6, 57} }, 327 | { 2187, {6, 58} }, 328 | { 2203, {6, 59} }, 329 | { 2304, {7, 1} }, 330 | { 2305, {7, 2} }, 331 | { 2321, {7, 3} }, 332 | { 2306, {7, 4} }, 333 | { 2322, {7, 5} }, 334 | { 2307, {7, 6} }, 335 | { 2323, {7, 7} }, 336 | { 2308, {7, 8} }, 337 | { 2324, {7, 9} }, 338 | { 2340, {7, 10} }, 339 | { 2309, {7, 11} }, 340 | { 2325, {7, 12} }, 341 | { 2341, {7, 13} }, 342 | { 2357, {7, 14} }, 343 | { 2310, {7, 15} }, 344 | { 2326, {7, 16} }, 345 | { 2342, {7, 17} }, 346 | { 2358, {7, 18} }, 347 | { 2374, {7, 19} }, 348 | { 2311, {7, 20} }, 349 | { 2327, {7, 21} }, 350 | { 2343, {7, 22} }, 351 | { 2359, {7, 23} }, 352 | { 2375, {7, 24} }, 353 | { 2391, {7, 25} }, 354 | { 2312, {7, 26} }, 355 | { 2328, {7, 27} }, 356 | { 2344, {7, 28} }, 357 | { 2360, {7, 29} }, 358 | { 2376, {7, 30} }, 359 | { 2392, {7, 31} }, 360 | { 2408, {7, 32} }, 361 | { 2313, {7, 33} }, 362 | { 2329, {7, 34} }, 363 | { 2345, {7, 35} }, 364 | { 2361, {7, 36} }, 365 | { 2377, {7, 37} }, 366 | { 2393, {7, 38} }, 367 | { 2409, {7, 39} }, 368 | { 2425, {7, 40} }, 369 | { 2314, {7, 41} }, 370 | { 2330, {7, 42} }, 371 | { 2346, {7, 43} }, 372 | { 2362, {7, 44} }, 373 | { 2378, {7, 45} }, 374 | { 2394, {7, 46} }, 375 | { 2410, {7, 47} }, 376 | { 2426, {7, 48} }, 377 | { 2442, {7, 49} }, 378 | { 2315, {7, 50} }, 379 | { 2331, {7, 51} }, 380 | { 2347, {7, 52} }, 381 | { 2363, {7, 53} }, 382 | { 2379, {7, 54} }, 383 | { 2395, {7, 55} }, 384 | { 2411, {7, 56} }, 385 | { 2427, {7, 57} }, 386 | { 2443, {7, 58} }, 387 | { 2459, {7, 59} } 388 | }; 389 | 390 | #endif -------------------------------------------------------------------------------- /src/main/jid-reader.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), Pierre-Anthony Lemieux (pal@palemieux.com) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include 40 | 41 | #ifdef WIN32 42 | #include 43 | #include 44 | #else 45 | #include 46 | #endif 47 | 48 | 49 | 50 | /* enumeration of supported input formats */ 51 | 52 | 53 | enum class OutputFormats { 54 | J2C, 55 | MJC 56 | }; 57 | 58 | std::istream& operator>>(std::istream& is, OutputFormats& f) { 59 | 60 | std::string s; 61 | 62 | is >> s; 63 | 64 | if (s == "J2C") { 65 | f = OutputFormats::J2C; 66 | } else if (s == "MJC") { 67 | f = OutputFormats::MJC; 68 | } else { 69 | throw std::runtime_error("Unknown input file format"); 70 | } 71 | 72 | return is; 73 | } 74 | 75 | 76 | std::ostream& operator<<(std::ostream& os, const OutputFormats& f) { 77 | 78 | switch (f) { 79 | case OutputFormats::J2C: 80 | os << "J2C"; 81 | break; 82 | case OutputFormats::MJC: 83 | os << "MJC"; 84 | break; 85 | } 86 | 87 | return os; 88 | } 89 | 90 | int main(int argc, const char* argv[]) { 91 | 92 | ASDCP::Result_t result = ASDCP::RESULT_OK; 93 | 94 | /* initialize command line options */ 95 | 96 | boost::program_options::options_description cli_opts{ "Unwraps JPEG 2000 codestreams from IMF Image Track Files" }; 97 | 98 | cli_opts.add_options() 99 | ("help", "Prints usage") 100 | ("format", boost::program_options::value()->default_value(OutputFormats::J2C), "Output format\n" 101 | " MJC: \t16-byte header followed by a sequence of J2C codestreams, each preceded by a 4-byte little-endian length\n" 102 | " J2C: \tindividual JPEG 2000 codestreams") 103 | ("buffer-size", boost::program_options::value()->default_value(8192*8192*3*2 /* 8K */), "Read buffer size (8K 4:4:4 16-bit if unspecified)") 104 | ("out", boost::program_options::value(), "Output path (or stdout if none is specified)") 105 | ("in", boost::program_options::value()->required(), "Input MXF file path"); 106 | 107 | boost::program_options::variables_map cli_args; 108 | 109 | try { 110 | 111 | boost::program_options::store(boost::program_options::parse_command_line(argc, argv, cli_opts), cli_args); 112 | 113 | boost::program_options::notify(cli_args); 114 | 115 | /* display help options */ 116 | 117 | if (cli_args.count("help")) { 118 | std::cout << cli_opts << "\n"; 119 | return 1; 120 | } 121 | 122 | /* setup the output */ 123 | 124 | const OutputFormats format = cli_args["format"].as(); 125 | 126 | FILE* mjc_output = NULL; 127 | 128 | switch (format) { 129 | 130 | case OutputFormats::J2C: 131 | 132 | if (cli_args["out"].empty() || (! Kumu::PathIsDirectory(cli_args["out"].as()) )) { 133 | throw std::runtime_error("Output path must be an existing directory when J2C output format is selected."); 134 | } 135 | 136 | break; 137 | 138 | case OutputFormats::MJC: 139 | 140 | if (cli_args["out"].empty()) { 141 | 142 | /* open stdout in binary mode */ 143 | 144 | #ifdef WIN32 145 | 146 | int mode = _setmode(_fileno(stdout), O_BINARY); 147 | 148 | if (mode == -1) { 149 | throw std::runtime_error("Cannot reopen stdout"); 150 | } 151 | #endif 152 | 153 | mjc_output = stdout; 154 | 155 | } else { 156 | 157 | /* create output file */ 158 | 159 | mjc_output = fopen(cli_args["out"].as().c_str(), "wb"); 160 | 161 | if (!mjc_output) { 162 | throw std::runtime_error("Cannot create output file"); 163 | } 164 | 165 | } 166 | 167 | 168 | 169 | break; 170 | 171 | default: 172 | 173 | throw std::runtime_error("Unknown output format"); 174 | 175 | } 176 | 177 | /* open input file */ 178 | 179 | AS_02::JP2K::MXFReader reader; 180 | 181 | result = reader.OpenRead(cli_args["in"].as()); 182 | 183 | if (result.Failure()) { 184 | throw std::runtime_error("Cannot open input file"); 185 | } 186 | 187 | if (format == OutputFormats::MJC) { 188 | 189 | /* output MJC header */ 190 | 191 | ASDCP::MXF::InterchangeObject* obj = 0; 192 | 193 | result = reader.OP1aHeader().GetMDObjectByType( 194 | reader.OP1aHeader().m_Dict->Type(ASDCP::MDD_RGBAEssenceDescriptor).ul, 195 | &obj 196 | ); 197 | 198 | uint32_t flags = result.Success() ? 2 /* KDU_SIMPLE_VIDEO_RGB */ : 1 /* KDU_SIMPLE_VIDEO_YCC */; 199 | 200 | ASDCP::Rational edit_rate; 201 | 202 | if (!ASDCP::MXF::GetEditRateFromFP(reader.OP1aHeader(), edit_rate)) { 203 | 204 | throw std::runtime_error("Cannot read edit rate from input file"); 205 | 206 | } 207 | 208 | std::array header = { 209 | 'M', 210 | 'J', 211 | 'C', 212 | '2', 213 | (uint8_t) ((edit_rate.Numerator >> 24) & 0xFF), 214 | (uint8_t) ((edit_rate.Numerator >> 16) & 0xFF), 215 | (uint8_t) ((edit_rate.Numerator >> 8) & 0xFF), 216 | (uint8_t) (edit_rate.Numerator & 0xFF), 217 | (uint8_t) ((edit_rate.Denominator >> 24) & 0xFF), 218 | (uint8_t) ((edit_rate.Denominator >> 16) & 0xFF), 219 | (uint8_t) ((edit_rate.Denominator >> 8) & 0xFF), 220 | (uint8_t) (edit_rate.Denominator & 0xFF), 221 | (uint8_t) ((flags >> 24) & 0xFF), 222 | (uint8_t) ((flags >> 16) & 0xFF), 223 | (uint8_t) ((flags >> 8) & 0xFF), 224 | (uint8_t) (flags & 0xFF), 225 | }; 226 | 227 | fwrite(header.data(), sizeof(header), 1, mjc_output); 228 | 229 | } 230 | 231 | /* Codestream frame buffer for the MXF writer */ 232 | 233 | ASDCP::JP2K::FrameBuffer fb(cli_args["buffer-size"].as()); 234 | 235 | uint32_t frame_count = reader.AS02IndexReader().GetDuration(); 236 | 237 | for (uint32_t i = 0; i < frame_count; i++) { 238 | 239 | result = reader.ReadFrame(i, fb); 240 | 241 | if (result.Failure()) { 242 | throw std::runtime_error("Cannot read frame"); 243 | } 244 | 245 | if (format == OutputFormats::J2C) { 246 | 247 | /* write single J2C */ 248 | 249 | std::stringstream ss; 250 | 251 | ss << cli_args["out"].as() << "/" << std::setfill('0') << std::setw(6) << i << ".j2c"; 252 | 253 | std::ofstream f(ss.str(), std::ios_base::out | std::ios_base::binary); 254 | 255 | if (!f.good()) { 256 | throw std::runtime_error("Cannot open output file"); 257 | } 258 | 259 | f.write((const char*) fb.RoData(), fb.Size()); 260 | 261 | f.close(); 262 | 263 | } else { 264 | 265 | /* write single MJC frame */ 266 | 267 | uint32_t csz = KM_i32_BE(fb.Size()); 268 | 269 | fwrite(&csz, 4, 1, mjc_output); 270 | 271 | fwrite((const char*)fb.RoData(), 1, fb.Size(), mjc_output); 272 | 273 | } 274 | 275 | } 276 | 277 | /* close reader */ 278 | 279 | result = reader.Close(); 280 | 281 | if (ASDCP_FAILURE(result)) { 282 | throw std::runtime_error("Cannot close file"); 283 | } 284 | 285 | } catch (boost::program_options::required_option e) { 286 | 287 | std::cout << cli_opts << std::endl; 288 | return 1; 289 | 290 | } catch (std::runtime_error e) { 291 | 292 | std::cout << e.what() << std::endl; 293 | return 1; 294 | } 295 | 296 | return 0; 297 | } 298 | -------------------------------------------------------------------------------- /src/main/jid-writer.cpp: -------------------------------------------------------------------------------- 1 | /* 2 | * Copyright (c), Pierre-Anthony Lemieux (pal@palemieux.com) 3 | * All rights reserved. 4 | * 5 | * Redistribution and use in source and binary forms, with or without 6 | * modification, are permitted provided that the following conditions are met: 7 | * 8 | * * Redistributions of source code must retain the above copyright notice, this 9 | * list of conditions and the following disclaimer. 10 | * * Redistributions in binary form must reproduce the above copyright notice, 11 | * this list of conditions and the following disclaimer in the documentation 12 | * and/or other materials provided with the distribution. 13 | * 14 | * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" 15 | * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 16 | * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 17 | * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE 18 | * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 19 | * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF 20 | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS 21 | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN 22 | * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) 23 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 24 | * POSSIBILITY OF SUCH DAMAGE. 25 | */ 26 | 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include 34 | #include 35 | #include 36 | #include 37 | #include 38 | #include 39 | #include "CodestreamSequence.h" 40 | #include "J2KProfileULMap.h" 41 | 42 | #ifdef WIN32 43 | #include 44 | #include 45 | #else 46 | #include 47 | #endif 48 | 49 | /* authoring identification info written to file headers */ 50 | 51 | class DCDM2IMFWriterInfo : public ASDCP::WriterInfo { 52 | public: 53 | DCDM2IMFWriterInfo() { 54 | static byte_t default_ProductUUID_Data[ASDCP::UUIDlen] = 55 | { 0x92, 0x7f, 0xc4, 0xd1, 0x89, 0xa3, 0x4f, 0x88, 0x88, 0xbb, 0xd3, 0x63, 0xed, 0x33, 0x08, 0x4a }; 56 | 57 | memcpy(ProductUUID, default_ProductUUID_Data, ASDCP::UUIDlen); 58 | CompanyName = "Sandflow Consulting LLC"; 59 | ProductName = "dcdm2imf"; 60 | ProductVersion = "1.0-beta1"; 61 | } 62 | }; 63 | 64 | 65 | /* hard-coded UL definitions */ 66 | 67 | std::array CodingEquations_ITU601 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x02, 0x01, 0x00, 0x00 }; 68 | std::array CodingEquations_ITU709 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x02, 0x02, 0x00, 0x00 }; 69 | std::array CodingEquations_ITU2020_NCL = { 0x06, 0x0e, 0x2b, 0x34, 04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x02, 0x06, 0x00, 0x00 }; 70 | 71 | std::array TransferCharacteristic_ITU709 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x01, 0x04, 0x01, 0x01, 0x01, 0x01, 0x02, 0x00, 0x00 }; 72 | std::array TransferCharacteristic_IEC6196624_xvYCC = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x01, 0x08, 0x00, 0x00 }; 73 | std::array TransferCharacteristic_ITU2020 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0e, 0x04, 0x01, 0x01, 0x01, 0x01, 0x09, 0x00, 0x00 }; 74 | std::array TransferCharacteristic_SMPTEST2084 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x01, 0x0a, 0x00, 0x00 }; 75 | std::array TransferCharacteristic_CinemaMezzanine_DCDM = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x01, 0x13, 0x00, 0x00 }; 76 | 77 | std::array ColorPrimaries_SMPTE170M = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x06, 0x04, 0x01, 0x01, 0x01, 0x03, 0x01, 0x00, 0x00 }; 78 | std::array ColorPrimaries_ITU470_PAL = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x06, 0x04, 0x01, 0x01, 0x01, 0x03, 0x02, 0x00, 0x00 }; 79 | std::array ColorPrimaries_ITU709 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x06, 0x04, 0x01, 0x01, 0x01, 0x03, 0x03, 0x00, 0x00 }; 80 | std::array ColorPrimaries_ITU2020 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x03, 0x04, 0x00, 0x00 }; 81 | std::array ColorPrimaries_P3D65 = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x03, 0x06, 0x00, 0x00 }; 82 | std::array ColorPrimaries_CinemaMezzanine = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x01, 0x01, 0x03, 0x08, 0x00, 0x00 }; 83 | 84 | std::array HTJ2KPictureCodingSchemeGeneric = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0D, 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x08, 0x01 }; 85 | 86 | namespace ASDCP { 87 | 88 | /* TODO: this is necessary since the symbol is never exported by the core libraries */ 89 | 90 | Result_t JP2K_PDesc_to_MD(const ASDCP::JP2K::PictureDescriptor& PDesc, 91 | const ASDCP::Dictionary& dict, 92 | ASDCP::MXF::GenericPictureEssenceDescriptor& GenericPictureEssenceDescriptor, 93 | ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor); 94 | 95 | /* TODO: this is necessary since the symbol is never exported by the core libraries */ 96 | 97 | Result_t JP2K::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDesc, byte_t* start_of_data); 98 | 99 | 100 | /* overloads needed for boost::program_options */ 101 | 102 | std::istream& operator>>(std::istream& is, ASDCP::Rational& r) { 103 | 104 | std::string s; 105 | 106 | is >> s; 107 | 108 | std::vector params; 109 | 110 | boost::split(params, s, boost::is_any_of("/")); 111 | 112 | if (params.size() == 0 || params.size() > 2) { 113 | throw std::runtime_error("Cannot read rational"); 114 | } 115 | 116 | r = ASDCP::Rational( 117 | std::stoi(params[0]), 118 | params.size() == 1 ? 1 : std::stoi(params[1]) 119 | ); 120 | 121 | return is; 122 | } 123 | 124 | /* overloads needed for boost::program_options */ 125 | 126 | std::ostream& operator<<(std::ostream& os, const ASDCP::Rational& r) { 127 | 128 | os << r.Numerator << "/" << r.Denominator; 129 | 130 | return os; 131 | } 132 | 133 | } 134 | 135 | namespace Kumu { 136 | /* overloads needed for boost::program_options */ 137 | 138 | std::istream& operator>>(std::istream& is, Kumu::UUID& uuid) { 139 | 140 | std::string s; 141 | 142 | is >> s; 143 | 144 | if (!uuid.DecodeHex(s.c_str())) { 145 | throw std::invalid_argument("Bad UUID"); 146 | } 147 | 148 | return is; 149 | } 150 | 151 | 152 | /* overloads needed for boost::program_options */ 153 | 154 | std::ostream& operator<<(std::ostream& os, const Kumu::UUID& uuid) { 155 | 156 | char buf[128]; 157 | 158 | if (uuid.EncodeString(buf, sizeof buf)) { 159 | 160 | os << buf; 161 | 162 | } else { 163 | 164 | throw std::invalid_argument("Bad UUID"); 165 | 166 | } 167 | 168 | return os; 169 | } 170 | 171 | } 172 | 173 | /* enumeration of supported input formats */ 174 | 175 | 176 | enum class InputFormats { 177 | J2C, 178 | MJC 179 | }; 180 | 181 | std::istream& operator>>(std::istream& is, InputFormats& f) { 182 | 183 | std::string s; 184 | 185 | is >> s; 186 | 187 | if (s == "J2C") { 188 | f = InputFormats::J2C; 189 | } else if (s == "MJC") { 190 | f = InputFormats::MJC; 191 | } else { 192 | throw std::runtime_error("Unknown input file format"); 193 | } 194 | 195 | return is; 196 | } 197 | 198 | 199 | std::ostream& operator<<(std::ostream& os, const InputFormats& f) { 200 | 201 | switch (f) { 202 | case InputFormats::J2C: 203 | os << "J2C"; 204 | break; 205 | case InputFormats::MJC: 206 | os << "MJC"; 207 | break; 208 | } 209 | 210 | return os; 211 | } 212 | 213 | /* quantization */ 214 | 215 | 216 | enum class Quantization { 217 | QE_2, 218 | QE_1 219 | }; 220 | 221 | std::istream& operator>>(std::istream& is, Quantization& q) { 222 | 223 | std::string s; 224 | 225 | is >> s; 226 | 227 | if (s == "QE.1") { 228 | q = Quantization::QE_1; 229 | } else if (s == "QE.2") { 230 | q = Quantization::QE_2; 231 | } else { 232 | throw std::runtime_error("Unknown quantization"); 233 | } 234 | 235 | return is; 236 | } 237 | 238 | 239 | std::ostream& operator<<(std::ostream& os, const Quantization& q) { 240 | 241 | switch (q) { 242 | case Quantization::QE_2: 243 | os << "QE.2"; 244 | break; 245 | case Quantization::QE_1: 246 | os << "QE.1"; 247 | break; 248 | } 249 | 250 | return os; 251 | } 252 | 253 | /* enumeration of components */ 254 | 255 | enum class ImageComponents { 256 | RGB, 257 | YCbCr, 258 | XYZ 259 | }; 260 | 261 | std::istream& operator>>(std::istream& is, ImageComponents& f) { 262 | 263 | std::string s; 264 | 265 | is >> s; 266 | 267 | if (s == "RGB") { 268 | f = ImageComponents::RGB; 269 | } else if (s == "YCbCr") { 270 | f = ImageComponents::YCbCr; 271 | } else if (s == "XYZ") { 272 | f = ImageComponents::XYZ; 273 | } else { 274 | throw std::runtime_error("Unknown image components"); 275 | } 276 | 277 | return is; 278 | } 279 | 280 | 281 | std::ostream& operator<<(std::ostream& os, const ImageComponents& f) { 282 | 283 | switch (f) { 284 | case ImageComponents::RGB: 285 | os << "RGB"; 286 | break; 287 | case ImageComponents::YCbCr: 288 | os << "YCbCr"; 289 | break; 290 | case ImageComponents::XYZ: 291 | os << "XYZ"; 292 | break; 293 | } 294 | 295 | return os; 296 | } 297 | 298 | /* enumeration of supported colorimetry */ 299 | 300 | class EnumeratedColorimetry { 301 | public: 302 | 303 | /* defined colorimetry values */ 304 | 305 | static const EnumeratedColorimetry COLOR_1; 306 | static const EnumeratedColorimetry COLOR_2; 307 | static const EnumeratedColorimetry COLOR_3; 308 | static const EnumeratedColorimetry COLOR_4; 309 | static const EnumeratedColorimetry COLOR_5; 310 | static const EnumeratedColorimetry COLOR_6; 311 | static const EnumeratedColorimetry COLOR_7; 312 | static const EnumeratedColorimetry COLOR_APP4_2; 313 | 314 | static const EnumeratedColorimetry& fromString(const std::string s) { 315 | 316 | auto i = EnumeratedColorimetry::colors_.find(s); 317 | 318 | if (i == EnumeratedColorimetry::colors_.cend()) { 319 | throw std::runtime_error("Unknown colorimetry"); 320 | } 321 | 322 | return *(i->second); 323 | } 324 | 325 | static std::string usage() { 326 | std::stringstream ss; 327 | 328 | ss << "Colorspace:" << std::endl; 329 | 330 | for (auto pair : EnumeratedColorimetry::colors_) { 331 | ss << pair.first << std::endl; 332 | } 333 | 334 | return ss.str(); 335 | } 336 | 337 | const std::string& symbol() const { 338 | return this->symbol_; 339 | } 340 | 341 | const std::array& transfer_characteristic() const { 342 | return this->transfer_characteristic_; 343 | } 344 | 345 | const std::array& color_primaries() const { 346 | return this->color_primaries_; 347 | } 348 | 349 | const std::array& coding_equations() const { 350 | return this->coding_equations_; 351 | } 352 | 353 | private: 354 | 355 | EnumeratedColorimetry(const std::string& symbol, 356 | const std::array& transfer_characteristic, 357 | const std::array& color_primaries, 358 | const std::array& coding_equations) : 359 | symbol_(symbol), 360 | transfer_characteristic_(transfer_characteristic), 361 | color_primaries_(color_primaries), 362 | coding_equations_(coding_equations) { 363 | if (!this->colors_.insert(std::make_pair(this->symbol_, this)).second) { 364 | throw std::runtime_error("Existing colorimetry"); 365 | } 366 | } 367 | 368 | static std::map colors_; 369 | 370 | std::string symbol_; 371 | 372 | std::array transfer_characteristic_; 373 | std::array color_primaries_; 374 | std::array coding_equations_; 375 | }; 376 | 377 | bool operator==(const EnumeratedColorimetry& lhs, const EnumeratedColorimetry& rhs) { return &lhs == &rhs; } 378 | 379 | bool operator!=(const EnumeratedColorimetry& lhs, const EnumeratedColorimetry& rhs) { return !(lhs == rhs); } 380 | 381 | std::map EnumeratedColorimetry::colors_; 382 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_1("COLOR.1", TransferCharacteristic_ITU709, ColorPrimaries_ITU470_PAL, CodingEquations_ITU601); 383 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_2("COLOR.2", TransferCharacteristic_ITU709, ColorPrimaries_SMPTE170M, CodingEquations_ITU601); 384 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_3("COLOR.3", TransferCharacteristic_ITU709, ColorPrimaries_ITU709, CodingEquations_ITU709); 385 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_4("COLOR.4", TransferCharacteristic_IEC6196624_xvYCC, ColorPrimaries_SMPTE170M, CodingEquations_ITU601); 386 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_5("COLOR.5", TransferCharacteristic_ITU2020, ColorPrimaries_ITU2020, CodingEquations_ITU2020_NCL); 387 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_6("COLOR.6", TransferCharacteristic_SMPTEST2084, ColorPrimaries_P3D65, CodingEquations_ITU2020_NCL /* not used */); 388 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_7("COLOR.7", TransferCharacteristic_SMPTEST2084, ColorPrimaries_ITU2020, CodingEquations_ITU2020_NCL); 389 | const EnumeratedColorimetry EnumeratedColorimetry::COLOR_APP4_2("COLOR.APP4.2", TransferCharacteristic_CinemaMezzanine_DCDM, ColorPrimaries_CinemaMezzanine, CodingEquations_ITU2020_NCL /* not used */); 390 | 391 | int main(int argc, const char* argv[]) { 392 | 393 | ASDCP::Result_t result = ASDCP::RESULT_OK; 394 | 395 | /* initialize command line options */ 396 | 397 | boost::program_options::options_description cli_opts{ "Wraps JPEG 2000 codestreams into IMF Image Track File" }; 398 | 399 | cli_opts.add_options() 400 | ("help", "Prints usage") 401 | ("fps", boost::program_options::value()->default_value(ASDCP::EditRate_24), "Edit rate in the form of '/' , e.g. 24/1") 402 | ("aspect_ratio", boost::program_options::value(), "Aspect ratio in the form of '/' , e.g. 16/9") 403 | ("format", boost::program_options::value()->default_value(InputFormats::J2C), "Input codestream format\n" 404 | " MJC: \t16-byte header followed by a sequence of J2C codestreams, each preceded by a 4-byte little-endian length\n" 405 | " J2C: \tsingle JPEG 2000 codestream") 406 | ("assetid", boost::program_options::value(), "Asset UUID in hex notation, e.g. 8538b543169743dd9a08c6d8b4b1b7df") 407 | ("out", boost::program_options::value()->required(), "Output file path") 408 | ("fake", boost::program_options::bool_switch()->default_value(false), "Generate fake input data") 409 | ("in", boost::program_options::value(), "Input file path (or stdin if none is specified)") 410 | ("color", boost::program_options::value()->default_value(EnumeratedColorimetry::COLOR_APP4_2.symbol()), EnumeratedColorimetry::usage().c_str()) 411 | ("components", boost::program_options::value()->default_value(ImageComponents::XYZ), "Image components: RGB or YCbCr or XYZ") 412 | ("quantization", boost::program_options::value()->default_value(Quantization::QE_2), "Quantization: QE.1 or QE.2") 413 | ("active_area", boost::program_options::value>()->multitoken(), "Active area rectangle (in pixels): x_offset y_offset width height") 414 | ("display_area", boost::program_options::value>()->multitoken(), "Display rectangle (in pixels): x_offset y_offset width height") 415 | ("mastering_display_primaries", boost::program_options::value>()->multitoken(), "Mastering Display Primaries: x_0 y_0 x_1 y_1 x_2 y_2") 416 | ("mastering_display_white_point_chroma", boost::program_options::value>()->multitoken(), "Mastering Display White Point Chromaticity: x y") 417 | ("mastering_display_max_luminance", boost::program_options::value(), "Mastering Display Maximum Luminance") 418 | ("mastering_display_min_luminance", boost::program_options::value(), "Mastering Display Minimum Luminance"); 419 | 420 | boost::program_options::variables_map cli_args; 421 | 422 | try { 423 | 424 | boost::program_options::store(boost::program_options::parse_command_line(argc, argv, cli_opts), cli_args); 425 | 426 | boost::program_options::notify(cli_args); 427 | 428 | /* display help options */ 429 | 430 | if (cli_args.count("help")) { 431 | std::cout << cli_opts << "\n"; 432 | return 1; 433 | } 434 | 435 | const ASDCP::Dictionary* g_dict = &ASDCP::DefaultSMPTEDict(); 436 | 437 | if (!g_dict) { 438 | throw std::runtime_error("Cannot open SMPTE dictionary"); 439 | } 440 | 441 | /* setup the input codestream sequence */ 442 | 443 | std::unique_ptr seq; 444 | 445 | if (cli_args["fake"].as()) { 446 | 447 | seq.reset(new FakeSequence()); 448 | 449 | } else { 450 | 451 | FILE* f_in = NULL; 452 | 453 | if (cli_args.count("in") == 0) { 454 | 455 | /* open stdin in binary mode */ 456 | 457 | #ifdef WIN32 458 | 459 | int mode = _setmode(_fileno(stdin), O_BINARY); 460 | 461 | if (mode == -1) { 462 | throw std::runtime_error("Cannot reopen stdout"); 463 | } 464 | 465 | f_in = stdin; 466 | 467 | #else 468 | 469 | f_in = freopen(NULL, "rb", stdin); 470 | 471 | if (!f_in) { 472 | throw std::runtime_error("Cannot reopen stdout"); 473 | } 474 | 475 | #endif 476 | switch (cli_args["format"].as()) { 477 | 478 | case InputFormats::J2C: 479 | seq.reset(new J2CFile(f_in)); 480 | break; 481 | 482 | case InputFormats::MJC: 483 | seq.reset(new MJCFile(f_in)); 484 | break; 485 | 486 | } 487 | 488 | 489 | } else { 490 | 491 | switch (cli_args["format"].as()) { 492 | 493 | case InputFormats::J2C: 494 | 495 | { 496 | 497 | const std::string& path = cli_args["in"].as(); 498 | std::vector file_list; 499 | 500 | 501 | if (Kumu::PathIsFile(path)) { 502 | 503 | file_list.push_back(path); 504 | 505 | } else { 506 | 507 | char next_file[Kumu::MaxFilePath]; 508 | Kumu::DirScanner scanner; 509 | 510 | result = scanner.Open(path); 511 | 512 | if (result.Failure()) { 513 | throw std::runtime_error("Cannot open directory"); 514 | } 515 | 516 | while (scanner.GetNext(next_file).Success()) { 517 | 518 | /* skip hidden and special files */ 519 | 520 | if (next_file[0] == '.') continue; 521 | 522 | std::string file_path = path + "/" + next_file; 523 | 524 | /* skip directories*/ 525 | 526 | if (Kumu::PathIsDirectory(file_path)) continue; 527 | 528 | file_list.push_back(file_path); 529 | } 530 | 531 | } 532 | 533 | std::sort(file_list.begin(), file_list.end()); 534 | 535 | seq.reset(new J2CFile(file_list)); 536 | } 537 | 538 | break; 539 | 540 | case InputFormats::MJC: 541 | 542 | f_in = fopen(cli_args["in"].as().c_str(), "rb"); 543 | 544 | if (!f_in) { 545 | throw std::runtime_error("Cannot open input file"); 546 | } 547 | 548 | seq.reset(new MJCFile(f_in)); 549 | 550 | break; 551 | 552 | } 553 | 554 | } 555 | 556 | 557 | 558 | } 559 | 560 | /* Codestream frame buffer for the MXF writer */ 561 | 562 | ASDCP::JP2K::FrameBuffer fb; 563 | 564 | /* MXF writer */ 565 | 566 | AS_02::JP2K::MXFWriter writer; 567 | 568 | /* information about this software that will be written in the header metadata*/ 569 | 570 | DCDM2IMFWriterInfo writer_info; 571 | 572 | writer_info.LabelSetType = ASDCP::LS_MXF_SMPTE; 573 | 574 | if (cli_args.count("assetid")) { 575 | 576 | const Kumu::UUID& uuid = cli_args["assetid"].as(); 577 | 578 | memcpy(writer_info.AssetUUID, uuid.Value(), uuid.Size()); 579 | 580 | } else { 581 | 582 | Kumu::GenRandomUUID(writer_info.AssetUUID); 583 | 584 | } 585 | 586 | /* keep count of the number of frames written to the file */ 587 | 588 | uint32_t frame_count = 0; 589 | 590 | while (seq->good()) { 591 | 592 | /* setup the frame buffer using the current codestream */ 593 | 594 | seq->fill(fb); 595 | 596 | fb.PlaintextOffset(0); 597 | 598 | /* fill J2K picture descriptor */ 599 | 600 | ASDCP::JP2K::PictureDescriptor pdesc; 601 | 602 | byte_t start_of_data; 603 | 604 | result = ASDCP::JP2K::ParseMetadataIntoDesc(fb, pdesc, &start_of_data); 605 | 606 | if (ASDCP_FAILURE(result)) { 607 | throw std::runtime_error(result.Message()); 608 | } 609 | 610 | pdesc.EditRate = cli_args["fps"].as(); 611 | 612 | /* initialize header metadata if this is the first codestream */ 613 | 614 | if (frame_count == 0) { 615 | 616 | /* build the essence descriptor */ 617 | 618 | ASDCP::MXF::GenericPictureEssenceDescriptor* desc = NULL; 619 | 620 | /* initialize the J2K subdescriptor */ 621 | 622 | ASDCP::MXF::JPEG2000PictureSubDescriptor* j2k_subdesc = new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict); 623 | 624 | /* determine pixel depth from the first component */ 625 | 626 | if (!(pdesc.ImageComponents[0].Ssize == pdesc.ImageComponents[1].Ssize && pdesc.ImageComponents[1].Ssize == pdesc.ImageComponents[2].Ssize)) { 627 | throw std::runtime_error("Not all components have equal pixel depth"); 628 | } 629 | 630 | uint8_t pixel_depth = pdesc.ImageComponents[0].Ssize + 1; 631 | 632 | /* determine the color scheme */ 633 | 634 | const EnumeratedColorimetry& color = EnumeratedColorimetry::fromString(cli_args["color"].as()); 635 | 636 | /* J2CLayout depends on the image components */ 637 | 638 | std::array j2c_layout; 639 | 640 | if (cli_args["components"].as() == ImageComponents::YCbCr) { 641 | 642 | /* YCbCr image */ 643 | 644 | if (pdesc.ImageComponents[1].YRsize != pdesc.ImageComponents[2].YRsize) { 645 | 646 | throw std::runtime_error("Inconsistent subsampling"); 647 | } 648 | 649 | if (cli_args["quantization"].as() != Quantization::QE_1) { 650 | 651 | throw std::runtime_error("Quantization must be QE.1 for YCbCr images"); 652 | 653 | } 654 | 655 | /* compute the J2C Layout */ 656 | 657 | j2c_layout = { 0x59, pixel_depth, 0x55, pixel_depth, 0x56, pixel_depth, 0x00 }; 658 | 659 | /* build the CDCI descriptor */ 660 | 661 | ASDCP::MXF::CDCIEssenceDescriptor* yuv_desc = new ASDCP::MXF::CDCIEssenceDescriptor(g_dict); 662 | 663 | yuv_desc->CodingEquations = color.coding_equations().data(); 664 | 665 | yuv_desc->HorizontalSubsampling = pdesc.ImageComponents[1].YRsize; 666 | 667 | yuv_desc->VerticalSubsampling = 1; 668 | 669 | yuv_desc->ComponentDepth = pdesc.ImageComponents->Ssize + 1; 670 | 671 | yuv_desc->ColorSiting = 0; 672 | 673 | yuv_desc->WhiteReflevel = (2 << pdesc.ImageComponents->Ssize) - 21 * (2 << (pdesc.ImageComponents->Ssize - 8)); /* 2^A1 - 21*2^A1/2^8 */ 674 | 675 | yuv_desc->BlackRefLevel = 2 << (pdesc.ImageComponents->Ssize - 4); 676 | 677 | yuv_desc->ColorRange = (2 << pdesc.ImageComponents->Ssize) - (2 << (pdesc.ImageComponents->Ssize - 3)) + 1; /* 2^A1 - 2^A1/2^3 + 1 */ 678 | 679 | desc = yuv_desc; 680 | 681 | } else { 682 | 683 | /* RGB image */ 684 | 685 | ASDCP::MXF::RGBAEssenceDescriptor* rgba_desc = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict); 686 | 687 | if (pdesc.ImageComponents[1].YRsize == 2 || pdesc.ImageComponents[2].YRsize == 2) { 688 | 689 | throw std::runtime_error("Components are sub-sampled but RGB images have been requested"); 690 | 691 | } 692 | 693 | if (cli_args["quantization"].as() == Quantization::QE_1) { 694 | 695 | rgba_desc->ComponentMaxRef = (2 << pdesc.ImageComponents->Ssize) - 21 * (2 << (pdesc.ImageComponents->Ssize - 8)); 696 | rgba_desc->ComponentMinRef = 2 << (pdesc.ImageComponents->Ssize - 4); 697 | 698 | } else { 699 | 700 | rgba_desc->ComponentMaxRef = (2 << pdesc.ImageComponents->Ssize) - 1; 701 | rgba_desc->ComponentMinRef = 0; 702 | 703 | } 704 | 705 | /* compute the J2C Layout */ 706 | 707 | if (cli_args["components"].as() == ImageComponents::XYZ) { 708 | 709 | j2c_layout = { 0xd8, pixel_depth, 0xd9, pixel_depth, 0xda, pixel_depth, 0x00 }; 710 | 711 | } else { 712 | 713 | j2c_layout = { 0x52, pixel_depth, 0x47, pixel_depth, 0x42, pixel_depth, 0x00 }; 714 | 715 | } 716 | 717 | /* set Pixel Layout (ignored in the case of App 2) */ 718 | 719 | rgba_desc->PixelLayout.Set(j2c_layout.data()); 720 | 721 | /* ScanningDirection shall be present and zero */ 722 | 723 | rgba_desc->ScanningDirection.set(0); 724 | 725 | desc = rgba_desc; 726 | 727 | } 728 | 729 | /* set the J2CLayout */ 730 | 731 | j2k_subdesc->J2CLayout.set(j2c_layout.data()); 732 | 733 | /* fill the essence descriptor */ 734 | 735 | result = ASDCP::JP2K_PDesc_to_MD( 736 | pdesc, 737 | *g_dict, 738 | *desc, 739 | *j2k_subdesc 740 | ); 741 | 742 | if (ASDCP_FAILURE(result)) { 743 | throw std::runtime_error(result.Message()); 744 | } 745 | 746 | /* determine Picture Essence Coding Label */ 747 | 748 | if (pdesc.ExtendedCapabilities.Pcap & 0x00020000) { 749 | 750 | /* Part 15 codestream */ 751 | 752 | desc->PictureEssenceCoding = HTJ2KPictureCodingSchemeGeneric.data(); 753 | 754 | } else { 755 | 756 | /* Part 1 codestream */ 757 | 758 | std::map>::const_iterator ul_bytes = J2KPROFILE_UL_MAP.find(pdesc.Rsize); 759 | 760 | if (ul_bytes != J2KPROFILE_UL_MAP.end()) { 761 | 762 | /* It is an IMF profile */ 763 | 764 | std::array ul = { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, 0x04, 0x01, 0x02, 0x02, 0x03, 0x01, 0x00 /* placeholder*/, 0x00 /* placeholder*/ }; 765 | 766 | ul[14] = static_cast(ul_bytes->second.first); 767 | ul[15] = static_cast(ul_bytes->second.second); 768 | 769 | desc->PictureEssenceCoding = ul.data(); 770 | 771 | } else { 772 | 773 | throw std::runtime_error("Supports only J2K IMF profiles or HTJ2K"); 774 | 775 | } 776 | 777 | } 778 | 779 | /* fill-in remaining common essence descriptor fields */ 780 | 781 | desc->TransferCharacteristic = color.transfer_characteristic().data(); 782 | 783 | desc->ColorPrimaries = color.color_primaries().data(); 784 | 785 | desc->VideoLineMap = ASDCP::MXF::LineMapPair(0, 0); 786 | 787 | /* DisplayF2Offset is required by ST 2067-21, but set to 0 since interlaced is not supported by JID */ 788 | 789 | desc->DisplayF2Offset.set(0); 790 | 791 | if (cli_args.count("display_area")) { 792 | 793 | std::vector display_rectangle = cli_args["display_area"].as>(); 794 | 795 | if (display_rectangle.size() != 4) { 796 | throw std::runtime_error("Display area must consist of exactly four positive integer values"); 797 | } 798 | 799 | desc->DisplayXOffset = display_rectangle[0]; 800 | desc->DisplayYOffset = display_rectangle[1]; 801 | desc->DisplayWidth = display_rectangle[2]; 802 | desc->DisplayHeight = display_rectangle[3]; 803 | 804 | if (desc->DisplayXOffset.get() + desc->DisplayWidth.get() > desc->StoredWidth || 805 | desc->DisplayYOffset.get() + desc->DisplayHeight.get() > desc->StoredHeight) { 806 | throw std::runtime_error("Display area does not fit within the stored rectangle"); 807 | } 808 | } 809 | 810 | if (cli_args.count("active_area")) { 811 | 812 | std::vector active_rectangle = cli_args["active_area"].as>(); 813 | 814 | if (active_rectangle.size() != 4) { 815 | throw std::runtime_error("Active area must consist of exactly four positive integer values"); 816 | } 817 | 818 | desc->ActiveXOffset = active_rectangle[0]; 819 | desc->ActiveYOffset = active_rectangle[1]; 820 | desc->ActiveWidth = active_rectangle[2]; 821 | desc->ActiveHeight = active_rectangle[3]; 822 | 823 | int display_width = desc->DisplayWidth.empty() ? desc->StoredWidth : desc->DisplayWidth.get(); 824 | int display_height = desc->DisplayHeight.empty() ? desc->StoredHeight : desc->DisplayHeight.get(); 825 | 826 | if (desc->ActiveXOffset.get() + desc->ActiveWidth.get() > display_width || 827 | desc->ActiveYOffset.get() + desc->ActiveHeight.get() > display_height) { 828 | throw std::runtime_error("Active area does not fit within the display rectangle"); 829 | } 830 | } 831 | 832 | /* Mastering Display Color Volume Metadata */ 833 | 834 | if (cli_args.count("mastering_display_primaries") || 835 | cli_args.count("mastering_display_white_point_chroma") || 836 | cli_args.count("mastering_display_max_luminance") || 837 | cli_args.count("mastering_display_min_luminance")) { 838 | 839 | if (cli_args.count("mastering_display_primaries") != 1 || 840 | cli_args.count("mastering_display_white_point_chroma") != 1 || 841 | cli_args.count("mastering_display_max_luminance") != 1 || 842 | cli_args.count("mastering_display_min_luminance") != 1 843 | ) { 844 | 845 | throw std::runtime_error("All Mastering Display Color Volume Metadata items must be defined"); 846 | 847 | } 848 | 849 | if (! (color == EnumeratedColorimetry::COLOR_3 || 850 | color == EnumeratedColorimetry::COLOR_5 || 851 | color == EnumeratedColorimetry::COLOR_6 || 852 | color == EnumeratedColorimetry::COLOR_7) 853 | ) { 854 | 855 | throw std::runtime_error("Mastering Display Color Volume Metadata can only be used with COLOR.3, COLOR.5, COLOR.6 or COLOR.7"); 856 | 857 | } 858 | 859 | std::vector mastering_display_primaries = cli_args["mastering_display_primaries"].as>(); 860 | 861 | if (mastering_display_primaries.size() != 6) { 862 | throw std::runtime_error("Mastering display primaries must consist of exactly 6 positive integer values"); 863 | } 864 | 865 | ASDCP::MXF::ColorPrimary p1(mastering_display_primaries[0], mastering_display_primaries[1]); 866 | ASDCP::MXF::ColorPrimary p2(mastering_display_primaries[2], mastering_display_primaries[3]); 867 | ASDCP::MXF::ColorPrimary p3(mastering_display_primaries[4], mastering_display_primaries[5]); 868 | 869 | desc->MasteringDisplayPrimaries = ASDCP::MXF::ThreeColorPrimaries(p1, p2, p3); 870 | 871 | std::vector mastering_display_white_point_chroma = cli_args["mastering_display_white_point_chroma"].as>(); 872 | 873 | if (mastering_display_white_point_chroma.size() != 2) { 874 | throw std::runtime_error("Mastering Display White Point Chromaticity must consist of exactly 2 positive integer values"); 875 | } 876 | 877 | desc->MasteringDisplayWhitePointChromaticity = ASDCP::MXF::ColorPrimary(mastering_display_white_point_chroma[0], mastering_display_white_point_chroma[1]); 878 | 879 | if (mastering_display_white_point_chroma.size() != 2) { 880 | throw std::runtime_error("Mastering Display White Point Chromaticity must consist of exactly 2 positive integer values"); 881 | } 882 | 883 | desc->MasteringDisplayMinimumLuminance = cli_args["mastering_display_min_luminance"].as(); 884 | desc->MasteringDisplayMaximumLuminance = cli_args["mastering_display_max_luminance"].as(); 885 | 886 | } 887 | 888 | /* we do not know the container duration */ 889 | 890 | desc->ContainerDuration.set_has_value(false); 891 | 892 | ASDCP::MXF::FileDescriptor* essence_descriptor = static_cast(desc); 893 | 894 | if (ASDCP_FAILURE(result)) { 895 | throw std::runtime_error(result.Message()); 896 | } 897 | 898 | /* initialize the sub-descriptor container */ 899 | 900 | ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors; 901 | 902 | essence_sub_descriptors.push_back(j2k_subdesc); 903 | 904 | /* initialize the MXF file */ 905 | 906 | result = writer.OpenWrite( 907 | cli_args["out"].as(), 908 | writer_info, 909 | essence_descriptor, 910 | essence_sub_descriptors, 911 | cli_args["fps"].as(), 912 | 16384, 913 | AS_02::IndexStrategy_t::IS_FOLLOW, 914 | 60); 915 | 916 | if (ASDCP_FAILURE(result)) { 917 | throw std::runtime_error(result.Message()); 918 | } 919 | 920 | } 921 | 922 | /* write the codestream into a new frame */ 923 | 924 | result = writer.WriteFrame(fb, NULL, NULL); 925 | 926 | if (ASDCP_FAILURE(result)) { 927 | throw std::runtime_error(result.Message()); 928 | } 929 | 930 | /* move to the next codestream */ 931 | 932 | seq->next(); 933 | 934 | frame_count++; 935 | 936 | } 937 | 938 | result = writer.Finalize(); 939 | 940 | if (ASDCP_FAILURE(result)) { 941 | throw std::runtime_error(result.Message()); 942 | } 943 | 944 | } catch (boost::program_options::required_option e) { 945 | 946 | std::cout << cli_opts << std::endl; 947 | return 1; 948 | 949 | } catch (std::runtime_error e) { 950 | 951 | std::cout << e.what() << std::endl; 952 | return 1; 953 | } 954 | 955 | return 0; 956 | } 957 | -------------------------------------------------------------------------------- /src/test/resources/README.md: -------------------------------------------------------------------------------- 1 | The files in this directory were generated as described below from the [Netflix Meridian test material](https://media.xiph.org/video/derf/meridian/MERIDIAN_SHR_C_EN-XX_US-NR_51_LTRT_UHD_20160909_OV), which is licensed under the [BY-NC-ND 4.0](https://creativecommons.org/licenses/by-nc-nd/4.0/) license. 2 | 3 | ``` 4 | kdu_compress -i mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif Simf=\{6,0,rev\} -fprec 12M -o part1.j2c 5 | ``` 6 | 7 | ``` 8 | kdu_compress -i mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif Corder="CPRL" Clevels="{6}" \ 9 | Cprecincts="{256,256},{256,256},{256,256},{256,256},{256,256},{256,256},{128,128}" ORGgen_tlm="{3}" ORGtparts=C \ 10 | Cblk="{32,32}" Creversible=yes Cmodes=HT -fprec 12M -o part15.j2c 11 | ``` 12 | 13 | ``` 14 | kdu_v_compress -i mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+1 -o - \ 15 | Simf=\{6,0,rev\} -in_prec 12M > part1.mjc 16 | ``` 17 | 18 | ``` 19 | kdu_v_compress.exe -i mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913_12bit_DCDM.00090000.tif+1 -o - Corder="CPRL" \ 20 | Clevels="{6}" Cprecincts="{256,256},{256,256},{256,256},{256,256},{256,256},{256,256},{128,128}" ORGgen_tlm="{3}" \ 21 | ORGtparts=C Cblk="{32,32}" Creversible=yes Cmodes=HT -in_prec 12M > part15.mjc 22 | ``` 23 | 24 | The `kdu*` demonstration executables are available at . -------------------------------------------------------------------------------- /src/test/resources/crowdrun-lowlatency.1920x1080-422-10bit-50p.mjc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/crowdrun-lowlatency.1920x1080-422-10bit-50p.mjc -------------------------------------------------------------------------------- /src/test/resources/j2c-sequence/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000000.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/j2c-sequence/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000000.j2c -------------------------------------------------------------------------------- /src/test/resources/j2c-sequence/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000001.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/j2c-sequence/mer_shrt_23976_vdm_sdr_rec709_g24_3840x2160_20170913.000001.j2c -------------------------------------------------------------------------------- /src/test/resources/part1.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/part1.j2c -------------------------------------------------------------------------------- /src/test/resources/part1.mjc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/part1.mjc -------------------------------------------------------------------------------- /src/test/resources/part15.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/part15.j2c -------------------------------------------------------------------------------- /src/test/resources/part15.mjc: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/part15.mjc -------------------------------------------------------------------------------- /src/test/resources/yuv422_10b_p15.j2c: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/sandflow/jid/2237e2f9e5318bb81bec4cc9a2fe9844a16dbcdd/src/test/resources/yuv422_10b_p15.j2c --------------------------------------------------------------------------------