2 Copyright (c) 2003-2014, 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 create_random_uuid(byte_t* uuidbuf)
106 GenRandomValue(tmp_id);
107 memcpy(uuidbuf, tmp_id.Value(), tmp_id.Size());
112 banner(FILE* stream = stdout)
115 %s (asdcplib %s)\n\n\
116 Copyright (c) 2003-2014 John Hurst\n\n\
117 asdcplib may be copied only under the terms of the license found at\n\
118 the top of every file in the asdcplib distribution kit.\n\n\
119 Specify the -h (help) option for further information about %s\n\n",
120 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
125 usage(FILE* stream = stdout)
128 USAGE: %s [-h|-help] [-V]\n\
130 %s [-3] [-a <uuid>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
131 [-e|-E] [-f <start-frame>] [-j <key-id-string>] [-k <key-string>]\n\
132 [-l <label>] [-L] [-M] [-m <expr>] [-p <frame-rate>] [-s] [-v]\n\
133 [-W] [-z|-Z] <input-file>+ <output-file>\n\n",
134 PROGRAM_NAME, PROGRAM_NAME);
138 -3 - Create a stereoscopic image file. Expects two\n\
139 directories of JP2K codestreams (directories must have\n\
140 an equal number of frames; the left eye is first)\n\
141 -C <UL> - Set ChannelAssignment UL value in a PCM file\n\
142 -h | -help - Show help\n\
143 -V - Show version information\n\
144 -e - Encrypt MPEG or JP2K headers (default)\n\
145 -E - Do not encrypt MPEG or JP2K headers\n\
146 -j <key-id-str> - Write key ID instead of creating a random value\n\
147 -k <key-string> - Use key for ciphertext operations\n\
148 -M - Do not create HMAC values when writing\n\
149 -m <expr> - Write MCA labels using <expr>. Example:\n\
150 51(L,R,C,LFE,Ls,Rs,),HI,VIN\n\
151 Note: The symbol '-' may be used for an unlabeled\n\
152 channel, but not within a soundfield.\n\
153 -a <UUID> - Specify the Asset ID of the file\n\
154 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
155 Defaults to 4,194,304 (4MB)\n\
156 -d <duration> - Number of frames to process, default all\n\
157 -f <start-frame> - Starting frame number, default 0\n\
158 -l <label> - Use given channel format label when writing MXF sound\n\
159 files. SMPTE 429-2 labels: '5.1', '6.1', '7.1',\n\
161 Default is no label (valid for Interop only).\n\
162 -L - Write SMPTE UL values instead of MXF Interop\n\
163 -P <UL> - Set PictureEssenceCoding UL value in a JP2K file\n\
164 -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
165 Use one of [23|24|25|30|48|50|60], 24 is default\n\
166 -s - Insert a Dolby Atmos synchronization channel when\n\
167 wrapping PCM. This implies a -L option(SMPTE ULs) and \n\
168 will overide -C and -l options with Configuration 4 \n\
169 Channel Assigment and no format label respectively. \n\
170 -v - Verbose, prints informative messages to stderr\n\
171 -W - Read input file only, do not write source file\n\
172 -z - Fail if j2c inputs have unequal parameters (default)\n\
173 -Z - Ignore unequal parameters in j2c inputs\n\
175 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
176 o All option arguments must be separated from the option by whitespace.\n\
177 o An argument of \"23\" to the -p option will be interpreted\n\
178 as 24000/1001 fps.\n\
184 decode_channel_fmt(const std::string& label_name)
186 if ( label_name == "5.1" )
187 return PCM::CF_CFG_1;
189 else if ( label_name == "6.1" )
190 return PCM::CF_CFG_2;
192 else if ( label_name == "7.1" )
193 return PCM::CF_CFG_3;
195 else if ( label_name == "WTF" )
196 return PCM::CF_CFG_4;
198 else if ( label_name == "7.1DS" )
199 return PCM::CF_CFG_5;
201 fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
202 fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n");
213 bool error_flag; // true if the given options are in error or not complete
214 bool key_flag; // true if an encryption key was given
215 bool asset_id_flag; // true if an asset ID was given
216 bool encrypt_header_flag; // true if mpeg headers are to be encrypted
217 bool write_hmac; // true if HMAC values are to be generated and written
218 bool verbose_flag; // true if the verbose option was selected
219 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
220 bool no_write_flag; // true if no output files are to be written
221 bool version_flag; // true if the version display option was selected
222 bool help_flag; // true if the help display option was selected
223 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
224 ui32_t start_frame; // frame number to begin processing
225 ui32_t duration; // number of frames to be processed
226 bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values
227 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
228 ui32_t picture_rate; // fps of picture when wrapping PCM
229 ui32_t fb_size; // size of picture frame buffer
230 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
231 bool key_id_flag; // true if a key ID was given
232 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
233 byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
234 PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
235 std::string out_file; //
236 bool show_ul_values_flag; /// if true, dump the UL table before going to work.
237 Kumu::PathList_t filenames; // list of filenames to be processed
238 UL channel_assignment;
240 bool dolby_atmos_sync_flag; // if true, insert a Dolby Atmos Synchronization channel.
241 ui32_t ffoa; /// first frame of action for atmos wrapping
242 ui32_t max_channel_count; /// max channel count for atmos wrapping
243 ui32_t max_object_count; /// max object count for atmos wrapping
244 ASDCP::MXF::ASDCP_MCAConfigParser mca_config;
247 Rational PictureRate()
249 if ( picture_rate == 16 ) return EditRate_16;
250 if ( picture_rate == 18 ) return EditRate_18;
251 if ( picture_rate == 20 ) return EditRate_20;
252 if ( picture_rate == 22 ) return EditRate_22;
253 if ( picture_rate == 23 ) return EditRate_23_98;
254 if ( picture_rate == 24 ) return EditRate_24;
255 if ( picture_rate == 25 ) return EditRate_25;
256 if ( picture_rate == 30 ) return EditRate_30;
257 if ( picture_rate == 48 ) return EditRate_48;
258 if ( picture_rate == 50 ) return EditRate_50;
259 if ( picture_rate == 60 ) return EditRate_60;
260 if ( picture_rate == 96 ) return EditRate_96;
261 if ( picture_rate == 100 ) return EditRate_100;
262 if ( picture_rate == 120 ) return EditRate_120;
267 const char* szPictureRate()
269 if ( picture_rate == 16 ) return "16";
270 if ( picture_rate == 18 ) return "18.182";
271 if ( picture_rate == 20 ) return "20";
272 if ( picture_rate == 22 ) return "21.818";
273 if ( picture_rate == 23 ) return "23.976";
274 if ( picture_rate == 24 ) return "24";
275 if ( picture_rate == 25 ) return "25";
276 if ( picture_rate == 30 ) return "30";
277 if ( picture_rate == 48 ) return "48";
278 if ( picture_rate == 50 ) return "50";
279 if ( picture_rate == 60 ) return "60";
280 if ( picture_rate == 96 ) return "96";
281 if ( picture_rate == 100 ) return "100";
282 if ( picture_rate == 120 ) return "120";
287 CommandOptions(int argc, const char** argv) :
288 error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
289 encrypt_header_flag(true), write_hmac(true),
290 verbose_flag(false), fb_dump_size(0),
291 no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
293 duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
294 fb_size(FRAME_BUFFER_SIZE),
295 channel_fmt(PCM::CF_NONE),
296 ffoa(0), max_channel_count(10), max_object_count(118), // hard-coded sample atmos properties
297 dolby_atmos_sync_flag(false),
298 show_ul_values_flag(false),
301 memset(key_value, 0, KeyLen);
302 memset(key_id_value, 0, UUIDlen);
304 for ( int i = 1; i < argc; i++ )
307 if ( (strcmp( argv[i], "-help") == 0) )
313 if ( argv[i][0] == '-'
314 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
317 switch ( argv[i][1] )
319 case '3': stereo_image_flag = true; break;
322 asset_id_flag = true;
323 TEST_EXTRA_ARG(i, 'a');
326 Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
328 if ( length != UUIDlen )
330 fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
337 TEST_EXTRA_ARG(i, 'b');
338 fb_size = abs(atoi(argv[i]));
341 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
346 TEST_EXTRA_ARG(i, 'C');
347 if ( ! channel_assignment.DecodeHex(argv[i]) )
349 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
355 TEST_EXTRA_ARG(i, 'd');
356 duration = abs(atoi(argv[i]));
359 case 'E': encrypt_header_flag = false; break;
360 case 'e': encrypt_header_flag = true; break;
363 TEST_EXTRA_ARG(i, 'f');
364 start_frame = abs(atoi(argv[i]));
367 case 'h': help_flag = true; break;
369 case 'j': key_id_flag = true;
370 TEST_EXTRA_ARG(i, 'j');
373 Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
375 if ( length != UUIDlen )
377 fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
383 case 'k': key_flag = true;
384 TEST_EXTRA_ARG(i, 'k');
387 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
389 if ( length != KeyLen )
391 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
398 TEST_EXTRA_ARG(i, 'l');
399 channel_fmt = decode_channel_fmt(argv[i]);
402 case 'L': use_smpte_labels = true; break;
403 case 'M': write_hmac = false; break;
406 TEST_EXTRA_ARG(i, 'm');
407 if ( ! mca_config.DecodeString(argv[i]) )
414 TEST_EXTRA_ARG(i, 'P');
415 if ( ! picture_coding.DecodeHex(argv[i]) )
417 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
423 TEST_EXTRA_ARG(i, 'p');
424 picture_rate = abs(atoi(argv[i]));
427 case 's': dolby_atmos_sync_flag = true; break;
428 case 'u': show_ul_values_flag = true; break;
429 case 'V': version_flag = true; break;
430 case 'v': verbose_flag = true; break;
431 case 'W': no_write_flag = true; break;
432 case 'Z': j2c_pedantic = false; break;
433 case 'z': j2c_pedantic = true; break;
436 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
443 if ( argv[i][0] != '-' )
445 filenames.push_back(argv[i]);
449 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
455 if ( help_flag || version_flag )
458 if ( filenames.size() < 2 )
460 fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
464 out_file = filenames.back();
465 filenames.pop_back();
470 //------------------------------------------------------------------------------------------
473 // Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
474 // Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
477 write_MPEG2_file(CommandOptions& Options)
479 AESEncContext* Context = 0;
480 HMACContext* HMAC = 0;
481 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
482 MPEG2::Parser Parser;
483 MPEG2::MXFWriter Writer;
484 MPEG2::VideoDescriptor VDesc;
485 byte_t IV_buf[CBC_BLOCK_SIZE];
486 Kumu::FortunaRNG RNG;
488 // set up essence parser
489 Result_t result = Parser.OpenRead(Options.filenames.front());
492 if ( ASDCP_SUCCESS(result) )
494 Parser.FillVideoDescriptor(VDesc);
496 if ( Options.verbose_flag )
498 fputs("MPEG-2 Pictures\n", stderr);
499 fputs("VideoDescriptor:\n", stderr);
500 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
501 MPEG2::VideoDescriptorDump(VDesc);
505 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
507 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
508 if ( Options.asset_id_flag )
509 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
511 Kumu::GenRandomUUID(Info.AssetUUID);
513 if ( Options.use_smpte_labels )
515 Info.LabelSetType = LS_MXF_SMPTE;
516 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
519 // configure encryption
520 if( Options.key_flag )
522 Kumu::GenRandomUUID(Info.ContextID);
523 Info.EncryptedEssence = true;
525 if ( Options.key_id_flag )
527 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
531 create_random_uuid(Info.CryptographicKeyID);
534 Context = new AESEncContext;
535 result = Context->InitKey(Options.key_value);
537 if ( ASDCP_SUCCESS(result) )
538 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
540 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
542 Info.UsesHMAC = true;
543 HMAC = new HMACContext;
544 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
548 if ( ASDCP_SUCCESS(result) )
549 result = Writer.OpenWrite(Options.out_file, Info, VDesc);
552 if ( ASDCP_SUCCESS(result) )
553 // loop through the frames
555 result = Parser.Reset();
558 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
560 result = Parser.ReadFrame(FrameBuffer);
562 if ( ASDCP_SUCCESS(result) )
564 if ( Options.verbose_flag )
565 FrameBuffer.Dump(stderr, Options.fb_dump_size);
567 if ( Options.encrypt_header_flag )
568 FrameBuffer.PlaintextOffset(0);
571 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
573 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
575 // The Writer class will forward the last block of ciphertext
576 // to the encryption context for use as the IV for the next
577 // frame. If you want to use non-sequitur IV values, un-comment
578 // the following line of code.
579 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
580 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
584 if ( result == RESULT_ENDOFFILE )
588 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
589 result = Writer.Finalize();
595 //------------------------------------------------------------------------------------------
597 // return false if an error is discovered
599 check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
601 Rational rate = Options.PictureRate();
602 if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120 )
605 if ( PDesc.StoredWidth > 2048 )
607 fprintf(stderr, "P-HFR files currently limited to 2K.\n");
611 if ( ! Options.use_smpte_labels )
613 fprintf(stderr, "P-HFR files must be written using SMPTE labels. Use option '-L'.\n");
617 // do not set the label if the user has already done so
618 if ( ! Options.picture_coding.HasValue() )
619 Options.picture_coding = UL(P_HFR_UL_2K);
624 //------------------------------------------------------------------------------------------
627 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file
628 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file
631 write_JP2K_S_file(CommandOptions& Options)
633 AESEncContext* Context = 0;
634 HMACContext* HMAC = 0;
635 JP2K::MXFSWriter Writer;
636 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
637 JP2K::PictureDescriptor PDesc;
638 JP2K::SequenceParser ParserLeft, ParserRight;
639 byte_t IV_buf[CBC_BLOCK_SIZE];
640 Kumu::FortunaRNG RNG;
642 if ( Options.filenames.size() != 2 )
644 fprintf(stderr, "Two inputs are required for stereoscopic option.\n");
648 // set up essence parser
649 Result_t result = ParserLeft.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
651 if ( ASDCP_SUCCESS(result) )
653 Options.filenames.pop_front();
654 result = ParserRight.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
658 if ( ASDCP_SUCCESS(result) )
660 ParserLeft.FillPictureDescriptor(PDesc);
661 PDesc.EditRate = Options.PictureRate();
663 if ( Options.verbose_flag )
665 fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr);
666 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
667 JP2K::PictureDescriptorDump(PDesc);
671 if ( ! check_phfr_params(Options, PDesc) )
674 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
676 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
677 if ( Options.asset_id_flag )
678 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
680 Kumu::GenRandomUUID(Info.AssetUUID);
682 if ( Options.use_smpte_labels )
684 Info.LabelSetType = LS_MXF_SMPTE;
685 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
688 // configure encryption
689 if( Options.key_flag )
691 Kumu::GenRandomUUID(Info.ContextID);
692 Info.EncryptedEssence = true;
694 if ( Options.key_id_flag )
696 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
700 create_random_uuid(Info.CryptographicKeyID);
703 Context = new AESEncContext;
704 result = Context->InitKey(Options.key_value);
706 if ( ASDCP_SUCCESS(result) )
707 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
709 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
711 Info.UsesHMAC = true;
712 HMAC = new HMACContext;
713 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
717 if ( ASDCP_SUCCESS(result) )
718 result = Writer.OpenWrite(Options.out_file, Info, PDesc);
720 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
722 MXF::RGBAEssenceDescriptor *descriptor = 0;
723 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
724 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
725 descriptor->PictureEssenceCoding = Options.picture_coding;
729 if ( ASDCP_SUCCESS(result) )
732 result = ParserLeft.Reset();
733 if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset();
735 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
737 result = ParserLeft.ReadFrame(FrameBuffer);
739 if ( ASDCP_SUCCESS(result) )
741 if ( Options.verbose_flag )
742 FrameBuffer.Dump(stderr, Options.fb_dump_size);
744 if ( Options.encrypt_header_flag )
745 FrameBuffer.PlaintextOffset(0);
748 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
749 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC);
751 if ( ASDCP_SUCCESS(result) )
752 result = ParserRight.ReadFrame(FrameBuffer);
754 if ( ASDCP_SUCCESS(result) )
756 if ( Options.verbose_flag )
757 FrameBuffer.Dump(stderr, Options.fb_dump_size);
759 if ( Options.encrypt_header_flag )
760 FrameBuffer.PlaintextOffset(0);
763 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
764 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC);
767 if ( result == RESULT_ENDOFFILE )
771 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
772 result = Writer.Finalize();
777 // Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
778 // Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
781 write_JP2K_file(CommandOptions& Options)
783 AESEncContext* Context = 0;
784 HMACContext* HMAC = 0;
785 JP2K::MXFWriter Writer;
786 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
787 JP2K::PictureDescriptor PDesc;
788 JP2K::SequenceParser Parser;
789 byte_t IV_buf[CBC_BLOCK_SIZE];
790 Kumu::FortunaRNG RNG;
792 // set up essence parser
793 Result_t result = Parser.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
796 if ( ASDCP_SUCCESS(result) )
798 Parser.FillPictureDescriptor(PDesc);
799 PDesc.EditRate = Options.PictureRate();
801 if ( Options.verbose_flag )
803 fprintf(stderr, "JPEG 2000 pictures\n");
804 fputs("PictureDescriptor:\n", stderr);
805 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
806 JP2K::PictureDescriptorDump(PDesc);
810 if ( ! check_phfr_params(Options, PDesc) )
813 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
815 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
816 if ( Options.asset_id_flag )
817 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
819 Kumu::GenRandomUUID(Info.AssetUUID);
821 if ( Options.use_smpte_labels )
823 Info.LabelSetType = LS_MXF_SMPTE;
824 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
827 // configure encryption
828 if( Options.key_flag )
830 Kumu::GenRandomUUID(Info.ContextID);
831 Info.EncryptedEssence = true;
833 if ( Options.key_id_flag )
835 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
839 create_random_uuid(Info.CryptographicKeyID);
842 Context = new AESEncContext;
843 result = Context->InitKey(Options.key_value);
845 if ( ASDCP_SUCCESS(result) )
846 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
848 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
850 Info.UsesHMAC = true;
851 HMAC = new HMACContext;
852 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
856 if ( ASDCP_SUCCESS(result) )
857 result = Writer.OpenWrite(Options.out_file, Info, PDesc);
859 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
861 MXF::RGBAEssenceDescriptor *descriptor = 0;
862 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
863 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
864 descriptor->PictureEssenceCoding = Options.picture_coding;
868 if ( ASDCP_SUCCESS(result) )
871 result = Parser.Reset();
873 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
875 result = Parser.ReadFrame(FrameBuffer);
877 if ( ASDCP_SUCCESS(result) )
879 if ( Options.verbose_flag )
880 FrameBuffer.Dump(stderr, Options.fb_dump_size);
882 if ( Options.encrypt_header_flag )
883 FrameBuffer.PlaintextOffset(0);
886 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
888 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
890 // The Writer class will forward the last block of ciphertext
891 // to the encryption context for use as the IV for the next
892 // frame. If you want to use non-sequitur IV values, un-comment
893 // the following line of code.
894 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
895 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
899 if ( result == RESULT_ENDOFFILE )
903 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
904 result = Writer.Finalize();
909 //------------------------------------------------------------------------------------------
913 // Write one or more plaintext PCM audio streams to a plaintext ASDCP file
914 // Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
917 write_PCM_file(CommandOptions& Options)
919 AESEncContext* Context = 0;
920 HMACContext* HMAC = 0;
921 PCMParserList Parser;
922 PCM::MXFWriter Writer;
923 PCM::FrameBuffer FrameBuffer;
924 PCM::AudioDescriptor ADesc;
925 Rational PictureRate = Options.PictureRate();
926 byte_t IV_buf[CBC_BLOCK_SIZE];
927 Kumu::FortunaRNG RNG;
929 // set up essence parser
930 Result_t result = Parser.OpenRead(Options.filenames, PictureRate);
933 if ( ASDCP_SUCCESS(result) )
935 Parser.FillAudioDescriptor(ADesc);
937 ADesc.EditRate = PictureRate;
938 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
939 ADesc.ChannelFormat = Options.channel_fmt;
941 if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE && Options.mca_config.empty() )
943 fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see options -C, -l and -m)\n");
946 if ( Options.verbose_flag )
948 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
949 ADesc.AudioSamplingRate.Quotient() / 1000.0,
950 Options.szPictureRate(),
951 PCM::CalcSamplesPerFrame(ADesc));
952 fputs("AudioDescriptor:\n", stderr);
953 PCM::AudioDescriptorDump(ADesc);
957 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
959 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
960 if ( Options.asset_id_flag )
961 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
963 Kumu::GenRandomUUID(Info.AssetUUID);
965 if ( Options.use_smpte_labels )
967 Info.LabelSetType = LS_MXF_SMPTE;
968 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
971 // configure encryption
972 if( Options.key_flag )
974 Kumu::GenRandomUUID(Info.ContextID);
975 Info.EncryptedEssence = true;
977 if ( Options.key_id_flag )
979 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
983 create_random_uuid(Info.CryptographicKeyID);
986 Context = new AESEncContext;
987 result = Context->InitKey(Options.key_value);
989 if ( ASDCP_SUCCESS(result) )
990 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
992 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
994 Info.UsesHMAC = true;
995 HMAC = new HMACContext;
996 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1000 if ( ASDCP_SUCCESS(result) )
1001 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
1003 if ( ASDCP_SUCCESS(result)
1004 && ( Options.channel_assignment.HasValue()
1005 || ! Options.mca_config.empty() ) )
1007 MXF::WaveAudioDescriptor *essence_descriptor = 0;
1008 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_WaveAudioDescriptor),
1009 reinterpret_cast<MXF::InterchangeObject**>(&essence_descriptor));
1010 assert(essence_descriptor);
1012 if ( Options.mca_config.empty() )
1014 essence_descriptor->ChannelAssignment = Options.channel_assignment;
1018 if ( Options.mca_config.ChannelCount() != essence_descriptor->ChannelCount )
1020 fprintf(stderr, "MCA label count (%d) differs from essence stream channel count (%d).\n",
1021 Options.mca_config.ChannelCount(), essence_descriptor->ChannelCount);
1025 essence_descriptor->ChannelAssignment = g_dict->ul(MDD_DCAudioChannelCfg_MCA);
1027 // add descriptors to the essence_descriptor and header
1028 ASDCP::MXF::InterchangeObject_list_t::iterator i;
1029 for ( i = Options.mca_config.begin(); i != Options.mca_config.end(); ++i )
1031 if ( (*i)->GetUL() != UL(g_dict->ul(MDD_AudioChannelLabelSubDescriptor))
1032 && (*i)->GetUL() != UL(g_dict->ul(MDD_SoundfieldGroupLabelSubDescriptor))
1033 && (*i)->GetUL() != UL(g_dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor)) )
1035 fprintf(stderr, "Essence sub-descriptor is not an MCALabelSubDescriptor.\n");
1039 Writer.OP1aHeader().AddChildObject(*i);
1040 essence_descriptor->SubDescriptors.push_back((*i)->InstanceUID);
1041 *i = 0; // parent will only free the ones we don't keep
1047 if ( ASDCP_SUCCESS(result) )
1049 result = Parser.Reset();
1050 ui32_t duration = 0;
1052 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1054 result = Parser.ReadFrame(FrameBuffer);
1056 if ( ASDCP_SUCCESS(result) )
1058 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1060 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1061 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1062 result = RESULT_ENDOFFILE;
1066 if ( Options.verbose_flag )
1067 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1069 if ( ! Options.no_write_flag )
1071 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1073 // The Writer class will forward the last block of ciphertext
1074 // to the encryption context for use as the IV for the next
1075 // frame. If you want to use non-sequitur IV values, un-comment
1076 // the following line of code.
1077 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1078 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1083 if ( result == RESULT_ENDOFFILE )
1087 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1088 result = Writer.Finalize();
1093 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a plaintext ASDCP file
1094 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a ciphertext ASDCP file
1097 write_PCM_with_ATMOS_sync_file(CommandOptions& Options)
1099 AESEncContext* Context = 0;
1100 HMACContext* HMAC = 0;
1101 PCM::MXFWriter Writer;
1102 PCM::FrameBuffer FrameBuffer;
1103 PCM::AudioDescriptor ADesc;
1104 Rational PictureRate = Options.PictureRate();
1105 byte_t IV_buf[CBC_BLOCK_SIZE];
1106 Kumu::FortunaRNG RNG;
1108 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1109 if ( Options.asset_id_flag )
1110 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1112 Kumu::GenRandomUUID(Info.AssetUUID);
1113 AtmosSyncChannelMixer Mixer(Info.AssetUUID);
1115 // set up essence parser
1116 Result_t result = Mixer.OpenRead(Options.filenames, PictureRate);
1118 // set up MXF writer
1119 if ( ASDCP_SUCCESS(result) )
1121 Mixer.FillAudioDescriptor(ADesc);
1123 ADesc.EditRate = PictureRate;
1124 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
1125 ADesc.ChannelFormat = PCM::CF_CFG_4;
1127 if ( Options.verbose_flag )
1129 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
1130 ADesc.AudioSamplingRate.Quotient() / 1000.0,
1131 Options.szPictureRate(),
1132 PCM::CalcSamplesPerFrame(ADesc));
1133 fputs("AudioDescriptor:\n", stderr);
1134 PCM::AudioDescriptorDump(ADesc);
1138 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1140 Info.LabelSetType = LS_MXF_SMPTE;
1141 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1143 // configure encryption
1144 if( Options.key_flag )
1146 Kumu::GenRandomUUID(Info.ContextID);
1147 Info.EncryptedEssence = true;
1149 if ( Options.key_id_flag )
1151 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1155 create_random_uuid(Info.CryptographicKeyID);
1158 Context = new AESEncContext;
1159 result = Context->InitKey(Options.key_value);
1161 if ( ASDCP_SUCCESS(result) )
1162 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1164 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1166 Info.UsesHMAC = true;
1167 HMAC = new HMACContext;
1168 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1172 if ( ASDCP_SUCCESS(result) )
1173 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
1176 if ( ASDCP_SUCCESS(result) )
1178 result = Mixer.Reset();
1179 ui32_t duration = 0;
1181 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1183 result = Mixer.ReadFrame(FrameBuffer);
1185 if ( ASDCP_SUCCESS(result) )
1187 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1189 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1190 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1191 result = RESULT_ENDOFFILE;
1195 if ( Options.verbose_flag )
1196 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1198 if ( ! Options.no_write_flag )
1200 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1202 // The Writer class will forward the last block of ciphertext
1203 // to the encryption context for use as the IV for the next
1204 // frame. If you want to use non-sequitur IV values, un-comment
1205 // the following line of code.
1206 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1207 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1212 if ( result == RESULT_ENDOFFILE )
1216 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1217 result = Writer.Finalize();
1223 //------------------------------------------------------------------------------------------
1224 // TimedText essence
1227 // Write one or more plaintext timed text streams to a plaintext ASDCP file
1228 // Write one or more plaintext timed text streams to a ciphertext ASDCP file
1231 write_timed_text_file(CommandOptions& Options)
1233 AESEncContext* Context = 0;
1234 HMACContext* HMAC = 0;
1235 TimedText::DCSubtitleParser Parser;
1236 TimedText::MXFWriter Writer;
1237 TimedText::FrameBuffer FrameBuffer;
1238 TimedText::TimedTextDescriptor TDesc;
1239 byte_t IV_buf[CBC_BLOCK_SIZE];
1240 Kumu::FortunaRNG RNG;
1242 // set up essence parser
1243 Result_t result = Parser.OpenRead(Options.filenames.front());
1245 // set up MXF writer
1246 if ( ASDCP_SUCCESS(result) )
1248 Parser.FillTimedTextDescriptor(TDesc);
1249 FrameBuffer.Capacity(Options.fb_size);
1251 if ( Options.verbose_flag )
1253 fputs("D-Cinema Timed-Text Descriptor:\n", stderr);
1254 TimedText::DescriptorDump(TDesc);
1258 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1260 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1261 if ( Options.asset_id_flag )
1262 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1264 Kumu::GenRandomUUID(Info.AssetUUID);
1266 // 428-7 IN 429-5 always uses SMPTE labels
1267 Info.LabelSetType = LS_MXF_SMPTE;
1268 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1270 // configure encryption
1271 if( Options.key_flag )
1273 Kumu::GenRandomUUID(Info.ContextID);
1274 Info.EncryptedEssence = true;
1276 if ( Options.key_id_flag )
1278 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1282 create_random_uuid(Info.CryptographicKeyID);
1285 Context = new AESEncContext;
1286 result = Context->InitKey(Options.key_value);
1288 if ( ASDCP_SUCCESS(result) )
1289 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1291 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1293 Info.UsesHMAC = true;
1294 HMAC = new HMACContext;
1295 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1299 if ( ASDCP_SUCCESS(result) )
1300 result = Writer.OpenWrite(Options.out_file, Info, TDesc);
1303 if ( ASDCP_FAILURE(result) )
1307 TimedText::ResourceList_t::const_iterator ri;
1309 result = Parser.ReadTimedTextResource(XMLDoc);
1311 if ( ASDCP_SUCCESS(result) )
1312 result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
1314 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
1316 result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
1318 if ( ASDCP_SUCCESS(result) )
1320 if ( Options.verbose_flag )
1321 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1323 if ( ! Options.no_write_flag )
1325 result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
1327 // The Writer class will forward the last block of ciphertext
1328 // to the encryption context for use as the IV for the next
1329 // frame. If you want to use non-sequitur IV values, un-comment
1330 // the following line of code.
1331 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1332 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1336 if ( result == RESULT_ENDOFFILE )
1340 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1341 result = Writer.Finalize();
1346 // Write one or more plaintext Dolby ATMOS bytestreams to a plaintext ASDCP file
1347 // Write one or more plaintext Dolby ATMOS bytestreams to a ciphertext ASDCP file
1350 write_dolby_atmos_file(CommandOptions& Options)
1352 AESEncContext* Context = 0;
1353 HMACContext* HMAC = 0;
1354 ATMOS::MXFWriter Writer;
1355 DCData::FrameBuffer FrameBuffer(Options.fb_size);
1356 ATMOS::AtmosDescriptor ADesc;
1357 DCData::SequenceParser Parser;
1358 byte_t IV_buf[CBC_BLOCK_SIZE];
1359 Kumu::FortunaRNG RNG;
1361 // set up essence parser
1362 Result_t result = Parser.OpenRead(Options.filenames.front());
1364 // set up MXF writer
1365 if ( ASDCP_SUCCESS(result) )
1367 Parser.FillDCDataDescriptor(ADesc);
1368 ADesc.EditRate = Options.PictureRate();
1369 // TODO: fill AtmosDescriptor
1370 ADesc.FirstFrame = Options.ffoa;
1371 ADesc.MaxChannelCount = Options.max_channel_count;
1372 ADesc.MaxObjectCount = Options.max_object_count;
1373 Kumu::GenRandomUUID(ADesc.AtmosID);
1374 ADesc.AtmosVersion = 1;
1375 if ( Options.verbose_flag )
1377 fprintf(stderr, "Dolby ATMOS Data\n");
1378 fputs("AtmosDescriptor:\n", stderr);
1379 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
1380 ATMOS::AtmosDescriptorDump(ADesc);
1384 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1386 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1387 if ( Options.asset_id_flag )
1388 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1390 Kumu::GenRandomUUID(Info.AssetUUID);
1392 Info.LabelSetType = LS_MXF_SMPTE;
1394 // configure encryption
1395 if( Options.key_flag )
1397 Kumu::GenRandomUUID(Info.ContextID);
1398 Info.EncryptedEssence = true;
1400 if ( Options.key_id_flag )
1402 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1406 create_random_uuid(Info.CryptographicKeyID);
1409 Context = new AESEncContext;
1410 result = Context->InitKey(Options.key_value);
1412 if ( ASDCP_SUCCESS(result) )
1413 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1415 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1417 Info.UsesHMAC = true;
1418 HMAC = new HMACContext;
1419 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1423 if ( ASDCP_SUCCESS(result) )
1424 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
1427 if ( ASDCP_SUCCESS(result) )
1429 ui32_t duration = 0;
1430 result = Parser.Reset();
1432 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1434 result = Parser.ReadFrame(FrameBuffer);
1436 if ( ASDCP_SUCCESS(result) )
1438 if ( Options.verbose_flag )
1439 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1441 if ( Options.encrypt_header_flag )
1442 FrameBuffer.PlaintextOffset(0);
1445 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1447 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1449 // The Writer class will forward the last block of ciphertext
1450 // to the encryption context for use as the IV for the next
1451 // frame. If you want to use non-sequitur IV values, un-comment
1452 // the following line of code.
1453 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1454 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1458 if ( result == RESULT_ENDOFFILE )
1462 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1463 result = Writer.Finalize();
1470 main(int argc, const char** argv)
1472 Result_t result = RESULT_OK;
1474 g_dict = &ASDCP::DefaultSMPTEDict();
1476 CommandOptions Options(argc, argv);
1478 if ( Options.version_flag )
1481 if ( Options.help_flag )
1484 if ( Options.show_ul_values_flag )
1486 if ( Options.use_smpte_labels )
1487 DefaultSMPTEDict().Dump(stdout);
1489 DefaultInteropDict().Dump(stdout);
1492 if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
1495 if ( Options.error_flag )
1497 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
1501 EssenceType_t EssenceType;
1502 result = ASDCP::RawEssenceType(Options.filenames.front(), EssenceType);
1504 if ( ASDCP_SUCCESS(result) )
1506 switch ( EssenceType )
1509 result = write_MPEG2_file(Options);
1513 if ( Options.stereo_image_flag )
1515 result = write_JP2K_S_file(Options);
1519 result = write_JP2K_file(Options);
1523 case ESS_PCM_24b_48k:
1524 case ESS_PCM_24b_96k:
1525 if ( Options.dolby_atmos_sync_flag )
1527 result = write_PCM_with_ATMOS_sync_file(Options);
1531 result = write_PCM_file(Options);
1535 case ESS_TIMED_TEXT:
1536 result = write_timed_text_file(Options);
1539 case ESS_DCDATA_DOLBY_ATMOS:
1540 result = write_dolby_atmos_file(Options);
1544 fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
1545 Options.filenames.front().c_str());
1550 if ( ASDCP_FAILURE(result) )
1552 fputs("Program stopped on error.\n", stderr);
1554 if ( result != RESULT_FAIL )
1556 fputs(result, stderr);
1557 fputc('\n', stderr);
1568 // end asdcp-wrap.cpp