2 Copyright (c) 2011-2014, John Hurst
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
9 1. Redistributions of source code must retain the above copyright
10 notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12 notice, this list of conditions and the following disclaimer in the
13 documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15 derived from this software without specific prior written permission.
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 /*! \file phdr-unwrap.cpp
29 \version $Id: phdr-unwrap.cpp,v 1.6 2015/10/07 16:41:23 jhurst Exp $
30 \brief prototype unwrapping for HDR images in AS-02
32 This program extracts picture (P-HDR picture) from an AS-02 MXF file.
35 #include <KM_fileio.h>
36 #include <AS_02_PHDR.h>
38 using namespace ASDCP;
40 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
42 //------------------------------------------------------------------------------------------
44 // command line option parser class
46 static const char* PROGRAM_NAME = "as-02-unwrap"; // program name for messages
48 // Increment the iterator, test for an additional non-option command line argument.
49 // Causes the caller to return if there are no remaining arguments or if the next
50 // argument begins with '-'.
51 #define TEST_EXTRA_ARG(i,c) \
52 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
53 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
59 banner(FILE* stream = stdout)
63 Copyright (c) 2011-2015, John Hurst\n\n\
64 asdcplib may be copied only under the terms of the license found at\n\
65 the top of every file in the asdcplib distribution kit.\n\n\
66 Specify the -h (help) option for further information about %s\n\n",
67 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
72 usage(FILE* stream = stdout)
75 USAGE: %s [-h|-help] [-V]\n\
77 %s [-b <buffer-size>] [-d <duration>]\n\
78 [-f <starting-frame>] [-m] [-R] [-s <size>] [-v] [-W]\n\
79 [-w] <input-file> [<file-prefix>]\n\n",
80 PROGRAM_NAME, PROGRAM_NAME);
84 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
85 Defaults to 4,194,304 (4MB)\n\
86 -d <duration> - Number of frames to process, default all\n\
87 -f <start-frame> - Starting frame number, default 0\n\
88 -h | -help - Show help\n\
89 -k <key-string> - Use key for ciphertext operations\n\
90 -m - verify HMAC values when reading\n\
91 -s <size> - Number of bytes to dump to output when -v is given\n\
92 -V - Show version information\n\
93 -v - Verbose, prints informative messages to stderr\n\
94 -W - Read input file only, do not write destination file\n\
95 -w <width> - Width of numeric element in a series of frame file names\n\
98 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
99 o All option arguments must be separated from the option by whitespace.\n\n");
108 bool error_flag; // true if the given options are in error or not complete
109 bool key_flag; // true if an encryption key was given
110 bool read_hmac; // true if HMAC values are to be validated
111 bool verbose_flag; // true if the verbose option was selected
112 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
113 bool no_write_flag; // true if no output files are to be written
114 bool version_flag; // true if the version display option was selected
115 bool help_flag; // true if the help display option was selected
116 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
117 ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
118 ui32_t start_frame; // frame number to begin processing
119 ui32_t duration; // number of frames to be processed
120 bool duration_flag; // true if duration argument given
121 ui32_t fb_size; // size of picture frame buffer
122 const char* file_prefix; // filename pre for files written by the extract mode
123 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
124 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
125 const char* input_filename;
126 std::string prefix_buffer;
129 CommandOptions(int argc, const char** argv) :
130 error_flag(true), key_flag(false), read_hmac(false), verbose_flag(false),
131 fb_dump_size(0), no_write_flag(false),
132 version_flag(false), help_flag(false), number_width(6),
133 start_frame(0), duration(0xffffffff), duration_flag(false),
134 fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
137 memset(key_value, 0, KeyLen);
138 memset(key_id_value, 0, UUIDlen);
140 for ( int i = 1; i < argc; ++i )
143 if ( (strcmp( argv[i], "-help") == 0) )
149 if ( argv[i][0] == '-'
150 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
153 switch ( argv[i][1] )
156 TEST_EXTRA_ARG(i, 'b');
157 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
160 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
165 TEST_EXTRA_ARG(i, 'd');
166 duration_flag = true;
167 duration = Kumu::xabs(strtol(argv[i], 0, 10));
171 TEST_EXTRA_ARG(i, 'f');
172 start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
175 case 'h': help_flag = true; break;
176 case 'm': read_hmac = true; break;
179 TEST_EXTRA_ARG(i, 's');
180 fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
183 case 'V': version_flag = true; break;
184 case 'v': verbose_flag = true; break;
185 case 'W': no_write_flag = true; break;
188 TEST_EXTRA_ARG(i, 'w');
189 number_width = Kumu::xabs(strtol(argv[i], 0, 10));
193 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
199 if ( argv[i][0] != '-' )
201 if ( input_filename == 0 )
203 input_filename = argv[i];
205 else if ( file_prefix == 0 )
207 file_prefix = argv[i];
212 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
218 if ( help_flag || version_flag )
221 if ( input_filename == 0 )
223 fputs("At least one filename argument is required.\n", stderr);
227 if ( file_prefix == 0 )
229 prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
230 file_prefix = prefix_buffer.c_str();
238 //------------------------------------------------------------------------------------------
242 // Read one or more plaintext JPEG 2000 codestreams from a plaintext P-HDR file
243 // Read one or more plaintext JPEG 2000 codestreams from a ciphertext P-HDR file
244 // Read one or more ciphertext JPEG 2000 codestreams from a ciphertext P-HDR file
247 read_JP2K_file(CommandOptions& Options)
249 AESDecContext* Context = 0;
250 HMACContext* HMAC = 0;
251 AS_02::PHDR::MXFReader Reader;
252 AS_02::PHDR::FrameBuffer FrameBuffer(Options.fb_size);
253 ui32_t frame_count = 0;
255 std::string PHDR_master_metadata; // todo: write to a file?
257 Result_t result = Reader.OpenRead(Options.input_filename, PHDR_master_metadata);
258 fprintf(stderr, "PHDR_master_metadata size=%zd\n", PHDR_master_metadata.size());
260 if ( ASDCP_SUCCESS(result) )
262 if ( Options.verbose_flag )
264 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
267 ASDCP::MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
268 ASDCP::MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
270 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
271 reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
273 if ( KM_SUCCESS(result) )
275 assert(rgba_descriptor);
276 frame_count = rgba_descriptor->ContainerDuration;
278 if ( Options.verbose_flag )
280 rgba_descriptor->Dump();
285 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
286 reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
288 if ( KM_SUCCESS(result) )
290 assert(cdci_descriptor);
291 frame_count = cdci_descriptor->ContainerDuration;
293 if ( Options.verbose_flag )
295 cdci_descriptor->Dump();
300 fprintf(stderr, "File does not contain an essence descriptor.\n");
301 frame_count = Reader.AS02IndexReader().GetDuration();
305 if ( frame_count == 0 )
307 frame_count = Reader.AS02IndexReader().GetDuration();
310 if ( frame_count == 0 )
312 fprintf(stderr, "Unable to determine file duration.\n");
317 if ( ASDCP_SUCCESS(result) && Options.key_flag )
319 Context = new AESDecContext;
320 result = Context->InitKey(Options.key_value);
322 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
325 Reader.FillWriterInfo(Info);
329 HMAC = new HMACContext;
330 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
334 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
339 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
340 if ( last_frame > frame_count )
341 last_frame = frame_count;
343 char name_format[64];
344 snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
346 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
348 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
351 snprintf(filename, 1024, name_format, Options.file_prefix, i);
353 if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
355 printf("Frame %d, %d bytes", i, FrameBuffer.Size());
357 if ( ! Options.no_write_flag )
359 printf(" -> %s", filename);
365 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
367 Kumu::FileWriter OutFile;
369 result = OutFile.OpenWrite(filename);
371 if ( ASDCP_SUCCESS(result) )
372 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
374 if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
376 FrameBuffer.Dump(stderr, Options.fb_dump_size);
386 main(int argc, const char** argv)
389 CommandOptions Options(argc, argv);
391 if ( Options.version_flag )
394 if ( Options.help_flag )
397 if ( Options.version_flag || Options.help_flag )
400 if ( Options.error_flag )
402 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
406 EssenceType_t EssenceType;
407 Result_t result = ASDCP::EssenceType(Options.input_filename, EssenceType);
409 if ( ASDCP_SUCCESS(result) )
411 switch ( EssenceType )
413 case ESS_AS02_JPEG_2000:
414 result = read_JP2K_file(Options);
418 fprintf(stderr, "%s: Unknown file type, not P-HDR essence.\n", Options.input_filename);
423 if ( ASDCP_FAILURE(result) )
425 fputs("Program stopped on error.\n", stderr);
427 if ( result != RESULT_FAIL )
429 fputs(result, stderr);
441 // end phdr-unwrap.cpp