2 Copyright (c) 2003-2013, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file asdcp-wrap.cpp
29 \brief AS-DCP file manipulation utility
31 This program wraps d-cinema essence (picture, sound or text) into an AS-DCP
34 For more information about asdcplib, please refer to the header file AS_DCP.h
36 WARNING: While the asdcplib library attempts to provide a complete and secure
37 implementation of the cryptographic features of the AS-DCP file formats, this
38 unit test program is NOT secure and is therefore NOT SUITABLE FOR USE in a
39 production environment without some modification.
41 In particular, this program uses weak IV generation and externally generated
42 plaintext keys. These shortcomings exist because cryptographic-quality
43 random number generation and key management are outside the scope of the
44 asdcplib library. Developers using asdcplib for commercial implementations
45 claiming SMPTE conformance are expected to provide proper implementations of
49 #include <KM_fileio.h>
51 #include <AtmosSyncChannel_Mixer.h>
53 #include <PCMParserList.h>
56 using namespace ASDCP;
58 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
60 const byte_t P_HFR_UL_2K[16] = {
61 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d,
62 0x0e, 0x16, 0x02, 0x02, 0x03, 0x01, 0x01, 0x03
65 const ASDCP::Dictionary *g_dict = 0;
67 //------------------------------------------------------------------------------------------
69 // command line option parser class
71 static const char* PROGRAM_NAME = "asdcp-wrap"; // program name for messages
73 // local program identification info written to file headers
74 class MyInfo : public WriterInfo
79 static byte_t default_ProductUUID_Data[UUIDlen] =
80 { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
81 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
83 memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
84 CompanyName = "WidgetCo";
85 ProductName = "asdcp-wrap";
86 ProductVersion = ASDCP::Version();
92 // Increment the iterator, test for an additional non-option command line argument.
93 // Causes the caller to return if there are no remaining arguments or if the next
94 // argument begins with '-'.
95 #define TEST_EXTRA_ARG(i,c) \
96 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
97 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
103 banner(FILE* stream = stdout)
106 %s (asdcplib %s)\n\n\
107 Copyright (c) 2003-2012 John Hurst\n\n\
108 asdcplib may be copied only under the terms of the license found at\n\
109 the top of every file in the asdcplib distribution kit.\n\n\
110 Specify the -h (help) option for further information about %s\n\n",
111 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
116 usage(FILE* stream = stdout)
119 USAGE: %s [-h|-help] [-V]\n\
121 %s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
122 [-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\
123 [-l <label>] [-L] [-M] [-m <expr>] [-p <frame-rate>] [-s] [-v]\n\
124 [-W] [-z|-Z] <input-file>+ <output-file>\n\n",
125 PROGRAM_NAME, PROGRAM_NAME);
129 -3 - Create a stereoscopic image file. Expects two\n\
130 directories of JP2K codestreams (directories must have\n\
131 an equal number of frames; the left eye is first)\n\
132 -C <UL> - Set ChannelAssignment UL value in a PCM file\n\
133 -h | -help - Show help\n\
134 -V - Show version information\n\
135 -e - Encrypt MPEG or JP2K headers (default)\n\
136 -E - Do not encrypt MPEG or JP2K headers\n\
137 -j <key-id-str> - Write key ID instead of creating a random value\n\
138 -k <key-string> - Use key for ciphertext operations\n\
139 -M - Do not create HMAC values when writing\n\
140 -m <expr> - Write MCA labels using <expr>. Example:\n\
141 51(L,R,C,LFE,Ls,Rs,),HI,VIN\n\
142 -a <UUID> - Specify the Asset ID of the file\n\
143 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
144 Defaults to 4,194,304 (4MB)\n\
145 -d <duration> - Number of frames to process, default all\n\
146 -f <start-frame> - Starting frame number, default 0\n\
147 -l <label> - Use given channel format label when writing MXF sound\n\
148 files. SMPTE 429-2 labels: '5.1', '6.1', '7.1',\n\
150 Default is no label (valid for Interop only).\n\
151 -L - Write SMPTE UL values instead of MXF Interop\n\
152 -P <UL> - Set PictureEssenceCoding UL value in a JP2K file\n\
153 -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
154 Use one of [23|24|25|30|48|50|60], 24 is default\n\
155 -s - Insert a Dolby Atmos synchronization channel when\n\
156 wrapping PCM. This implies a -L option(SMPTE ULs) and \n\
157 will overide -C and -l options with Configuration 4 \n\
158 Channel Assigment and no format label respectively. \n\
159 -v - Verbose, prints informative messages to stderr\n\
160 -W - Read input file only, do not write source file\n\
161 -z - Fail if j2c inputs have unequal parameters (default)\n\
162 -Z - Ignore unequal parameters in j2c inputs\n\
164 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
165 o All option arguments must be separated from the option by whitespace.\n\
166 o An argument of \"23\" to the -p option will be interpreted\n\
167 as 24000/1001 fps.\n\
173 decode_channel_fmt(const std::string& label_name)
175 if ( label_name == "5.1" )
176 return PCM::CF_CFG_1;
178 else if ( label_name == "6.1" )
179 return PCM::CF_CFG_2;
181 else if ( label_name == "7.1" )
182 return PCM::CF_CFG_3;
184 else if ( label_name == "WTF" )
185 return PCM::CF_CFG_4;
187 else if ( label_name == "7.1DS" )
188 return PCM::CF_CFG_5;
190 fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
191 fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n");
202 bool error_flag; // true if the given options are in error or not complete
203 bool key_flag; // true if an encryption key was given
204 bool asset_id_flag; // true if an asset ID was given
205 bool encrypt_header_flag; // true if mpeg headers are to be encrypted
206 bool write_hmac; // true if HMAC values are to be generated and written
207 bool verbose_flag; // true if the verbose option was selected
208 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
209 bool no_write_flag; // true if no output files are to be written
210 bool version_flag; // true if the version display option was selected
211 bool help_flag; // true if the help display option was selected
212 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
213 ui32_t start_frame; // frame number to begin processing
214 ui32_t duration; // number of frames to be processed
215 bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values
216 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
217 ui32_t picture_rate; // fps of picture when wrapping PCM
218 ui32_t fb_size; // size of picture frame buffer
219 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
220 bool key_id_flag; // true if a key ID was given
221 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
222 byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
223 PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
224 std::string out_file; //
225 bool show_ul_values_flag; /// if true, dump the UL table before going to work.
226 Kumu::PathList_t filenames; // list of filenames to be processed
227 UL channel_assignment;
229 bool dolby_atmos_sync_flag; // if true, insert a Dolby Atmos Synchronization channel.
230 ui32_t ffoa; /// first frame of action for atmos wrapping
231 ui32_t max_channel_count; /// max channel count for atmos wrapping
232 ui32_t max_object_count; /// max object count for atmos wrapping
233 ASDCP::MXF::ASDCP_MCAConfigParser mca_config;
236 Rational PictureRate()
238 if ( picture_rate == 16 ) return EditRate_16;
239 if ( picture_rate == 18 ) return EditRate_18;
240 if ( picture_rate == 20 ) return EditRate_20;
241 if ( picture_rate == 22 ) return EditRate_22;
242 if ( picture_rate == 23 ) return EditRate_23_98;
243 if ( picture_rate == 24 ) return EditRate_24;
244 if ( picture_rate == 25 ) return EditRate_25;
245 if ( picture_rate == 30 ) return EditRate_30;
246 if ( picture_rate == 48 ) return EditRate_48;
247 if ( picture_rate == 50 ) return EditRate_50;
248 if ( picture_rate == 60 ) return EditRate_60;
249 if ( picture_rate == 96 ) return EditRate_96;
250 if ( picture_rate == 100 ) return EditRate_100;
251 if ( picture_rate == 120 ) return EditRate_120;
256 const char* szPictureRate()
258 if ( picture_rate == 16 ) return "16";
259 if ( picture_rate == 18 ) return "18.182";
260 if ( picture_rate == 20 ) return "20";
261 if ( picture_rate == 22 ) return "21.818";
262 if ( picture_rate == 23 ) return "23.976";
263 if ( picture_rate == 24 ) return "24";
264 if ( picture_rate == 25 ) return "25";
265 if ( picture_rate == 30 ) return "30";
266 if ( picture_rate == 48 ) return "48";
267 if ( picture_rate == 50 ) return "50";
268 if ( picture_rate == 60 ) return "60";
269 if ( picture_rate == 96 ) return "96";
270 if ( picture_rate == 100 ) return "100";
271 if ( picture_rate == 120 ) return "120";
276 CommandOptions(int argc, const char** argv) :
277 error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
278 encrypt_header_flag(true), write_hmac(true),
279 verbose_flag(false), fb_dump_size(0),
280 no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
282 duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
283 fb_size(FRAME_BUFFER_SIZE),
284 channel_fmt(PCM::CF_NONE),
285 ffoa(0), max_channel_count(10), max_object_count(118), // hard-coded sample atmos properties
286 dolby_atmos_sync_flag(false),
287 show_ul_values_flag(false),
290 memset(key_value, 0, KeyLen);
291 memset(key_id_value, 0, UUIDlen);
293 for ( int i = 1; i < argc; i++ )
296 if ( (strcmp( argv[i], "-help") == 0) )
302 if ( argv[i][0] == '-'
303 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
306 switch ( argv[i][1] )
308 case '3': stereo_image_flag = true; break;
311 asset_id_flag = true;
312 TEST_EXTRA_ARG(i, 'a');
315 Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
317 if ( length != UUIDlen )
319 fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
326 TEST_EXTRA_ARG(i, 'b');
327 fb_size = abs(atoi(argv[i]));
330 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
335 TEST_EXTRA_ARG(i, 'C');
336 if ( ! channel_assignment.DecodeHex(argv[i]) )
338 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
344 TEST_EXTRA_ARG(i, 'd');
345 duration = abs(atoi(argv[i]));
348 case 'E': encrypt_header_flag = false; break;
349 case 'e': encrypt_header_flag = true; break;
352 TEST_EXTRA_ARG(i, 'f');
353 start_frame = abs(atoi(argv[i]));
356 case 'h': help_flag = true; break;
358 case 'j': key_id_flag = true;
359 TEST_EXTRA_ARG(i, 'j');
362 Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
364 if ( length != UUIDlen )
366 fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
372 case 'k': key_flag = true;
373 TEST_EXTRA_ARG(i, 'k');
376 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
378 if ( length != KeyLen )
380 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
387 TEST_EXTRA_ARG(i, 'l');
388 channel_fmt = decode_channel_fmt(argv[i]);
391 case 'L': use_smpte_labels = true; break;
392 case 'M': write_hmac = false; break;
395 TEST_EXTRA_ARG(i, 'm');
396 if ( ! mca_config.DecodeString(argv[i]) )
403 TEST_EXTRA_ARG(i, 'P');
404 if ( ! picture_coding.DecodeHex(argv[i]) )
406 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
412 TEST_EXTRA_ARG(i, 'p');
413 picture_rate = abs(atoi(argv[i]));
416 case 's': dolby_atmos_sync_flag = true; break;
417 case 'u': show_ul_values_flag = true; break;
418 case 'V': version_flag = true; break;
419 case 'v': verbose_flag = true; break;
420 case 'W': no_write_flag = true; break;
421 case 'Z': j2c_pedantic = false; break;
422 case 'z': j2c_pedantic = true; break;
425 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
432 if ( argv[i][0] != '-' )
434 filenames.push_back(argv[i]);
438 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
444 if ( help_flag || version_flag )
447 if ( filenames.size() < 2 )
449 fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
453 out_file = filenames.back();
454 filenames.pop_back();
459 //------------------------------------------------------------------------------------------
462 // Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
463 // Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
466 write_MPEG2_file(CommandOptions& Options)
468 AESEncContext* Context = 0;
469 HMACContext* HMAC = 0;
470 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
471 MPEG2::Parser Parser;
472 MPEG2::MXFWriter Writer;
473 MPEG2::VideoDescriptor VDesc;
474 byte_t IV_buf[CBC_BLOCK_SIZE];
475 Kumu::FortunaRNG RNG;
477 // set up essence parser
478 Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
481 if ( ASDCP_SUCCESS(result) )
483 Parser.FillVideoDescriptor(VDesc);
485 if ( Options.verbose_flag )
487 fputs("MPEG-2 Pictures\n", stderr);
488 fputs("VideoDescriptor:\n", stderr);
489 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
490 MPEG2::VideoDescriptorDump(VDesc);
494 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
496 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
497 if ( Options.asset_id_flag )
498 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
500 Kumu::GenRandomUUID(Info.AssetUUID);
502 if ( Options.use_smpte_labels )
504 Info.LabelSetType = LS_MXF_SMPTE;
505 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
508 // configure encryption
509 if( Options.key_flag )
511 Kumu::GenRandomUUID(Info.ContextID);
512 Info.EncryptedEssence = true;
514 if ( Options.key_id_flag )
515 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
517 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
519 Context = new AESEncContext;
520 result = Context->InitKey(Options.key_value);
522 if ( ASDCP_SUCCESS(result) )
523 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
525 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
527 Info.UsesHMAC = true;
528 HMAC = new HMACContext;
529 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
533 if ( ASDCP_SUCCESS(result) )
534 result = Writer.OpenWrite(Options.out_file.c_str(), Info, VDesc);
537 if ( ASDCP_SUCCESS(result) )
538 // loop through the frames
540 result = Parser.Reset();
543 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
545 result = Parser.ReadFrame(FrameBuffer);
547 if ( ASDCP_SUCCESS(result) )
549 if ( Options.verbose_flag )
550 FrameBuffer.Dump(stderr, Options.fb_dump_size);
552 if ( Options.encrypt_header_flag )
553 FrameBuffer.PlaintextOffset(0);
556 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
558 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
560 // The Writer class will forward the last block of ciphertext
561 // to the encryption context for use as the IV for the next
562 // frame. If you want to use non-sequitur IV values, un-comment
563 // the following line of code.
564 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
565 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
569 if ( result == RESULT_ENDOFFILE )
573 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
574 result = Writer.Finalize();
580 //------------------------------------------------------------------------------------------
582 // return false if an error is discovered
584 check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
586 Rational rate = Options.PictureRate();
587 if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120 )
590 if ( PDesc.StoredWidth > 2048 )
592 fprintf(stderr, "P-HFR files currently limited to 2K.\n");
596 if ( ! Options.use_smpte_labels )
598 fprintf(stderr, "P-HFR files must be written using SMPTE labels. Use option '-L'.\n");
602 // do not set the label if the user has already done so
603 if ( ! Options.picture_coding.HasValue() )
604 Options.picture_coding = UL(P_HFR_UL_2K);
609 //------------------------------------------------------------------------------------------
612 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file
613 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file
616 write_JP2K_S_file(CommandOptions& Options)
618 AESEncContext* Context = 0;
619 HMACContext* HMAC = 0;
620 JP2K::MXFSWriter Writer;
621 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
622 JP2K::PictureDescriptor PDesc;
623 JP2K::SequenceParser ParserLeft, ParserRight;
624 byte_t IV_buf[CBC_BLOCK_SIZE];
625 Kumu::FortunaRNG RNG;
627 if ( Options.filenames.size() != 2 )
629 fprintf(stderr, "Two inputs are required for stereoscopic option.\n");
633 // set up essence parser
634 Result_t result = ParserLeft.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
636 if ( ASDCP_SUCCESS(result) )
638 Options.filenames.pop_front();
639 result = ParserRight.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
643 if ( ASDCP_SUCCESS(result) )
645 ParserLeft.FillPictureDescriptor(PDesc);
646 PDesc.EditRate = Options.PictureRate();
648 if ( Options.verbose_flag )
650 fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr);
651 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
652 JP2K::PictureDescriptorDump(PDesc);
656 if ( ! check_phfr_params(Options, PDesc) )
659 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
661 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
662 if ( Options.asset_id_flag )
663 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
665 Kumu::GenRandomUUID(Info.AssetUUID);
667 if ( Options.use_smpte_labels )
669 Info.LabelSetType = LS_MXF_SMPTE;
670 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
673 // configure encryption
674 if( Options.key_flag )
676 Kumu::GenRandomUUID(Info.ContextID);
677 Info.EncryptedEssence = true;
679 if ( Options.key_id_flag )
680 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
682 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
684 Context = new AESEncContext;
685 result = Context->InitKey(Options.key_value);
687 if ( ASDCP_SUCCESS(result) )
688 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
690 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
692 Info.UsesHMAC = true;
693 HMAC = new HMACContext;
694 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
698 if ( ASDCP_SUCCESS(result) )
699 result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
701 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
703 MXF::RGBAEssenceDescriptor *descriptor = 0;
704 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
705 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
706 descriptor->PictureEssenceCoding = Options.picture_coding;
710 if ( ASDCP_SUCCESS(result) )
713 result = ParserLeft.Reset();
714 if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset();
716 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
718 result = ParserLeft.ReadFrame(FrameBuffer);
720 if ( ASDCP_SUCCESS(result) )
722 if ( Options.verbose_flag )
723 FrameBuffer.Dump(stderr, Options.fb_dump_size);
725 if ( Options.encrypt_header_flag )
726 FrameBuffer.PlaintextOffset(0);
729 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
730 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC);
732 if ( ASDCP_SUCCESS(result) )
733 result = ParserRight.ReadFrame(FrameBuffer);
735 if ( ASDCP_SUCCESS(result) )
737 if ( Options.verbose_flag )
738 FrameBuffer.Dump(stderr, Options.fb_dump_size);
740 if ( Options.encrypt_header_flag )
741 FrameBuffer.PlaintextOffset(0);
744 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
745 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC);
748 if ( result == RESULT_ENDOFFILE )
752 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
753 result = Writer.Finalize();
758 // Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
759 // Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
762 write_JP2K_file(CommandOptions& Options)
764 AESEncContext* Context = 0;
765 HMACContext* HMAC = 0;
766 JP2K::MXFWriter Writer;
767 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
768 JP2K::PictureDescriptor PDesc;
769 JP2K::SequenceParser Parser;
770 byte_t IV_buf[CBC_BLOCK_SIZE];
771 Kumu::FortunaRNG RNG;
773 // set up essence parser
774 Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
777 if ( ASDCP_SUCCESS(result) )
779 Parser.FillPictureDescriptor(PDesc);
780 PDesc.EditRate = Options.PictureRate();
782 if ( Options.verbose_flag )
784 fprintf(stderr, "JPEG 2000 pictures\n");
785 fputs("PictureDescriptor:\n", stderr);
786 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
787 JP2K::PictureDescriptorDump(PDesc);
791 if ( ! check_phfr_params(Options, PDesc) )
794 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
796 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
797 if ( Options.asset_id_flag )
798 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
800 Kumu::GenRandomUUID(Info.AssetUUID);
802 if ( Options.use_smpte_labels )
804 Info.LabelSetType = LS_MXF_SMPTE;
805 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
808 // configure encryption
809 if( Options.key_flag )
811 Kumu::GenRandomUUID(Info.ContextID);
812 Info.EncryptedEssence = true;
814 if ( Options.key_id_flag )
815 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
817 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
819 Context = new AESEncContext;
820 result = Context->InitKey(Options.key_value);
822 if ( ASDCP_SUCCESS(result) )
823 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
825 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
827 Info.UsesHMAC = true;
828 HMAC = new HMACContext;
829 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
833 if ( ASDCP_SUCCESS(result) )
834 result = Writer.OpenWrite(Options.out_file.c_str(), Info, PDesc);
836 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
838 MXF::RGBAEssenceDescriptor *descriptor = 0;
839 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
840 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
841 descriptor->PictureEssenceCoding = Options.picture_coding;
845 if ( ASDCP_SUCCESS(result) )
848 result = Parser.Reset();
850 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
852 result = Parser.ReadFrame(FrameBuffer);
854 if ( ASDCP_SUCCESS(result) )
856 if ( Options.verbose_flag )
857 FrameBuffer.Dump(stderr, Options.fb_dump_size);
859 if ( Options.encrypt_header_flag )
860 FrameBuffer.PlaintextOffset(0);
863 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
865 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
867 // The Writer class will forward the last block of ciphertext
868 // to the encryption context for use as the IV for the next
869 // frame. If you want to use non-sequitur IV values, un-comment
870 // the following line of code.
871 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
872 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
876 if ( result == RESULT_ENDOFFILE )
880 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
881 result = Writer.Finalize();
886 //------------------------------------------------------------------------------------------
890 // Write one or more plaintext PCM audio streams to a plaintext ASDCP file
891 // Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
894 write_PCM_file(CommandOptions& Options)
896 AESEncContext* Context = 0;
897 HMACContext* HMAC = 0;
898 PCMParserList Parser;
899 PCM::MXFWriter Writer;
900 PCM::FrameBuffer FrameBuffer;
901 PCM::AudioDescriptor ADesc;
902 Rational PictureRate = Options.PictureRate();
903 byte_t IV_buf[CBC_BLOCK_SIZE];
904 Kumu::FortunaRNG RNG;
906 // set up essence parser
907 Result_t result = Parser.OpenRead(Options.filenames, PictureRate);
910 if ( ASDCP_SUCCESS(result) )
912 Parser.FillAudioDescriptor(ADesc);
914 ADesc.EditRate = PictureRate;
915 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
916 ADesc.ChannelFormat = Options.channel_fmt;
918 if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE)
920 fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see option -l)\n");
923 if ( Options.verbose_flag )
925 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
926 ADesc.AudioSamplingRate.Quotient() / 1000.0,
927 Options.szPictureRate(),
928 PCM::CalcSamplesPerFrame(ADesc));
929 fputs("AudioDescriptor:\n", stderr);
930 PCM::AudioDescriptorDump(ADesc);
934 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
936 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
937 if ( Options.asset_id_flag )
938 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
940 Kumu::GenRandomUUID(Info.AssetUUID);
942 if ( Options.use_smpte_labels )
944 Info.LabelSetType = LS_MXF_SMPTE;
945 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
948 // configure encryption
949 if( Options.key_flag )
951 Kumu::GenRandomUUID(Info.ContextID);
952 Info.EncryptedEssence = true;
954 if ( Options.key_id_flag )
955 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
957 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
959 Context = new AESEncContext;
960 result = Context->InitKey(Options.key_value);
962 if ( ASDCP_SUCCESS(result) )
963 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
965 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
967 Info.UsesHMAC = true;
968 HMAC = new HMACContext;
969 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
973 if ( ASDCP_SUCCESS(result) )
974 result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
976 if ( ASDCP_SUCCESS(result)
977 && ( Options.channel_assignment.HasValue()
978 || ! Options.mca_config.empty() ) )
980 MXF::WaveAudioDescriptor *essence_descriptor = 0;
981 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_WaveAudioDescriptor),
982 reinterpret_cast<MXF::InterchangeObject**>(&essence_descriptor));
983 assert(essence_descriptor);
985 if ( Options.mca_config.empty() )
987 essence_descriptor->ChannelAssignment = Options.channel_assignment;
991 if ( Options.mca_config.ChannelCount() != essence_descriptor->ChannelCount )
993 fprintf(stderr, "MCA label count (%d) differs from essence stream channel count (%d).\n",
994 Options.mca_config.ChannelCount(), essence_descriptor->ChannelCount);
998 essence_descriptor->ChannelAssignment = g_dict->ul(MDD_DCAudioChannelCfg_MCA);
1000 // add descriptors to the essence_descriptor and header
1001 ASDCP::MXF::InterchangeObject_list_t::iterator i;
1002 for ( i = Options.mca_config.begin(); i != Options.mca_config.end(); ++i )
1004 if ( (*i)->GetUL() != UL(g_dict->ul(MDD_AudioChannelLabelSubDescriptor))
1005 && (*i)->GetUL() != UL(g_dict->ul(MDD_SoundfieldGroupLabelSubDescriptor))
1006 && (*i)->GetUL() != UL(g_dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor)) )
1008 fprintf(stderr, "Essence sub-descriptor is not an MCALabelSubDescriptor.\n");
1012 Writer.OP1aHeader().AddChildObject(*i);
1013 essence_descriptor->SubDescriptors.push_back((*i)->InstanceUID);
1014 *i = 0; // parent will only free the ones we don't keep
1020 if ( ASDCP_SUCCESS(result) )
1022 result = Parser.Reset();
1023 ui32_t duration = 0;
1025 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1027 result = Parser.ReadFrame(FrameBuffer);
1029 if ( ASDCP_SUCCESS(result) )
1031 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1033 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1034 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1035 result = RESULT_ENDOFFILE;
1039 if ( Options.verbose_flag )
1040 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1042 if ( ! Options.no_write_flag )
1044 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1046 // The Writer class will forward the last block of ciphertext
1047 // to the encryption context for use as the IV for the next
1048 // frame. If you want to use non-sequitur IV values, un-comment
1049 // the following line of code.
1050 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1051 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1056 if ( result == RESULT_ENDOFFILE )
1060 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1061 result = Writer.Finalize();
1066 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a plaintext ASDCP file
1067 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a ciphertext ASDCP file
1070 write_PCM_with_ATMOS_sync_file(CommandOptions& Options)
1072 AESEncContext* Context = 0;
1073 HMACContext* HMAC = 0;
1074 PCM::MXFWriter Writer;
1075 PCM::FrameBuffer FrameBuffer;
1076 PCM::AudioDescriptor ADesc;
1077 Rational PictureRate = Options.PictureRate();
1078 byte_t IV_buf[CBC_BLOCK_SIZE];
1079 Kumu::FortunaRNG RNG;
1081 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1082 if ( Options.asset_id_flag )
1083 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1085 Kumu::GenRandomUUID(Info.AssetUUID);
1086 AtmosSyncChannelMixer Mixer(Info.AssetUUID);
1088 // set up essence parser
1089 Result_t result = Mixer.OpenRead(Options.filenames, PictureRate);
1091 // set up MXF writer
1092 if ( ASDCP_SUCCESS(result) )
1094 Mixer.FillAudioDescriptor(ADesc);
1096 ADesc.EditRate = PictureRate;
1097 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
1098 ADesc.ChannelFormat = PCM::CF_CFG_4;
1100 if ( Options.verbose_flag )
1102 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
1103 ADesc.AudioSamplingRate.Quotient() / 1000.0,
1104 Options.szPictureRate(),
1105 PCM::CalcSamplesPerFrame(ADesc));
1106 fputs("AudioDescriptor:\n", stderr);
1107 PCM::AudioDescriptorDump(ADesc);
1111 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1113 Info.LabelSetType = LS_MXF_SMPTE;
1114 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1116 // configure encryption
1117 if( Options.key_flag )
1119 Kumu::GenRandomUUID(Info.ContextID);
1120 Info.EncryptedEssence = true;
1122 if ( Options.key_id_flag )
1123 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1125 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1127 Context = new AESEncContext;
1128 result = Context->InitKey(Options.key_value);
1130 if ( ASDCP_SUCCESS(result) )
1131 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1133 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1135 Info.UsesHMAC = true;
1136 HMAC = new HMACContext;
1137 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1141 if ( ASDCP_SUCCESS(result) )
1142 result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
1145 if ( ASDCP_SUCCESS(result) )
1147 result = Mixer.Reset();
1148 ui32_t duration = 0;
1150 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1152 result = Mixer.ReadFrame(FrameBuffer);
1154 if ( ASDCP_SUCCESS(result) )
1156 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1158 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1159 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1160 result = RESULT_ENDOFFILE;
1164 if ( Options.verbose_flag )
1165 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1167 if ( ! Options.no_write_flag )
1169 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1171 // The Writer class will forward the last block of ciphertext
1172 // to the encryption context for use as the IV for the next
1173 // frame. If you want to use non-sequitur IV values, un-comment
1174 // the following line of code.
1175 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1176 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1181 if ( result == RESULT_ENDOFFILE )
1185 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1186 result = Writer.Finalize();
1192 //------------------------------------------------------------------------------------------
1193 // TimedText essence
1196 // Write one or more plaintext timed text streams to a plaintext ASDCP file
1197 // Write one or more plaintext timed text streams to a ciphertext ASDCP file
1200 write_timed_text_file(CommandOptions& Options)
1202 AESEncContext* Context = 0;
1203 HMACContext* HMAC = 0;
1204 TimedText::DCSubtitleParser Parser;
1205 TimedText::MXFWriter Writer;
1206 TimedText::FrameBuffer FrameBuffer;
1207 TimedText::TimedTextDescriptor TDesc;
1208 byte_t IV_buf[CBC_BLOCK_SIZE];
1209 Kumu::FortunaRNG RNG;
1211 // set up essence parser
1212 Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
1214 // set up MXF writer
1215 if ( ASDCP_SUCCESS(result) )
1217 Parser.FillTimedTextDescriptor(TDesc);
1218 FrameBuffer.Capacity(Options.fb_size);
1220 if ( Options.verbose_flag )
1222 fputs("D-Cinema Timed-Text Descriptor:\n", stderr);
1223 TimedText::DescriptorDump(TDesc);
1227 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1229 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1230 if ( Options.asset_id_flag )
1231 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1233 Kumu::GenRandomUUID(Info.AssetUUID);
1235 // 428-7 IN 429-5 always uses SMPTE labels
1236 Info.LabelSetType = LS_MXF_SMPTE;
1237 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1239 // configure encryption
1240 if( Options.key_flag )
1242 Kumu::GenRandomUUID(Info.ContextID);
1243 Info.EncryptedEssence = true;
1245 if ( Options.key_id_flag )
1246 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1248 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1250 Context = new AESEncContext;
1251 result = Context->InitKey(Options.key_value);
1253 if ( ASDCP_SUCCESS(result) )
1254 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1256 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1258 Info.UsesHMAC = true;
1259 HMAC = new HMACContext;
1260 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1264 if ( ASDCP_SUCCESS(result) )
1265 result = Writer.OpenWrite(Options.out_file.c_str(), Info, TDesc);
1268 if ( ASDCP_FAILURE(result) )
1272 TimedText::ResourceList_t::const_iterator ri;
1274 result = Parser.ReadTimedTextResource(XMLDoc);
1276 if ( ASDCP_SUCCESS(result) )
1277 result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
1279 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
1281 result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
1283 if ( ASDCP_SUCCESS(result) )
1285 if ( Options.verbose_flag )
1286 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1288 if ( ! Options.no_write_flag )
1290 result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
1292 // The Writer class will forward the last block of ciphertext
1293 // to the encryption context for use as the IV for the next
1294 // frame. If you want to use non-sequitur IV values, un-comment
1295 // the following line of code.
1296 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1297 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1301 if ( result == RESULT_ENDOFFILE )
1305 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1306 result = Writer.Finalize();
1311 // Write one or more plaintext Dolby ATMOS bytestreams to a plaintext ASDCP file
1312 // Write one or more plaintext Dolby ATMOS bytestreams to a ciphertext ASDCP file
1315 write_dolby_atmos_file(CommandOptions& Options)
1317 AESEncContext* Context = 0;
1318 HMACContext* HMAC = 0;
1319 ATMOS::MXFWriter Writer;
1320 DCData::FrameBuffer FrameBuffer(Options.fb_size);
1321 ATMOS::AtmosDescriptor ADesc;
1322 DCData::SequenceParser Parser;
1323 byte_t IV_buf[CBC_BLOCK_SIZE];
1324 Kumu::FortunaRNG RNG;
1326 // set up essence parser
1327 Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
1329 // set up MXF writer
1330 if ( ASDCP_SUCCESS(result) )
1332 Parser.FillDCDataDescriptor(ADesc);
1333 ADesc.EditRate = Options.PictureRate();
1334 // TODO: fill AtmosDescriptor
1335 ADesc.FirstFrame = Options.ffoa;
1336 ADesc.MaxChannelCount = Options.max_channel_count;
1337 ADesc.MaxObjectCount = Options.max_object_count;
1338 Kumu::GenRandomUUID(ADesc.AtmosID);
1339 ADesc.AtmosVersion = 1;
1340 if ( Options.verbose_flag )
1342 fprintf(stderr, "Dolby ATMOS Data\n");
1343 fputs("AtmosDescriptor:\n", stderr);
1344 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
1345 ATMOS::AtmosDescriptorDump(ADesc);
1349 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1351 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1352 if ( Options.asset_id_flag )
1353 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1355 Kumu::GenRandomUUID(Info.AssetUUID);
1357 Info.LabelSetType = LS_MXF_SMPTE;
1359 // configure encryption
1360 if( Options.key_flag )
1362 Kumu::GenRandomUUID(Info.ContextID);
1363 Info.EncryptedEssence = true;
1365 if ( Options.key_id_flag )
1366 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1368 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1370 Context = new AESEncContext;
1371 result = Context->InitKey(Options.key_value);
1373 if ( ASDCP_SUCCESS(result) )
1374 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1376 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1378 Info.UsesHMAC = true;
1379 HMAC = new HMACContext;
1380 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1384 if ( ASDCP_SUCCESS(result) )
1385 result = Writer.OpenWrite(Options.out_file.c_str(), Info, ADesc);
1388 if ( ASDCP_SUCCESS(result) )
1390 ui32_t duration = 0;
1391 result = Parser.Reset();
1393 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1395 result = Parser.ReadFrame(FrameBuffer);
1397 if ( ASDCP_SUCCESS(result) )
1399 if ( Options.verbose_flag )
1400 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1402 if ( Options.encrypt_header_flag )
1403 FrameBuffer.PlaintextOffset(0);
1406 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1408 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1410 // The Writer class will forward the last block of ciphertext
1411 // to the encryption context for use as the IV for the next
1412 // frame. If you want to use non-sequitur IV values, un-comment
1413 // the following line of code.
1414 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1415 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1419 if ( result == RESULT_ENDOFFILE )
1423 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1424 result = Writer.Finalize();
1431 main(int argc, const char** argv)
1433 Result_t result = RESULT_OK;
1435 g_dict = &ASDCP::DefaultSMPTEDict();
1437 CommandOptions Options(argc, argv);
1439 if ( Options.version_flag )
1442 if ( Options.help_flag )
1445 if ( Options.show_ul_values_flag )
1447 if ( Options.use_smpte_labels )
1448 DefaultSMPTEDict().Dump(stdout);
1450 DefaultInteropDict().Dump(stdout);
1453 if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
1456 if ( Options.error_flag )
1458 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
1462 EssenceType_t EssenceType;
1463 result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType);
1465 if ( ASDCP_SUCCESS(result) )
1467 switch ( EssenceType )
1470 result = write_MPEG2_file(Options);
1474 if ( Options.stereo_image_flag )
1476 result = write_JP2K_S_file(Options);
1480 result = write_JP2K_file(Options);
1484 case ESS_PCM_24b_48k:
1485 case ESS_PCM_24b_96k:
1486 if ( Options.dolby_atmos_sync_flag )
1488 result = write_PCM_with_ATMOS_sync_file(Options);
1492 result = write_PCM_file(Options);
1496 case ESS_TIMED_TEXT:
1497 result = write_timed_text_file(Options);
1500 case ESS_DCDATA_DOLBY_ATMOS:
1501 result = write_dolby_atmos_file(Options);
1505 fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
1506 Options.filenames.front().c_str());
1511 if ( ASDCP_FAILURE(result) )
1513 fputs("Program stopped on error.\n", stderr);
1515 if ( result != RESULT_FAIL )
1517 fputs(result, stderr);
1518 fputc('\n', stderr);
1529 // end asdcp-wrap.cpp