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 banner(FILE* stream = stdout)
106 %s (asdcplib %s)\n\n\
107 Copyright (c) 2003-2014 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 Note: The symbol '-' may be used for an unlabeled\n\
143 channel, but not within a soundfield.\n\
144 -a <UUID> - Specify the Asset ID of the file\n\
145 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
146 Defaults to 4,194,304 (4MB)\n\
147 -d <duration> - Number of frames to process, default all\n\
148 -f <start-frame> - Starting frame number, default 0\n\
149 -l <label> - Use given channel format label when writing MXF sound\n\
150 files. SMPTE 429-2 labels: '5.1', '6.1', '7.1',\n\
152 Default is no label (valid for Interop only).\n\
153 -L - Write SMPTE UL values instead of MXF Interop\n\
154 -P <UL> - Set PictureEssenceCoding UL value in a JP2K file\n\
155 -p <rate> - fps of picture when wrapping PCM or JP2K:\n\
156 Use one of [23|24|25|30|48|50|60], 24 is default\n\
157 -s - Insert a Dolby Atmos synchronization channel when\n\
158 wrapping PCM. This implies a -L option(SMPTE ULs) and \n\
159 will overide -C and -l options with Configuration 4 \n\
160 Channel Assigment and no format label respectively. \n\
161 -v - Verbose, prints informative messages to stderr\n\
162 -W - Read input file only, do not write source file\n\
163 -z - Fail if j2c inputs have unequal parameters (default)\n\
164 -Z - Ignore unequal parameters in j2c inputs\n\
166 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
167 o All option arguments must be separated from the option by whitespace.\n\
168 o An argument of \"23\" to the -p option will be interpreted\n\
169 as 24000/1001 fps.\n\
175 decode_channel_fmt(const std::string& label_name)
177 if ( label_name == "5.1" )
178 return PCM::CF_CFG_1;
180 else if ( label_name == "6.1" )
181 return PCM::CF_CFG_2;
183 else if ( label_name == "7.1" )
184 return PCM::CF_CFG_3;
186 else if ( label_name == "WTF" )
187 return PCM::CF_CFG_4;
189 else if ( label_name == "7.1DS" )
190 return PCM::CF_CFG_5;
192 fprintf(stderr, "Error decoding channel format string: %s\n", label_name.c_str());
193 fprintf(stderr, "Expecting '5.1', '6.1', '7.1', '7.1DS' or 'WTF'\n");
204 bool error_flag; // true if the given options are in error or not complete
205 bool key_flag; // true if an encryption key was given
206 bool asset_id_flag; // true if an asset ID was given
207 bool encrypt_header_flag; // true if mpeg headers are to be encrypted
208 bool write_hmac; // true if HMAC values are to be generated and written
209 bool verbose_flag; // true if the verbose option was selected
210 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
211 bool no_write_flag; // true if no output files are to be written
212 bool version_flag; // true if the version display option was selected
213 bool help_flag; // true if the help display option was selected
214 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
215 ui32_t start_frame; // frame number to begin processing
216 ui32_t duration; // number of frames to be processed
217 bool use_smpte_labels; // if true, SMPTE UL values will be written instead of MXF Interop values
218 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
219 ui32_t picture_rate; // fps of picture when wrapping PCM
220 ui32_t fb_size; // size of picture frame buffer
221 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
222 bool key_id_flag; // true if a key ID was given
223 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
224 byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
225 PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
226 std::string out_file; //
227 bool show_ul_values_flag; /// if true, dump the UL table before going to work.
228 Kumu::PathList_t filenames; // list of filenames to be processed
229 UL channel_assignment;
231 bool dolby_atmos_sync_flag; // if true, insert a Dolby Atmos Synchronization channel.
232 ui32_t ffoa; /// first frame of action for atmos wrapping
233 ui32_t max_channel_count; /// max channel count for atmos wrapping
234 ui32_t max_object_count; /// max object count for atmos wrapping
235 ASDCP::MXF::ASDCP_MCAConfigParser mca_config;
238 Rational PictureRate()
240 if ( picture_rate == 16 ) return EditRate_16;
241 if ( picture_rate == 18 ) return EditRate_18;
242 if ( picture_rate == 20 ) return EditRate_20;
243 if ( picture_rate == 22 ) return EditRate_22;
244 if ( picture_rate == 23 ) return EditRate_23_98;
245 if ( picture_rate == 24 ) return EditRate_24;
246 if ( picture_rate == 25 ) return EditRate_25;
247 if ( picture_rate == 30 ) return EditRate_30;
248 if ( picture_rate == 48 ) return EditRate_48;
249 if ( picture_rate == 50 ) return EditRate_50;
250 if ( picture_rate == 60 ) return EditRate_60;
251 if ( picture_rate == 96 ) return EditRate_96;
252 if ( picture_rate == 100 ) return EditRate_100;
253 if ( picture_rate == 120 ) return EditRate_120;
258 const char* szPictureRate()
260 if ( picture_rate == 16 ) return "16";
261 if ( picture_rate == 18 ) return "18.182";
262 if ( picture_rate == 20 ) return "20";
263 if ( picture_rate == 22 ) return "21.818";
264 if ( picture_rate == 23 ) return "23.976";
265 if ( picture_rate == 24 ) return "24";
266 if ( picture_rate == 25 ) return "25";
267 if ( picture_rate == 30 ) return "30";
268 if ( picture_rate == 48 ) return "48";
269 if ( picture_rate == 50 ) return "50";
270 if ( picture_rate == 60 ) return "60";
271 if ( picture_rate == 96 ) return "96";
272 if ( picture_rate == 100 ) return "100";
273 if ( picture_rate == 120 ) return "120";
278 CommandOptions(int argc, const char** argv) :
279 error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
280 encrypt_header_flag(true), write_hmac(true),
281 verbose_flag(false), fb_dump_size(0),
282 no_write_flag(false), version_flag(false), help_flag(false), stereo_image_flag(false),
284 duration(0xffffffff), use_smpte_labels(false), j2c_pedantic(true),
285 fb_size(FRAME_BUFFER_SIZE),
286 channel_fmt(PCM::CF_NONE),
287 ffoa(0), max_channel_count(10), max_object_count(118), // hard-coded sample atmos properties
288 dolby_atmos_sync_flag(false),
289 show_ul_values_flag(false),
292 memset(key_value, 0, KeyLen);
293 memset(key_id_value, 0, UUIDlen);
295 for ( int i = 1; i < argc; i++ )
298 if ( (strcmp( argv[i], "-help") == 0) )
304 if ( argv[i][0] == '-'
305 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
308 switch ( argv[i][1] )
310 case '3': stereo_image_flag = true; break;
313 asset_id_flag = true;
314 TEST_EXTRA_ARG(i, 'a');
317 Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
319 if ( length != UUIDlen )
321 fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
328 TEST_EXTRA_ARG(i, 'b');
329 fb_size = abs(atoi(argv[i]));
332 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
337 TEST_EXTRA_ARG(i, 'C');
338 if ( ! channel_assignment.DecodeHex(argv[i]) )
340 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
346 TEST_EXTRA_ARG(i, 'd');
347 duration = abs(atoi(argv[i]));
350 case 'E': encrypt_header_flag = false; break;
351 case 'e': encrypt_header_flag = true; break;
354 TEST_EXTRA_ARG(i, 'f');
355 start_frame = abs(atoi(argv[i]));
358 case 'h': help_flag = true; break;
360 case 'j': key_id_flag = true;
361 TEST_EXTRA_ARG(i, 'j');
364 Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
366 if ( length != UUIDlen )
368 fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
374 case 'k': key_flag = true;
375 TEST_EXTRA_ARG(i, 'k');
378 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
380 if ( length != KeyLen )
382 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
389 TEST_EXTRA_ARG(i, 'l');
390 channel_fmt = decode_channel_fmt(argv[i]);
393 case 'L': use_smpte_labels = true; break;
394 case 'M': write_hmac = false; break;
397 TEST_EXTRA_ARG(i, 'm');
398 if ( ! mca_config.DecodeString(argv[i]) )
405 TEST_EXTRA_ARG(i, 'P');
406 if ( ! picture_coding.DecodeHex(argv[i]) )
408 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
414 TEST_EXTRA_ARG(i, 'p');
415 picture_rate = abs(atoi(argv[i]));
418 case 's': dolby_atmos_sync_flag = true; break;
419 case 'u': show_ul_values_flag = true; break;
420 case 'V': version_flag = true; break;
421 case 'v': verbose_flag = true; break;
422 case 'W': no_write_flag = true; break;
423 case 'Z': j2c_pedantic = false; break;
424 case 'z': j2c_pedantic = true; break;
427 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
434 if ( argv[i][0] != '-' )
436 filenames.push_back(argv[i]);
440 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
446 if ( help_flag || version_flag )
449 if ( filenames.size() < 2 )
451 fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
455 out_file = filenames.back();
456 filenames.pop_back();
461 //------------------------------------------------------------------------------------------
464 // Write a plaintext MPEG2 Video Elementary Stream to a plaintext ASDCP file
465 // Write a plaintext MPEG2 Video Elementary Stream to a ciphertext ASDCP file
468 write_MPEG2_file(CommandOptions& Options)
470 AESEncContext* Context = 0;
471 HMACContext* HMAC = 0;
472 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
473 MPEG2::Parser Parser;
474 MPEG2::MXFWriter Writer;
475 MPEG2::VideoDescriptor VDesc;
476 byte_t IV_buf[CBC_BLOCK_SIZE];
477 Kumu::FortunaRNG RNG;
479 // set up essence parser
480 Result_t result = Parser.OpenRead(Options.filenames.front());
483 if ( ASDCP_SUCCESS(result) )
485 Parser.FillVideoDescriptor(VDesc);
487 if ( Options.verbose_flag )
489 fputs("MPEG-2 Pictures\n", stderr);
490 fputs("VideoDescriptor:\n", stderr);
491 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
492 MPEG2::VideoDescriptorDump(VDesc);
496 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
498 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
499 if ( Options.asset_id_flag )
500 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
502 Kumu::GenRandomUUID(Info.AssetUUID);
504 if ( Options.use_smpte_labels )
506 Info.LabelSetType = LS_MXF_SMPTE;
507 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
510 // configure encryption
511 if( Options.key_flag )
513 Kumu::GenRandomUUID(Info.ContextID);
514 Info.EncryptedEssence = true;
516 if ( Options.key_id_flag )
517 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
519 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
521 Context = new AESEncContext;
522 result = Context->InitKey(Options.key_value);
524 if ( ASDCP_SUCCESS(result) )
525 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
527 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
529 Info.UsesHMAC = true;
530 HMAC = new HMACContext;
531 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
535 if ( ASDCP_SUCCESS(result) )
536 result = Writer.OpenWrite(Options.out_file, Info, VDesc);
539 if ( ASDCP_SUCCESS(result) )
540 // loop through the frames
542 result = Parser.Reset();
545 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
547 result = Parser.ReadFrame(FrameBuffer);
549 if ( ASDCP_SUCCESS(result) )
551 if ( Options.verbose_flag )
552 FrameBuffer.Dump(stderr, Options.fb_dump_size);
554 if ( Options.encrypt_header_flag )
555 FrameBuffer.PlaintextOffset(0);
558 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
560 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
562 // The Writer class will forward the last block of ciphertext
563 // to the encryption context for use as the IV for the next
564 // frame. If you want to use non-sequitur IV values, un-comment
565 // the following line of code.
566 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
567 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
571 if ( result == RESULT_ENDOFFILE )
575 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
576 result = Writer.Finalize();
582 //------------------------------------------------------------------------------------------
584 // return false if an error is discovered
586 check_phfr_params(CommandOptions& Options, JP2K::PictureDescriptor& PDesc)
588 Rational rate = Options.PictureRate();
589 if ( rate != EditRate_96 && rate != EditRate_100 && rate != EditRate_120 )
592 if ( PDesc.StoredWidth > 2048 )
594 fprintf(stderr, "P-HFR files currently limited to 2K.\n");
598 if ( ! Options.use_smpte_labels )
600 fprintf(stderr, "P-HFR files must be written using SMPTE labels. Use option '-L'.\n");
604 // do not set the label if the user has already done so
605 if ( ! Options.picture_coding.HasValue() )
606 Options.picture_coding = UL(P_HFR_UL_2K);
611 //------------------------------------------------------------------------------------------
614 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a plaintext ASDCP file
615 // Write one or more plaintext JPEG 2000 stereoscopic codestream pairs to a ciphertext ASDCP file
618 write_JP2K_S_file(CommandOptions& Options)
620 AESEncContext* Context = 0;
621 HMACContext* HMAC = 0;
622 JP2K::MXFSWriter Writer;
623 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
624 JP2K::PictureDescriptor PDesc;
625 JP2K::SequenceParser ParserLeft, ParserRight;
626 byte_t IV_buf[CBC_BLOCK_SIZE];
627 Kumu::FortunaRNG RNG;
629 if ( Options.filenames.size() != 2 )
631 fprintf(stderr, "Two inputs are required for stereoscopic option.\n");
635 // set up essence parser
636 Result_t result = ParserLeft.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
638 if ( ASDCP_SUCCESS(result) )
640 Options.filenames.pop_front();
641 result = ParserRight.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
645 if ( ASDCP_SUCCESS(result) )
647 ParserLeft.FillPictureDescriptor(PDesc);
648 PDesc.EditRate = Options.PictureRate();
650 if ( Options.verbose_flag )
652 fputs("JPEG 2000 stereoscopic pictures\nPictureDescriptor:\n", stderr);
653 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
654 JP2K::PictureDescriptorDump(PDesc);
658 if ( ! check_phfr_params(Options, PDesc) )
661 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
663 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
664 if ( Options.asset_id_flag )
665 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
667 Kumu::GenRandomUUID(Info.AssetUUID);
669 if ( Options.use_smpte_labels )
671 Info.LabelSetType = LS_MXF_SMPTE;
672 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
675 // configure encryption
676 if( Options.key_flag )
678 Kumu::GenRandomUUID(Info.ContextID);
679 Info.EncryptedEssence = true;
681 if ( Options.key_id_flag )
682 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
684 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
686 Context = new AESEncContext;
687 result = Context->InitKey(Options.key_value);
689 if ( ASDCP_SUCCESS(result) )
690 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
692 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
694 Info.UsesHMAC = true;
695 HMAC = new HMACContext;
696 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
700 if ( ASDCP_SUCCESS(result) )
701 result = Writer.OpenWrite(Options.out_file, Info, PDesc);
703 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
705 MXF::RGBAEssenceDescriptor *descriptor = 0;
706 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
707 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
708 descriptor->PictureEssenceCoding = Options.picture_coding;
712 if ( ASDCP_SUCCESS(result) )
715 result = ParserLeft.Reset();
716 if ( ASDCP_SUCCESS(result) ) result = ParserRight.Reset();
718 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
720 result = ParserLeft.ReadFrame(FrameBuffer);
722 if ( ASDCP_SUCCESS(result) )
724 if ( Options.verbose_flag )
725 FrameBuffer.Dump(stderr, Options.fb_dump_size);
727 if ( Options.encrypt_header_flag )
728 FrameBuffer.PlaintextOffset(0);
731 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
732 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_LEFT, Context, HMAC);
734 if ( ASDCP_SUCCESS(result) )
735 result = ParserRight.ReadFrame(FrameBuffer);
737 if ( ASDCP_SUCCESS(result) )
739 if ( Options.verbose_flag )
740 FrameBuffer.Dump(stderr, Options.fb_dump_size);
742 if ( Options.encrypt_header_flag )
743 FrameBuffer.PlaintextOffset(0);
746 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
747 result = Writer.WriteFrame(FrameBuffer, JP2K::SP_RIGHT, Context, HMAC);
750 if ( result == RESULT_ENDOFFILE )
754 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
755 result = Writer.Finalize();
760 // Write one or more plaintext JPEG 2000 codestreams to a plaintext ASDCP file
761 // Write one or more plaintext JPEG 2000 codestreams to a ciphertext ASDCP file
764 write_JP2K_file(CommandOptions& Options)
766 AESEncContext* Context = 0;
767 HMACContext* HMAC = 0;
768 JP2K::MXFWriter Writer;
769 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
770 JP2K::PictureDescriptor PDesc;
771 JP2K::SequenceParser Parser;
772 byte_t IV_buf[CBC_BLOCK_SIZE];
773 Kumu::FortunaRNG RNG;
775 // set up essence parser
776 Result_t result = Parser.OpenRead(Options.filenames.front(), Options.j2c_pedantic);
779 if ( ASDCP_SUCCESS(result) )
781 Parser.FillPictureDescriptor(PDesc);
782 PDesc.EditRate = Options.PictureRate();
784 if ( Options.verbose_flag )
786 fprintf(stderr, "JPEG 2000 pictures\n");
787 fputs("PictureDescriptor:\n", stderr);
788 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
789 JP2K::PictureDescriptorDump(PDesc);
793 if ( ! check_phfr_params(Options, PDesc) )
796 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
798 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
799 if ( Options.asset_id_flag )
800 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
802 Kumu::GenRandomUUID(Info.AssetUUID);
804 if ( Options.use_smpte_labels )
806 Info.LabelSetType = LS_MXF_SMPTE;
807 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
810 // configure encryption
811 if( Options.key_flag )
813 Kumu::GenRandomUUID(Info.ContextID);
814 Info.EncryptedEssence = true;
816 if ( Options.key_id_flag )
817 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
819 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
821 Context = new AESEncContext;
822 result = Context->InitKey(Options.key_value);
824 if ( ASDCP_SUCCESS(result) )
825 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
827 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
829 Info.UsesHMAC = true;
830 HMAC = new HMACContext;
831 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
835 if ( ASDCP_SUCCESS(result) )
836 result = Writer.OpenWrite(Options.out_file, Info, PDesc);
838 if ( ASDCP_SUCCESS(result) && Options.picture_coding.HasValue() )
840 MXF::RGBAEssenceDescriptor *descriptor = 0;
841 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_RGBAEssenceDescriptor),
842 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
843 descriptor->PictureEssenceCoding = Options.picture_coding;
847 if ( ASDCP_SUCCESS(result) )
850 result = Parser.Reset();
852 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
854 result = Parser.ReadFrame(FrameBuffer);
856 if ( ASDCP_SUCCESS(result) )
858 if ( Options.verbose_flag )
859 FrameBuffer.Dump(stderr, Options.fb_dump_size);
861 if ( Options.encrypt_header_flag )
862 FrameBuffer.PlaintextOffset(0);
865 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
867 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
869 // The Writer class will forward the last block of ciphertext
870 // to the encryption context for use as the IV for the next
871 // frame. If you want to use non-sequitur IV values, un-comment
872 // the following line of code.
873 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
874 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
878 if ( result == RESULT_ENDOFFILE )
882 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
883 result = Writer.Finalize();
888 //------------------------------------------------------------------------------------------
892 // Write one or more plaintext PCM audio streams to a plaintext ASDCP file
893 // Write one or more plaintext PCM audio streams to a ciphertext ASDCP file
896 write_PCM_file(CommandOptions& Options)
898 AESEncContext* Context = 0;
899 HMACContext* HMAC = 0;
900 PCMParserList Parser;
901 PCM::MXFWriter Writer;
902 PCM::FrameBuffer FrameBuffer;
903 PCM::AudioDescriptor ADesc;
904 Rational PictureRate = Options.PictureRate();
905 byte_t IV_buf[CBC_BLOCK_SIZE];
906 Kumu::FortunaRNG RNG;
908 // set up essence parser
909 Result_t result = Parser.OpenRead(Options.filenames, PictureRate);
912 if ( ASDCP_SUCCESS(result) )
914 Parser.FillAudioDescriptor(ADesc);
916 ADesc.EditRate = PictureRate;
917 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
918 ADesc.ChannelFormat = Options.channel_fmt;
920 if ( Options.use_smpte_labels && ADesc.ChannelFormat == PCM::CF_NONE && Options.mca_config.empty() )
922 fprintf(stderr, "ATTENTION! Writing SMPTE audio without ChannelAssignment property (see options -C, -l and -m)\n");
925 if ( Options.verbose_flag )
927 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
928 ADesc.AudioSamplingRate.Quotient() / 1000.0,
929 Options.szPictureRate(),
930 PCM::CalcSamplesPerFrame(ADesc));
931 fputs("AudioDescriptor:\n", stderr);
932 PCM::AudioDescriptorDump(ADesc);
936 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
938 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
939 if ( Options.asset_id_flag )
940 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
942 Kumu::GenRandomUUID(Info.AssetUUID);
944 if ( Options.use_smpte_labels )
946 Info.LabelSetType = LS_MXF_SMPTE;
947 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
950 // configure encryption
951 if( Options.key_flag )
953 Kumu::GenRandomUUID(Info.ContextID);
954 Info.EncryptedEssence = true;
956 if ( Options.key_id_flag )
957 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
959 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
961 Context = new AESEncContext;
962 result = Context->InitKey(Options.key_value);
964 if ( ASDCP_SUCCESS(result) )
965 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
967 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
969 Info.UsesHMAC = true;
970 HMAC = new HMACContext;
971 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
975 if ( ASDCP_SUCCESS(result) )
976 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
978 if ( ASDCP_SUCCESS(result)
979 && ( Options.channel_assignment.HasValue()
980 || ! Options.mca_config.empty() ) )
982 MXF::WaveAudioDescriptor *essence_descriptor = 0;
983 Writer.OP1aHeader().GetMDObjectByType(g_dict->ul(MDD_WaveAudioDescriptor),
984 reinterpret_cast<MXF::InterchangeObject**>(&essence_descriptor));
985 assert(essence_descriptor);
987 if ( Options.mca_config.empty() )
989 essence_descriptor->ChannelAssignment = Options.channel_assignment;
993 if ( Options.mca_config.ChannelCount() != essence_descriptor->ChannelCount )
995 fprintf(stderr, "MCA label count (%d) differs from essence stream channel count (%d).\n",
996 Options.mca_config.ChannelCount(), essence_descriptor->ChannelCount);
1000 essence_descriptor->ChannelAssignment = g_dict->ul(MDD_DCAudioChannelCfg_MCA);
1002 // add descriptors to the essence_descriptor and header
1003 ASDCP::MXF::InterchangeObject_list_t::iterator i;
1004 for ( i = Options.mca_config.begin(); i != Options.mca_config.end(); ++i )
1006 if ( (*i)->GetUL() != UL(g_dict->ul(MDD_AudioChannelLabelSubDescriptor))
1007 && (*i)->GetUL() != UL(g_dict->ul(MDD_SoundfieldGroupLabelSubDescriptor))
1008 && (*i)->GetUL() != UL(g_dict->ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor)) )
1010 fprintf(stderr, "Essence sub-descriptor is not an MCALabelSubDescriptor.\n");
1014 Writer.OP1aHeader().AddChildObject(*i);
1015 essence_descriptor->SubDescriptors.push_back((*i)->InstanceUID);
1016 *i = 0; // parent will only free the ones we don't keep
1022 if ( ASDCP_SUCCESS(result) )
1024 result = Parser.Reset();
1025 ui32_t duration = 0;
1027 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1029 result = Parser.ReadFrame(FrameBuffer);
1031 if ( ASDCP_SUCCESS(result) )
1033 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1035 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1036 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1037 result = RESULT_ENDOFFILE;
1041 if ( Options.verbose_flag )
1042 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1044 if ( ! Options.no_write_flag )
1046 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1048 // The Writer class will forward the last block of ciphertext
1049 // to the encryption context for use as the IV for the next
1050 // frame. If you want to use non-sequitur IV values, un-comment
1051 // the following line of code.
1052 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1053 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1058 if ( result == RESULT_ENDOFFILE )
1062 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1063 result = Writer.Finalize();
1068 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a plaintext ASDCP file
1069 // Mix one or more plaintext PCM audio streams with a Dolby Atmos Synchronization channel and write them to a ciphertext ASDCP file
1072 write_PCM_with_ATMOS_sync_file(CommandOptions& Options)
1074 AESEncContext* Context = 0;
1075 HMACContext* HMAC = 0;
1076 PCM::MXFWriter Writer;
1077 PCM::FrameBuffer FrameBuffer;
1078 PCM::AudioDescriptor ADesc;
1079 Rational PictureRate = Options.PictureRate();
1080 byte_t IV_buf[CBC_BLOCK_SIZE];
1081 Kumu::FortunaRNG RNG;
1083 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1084 if ( Options.asset_id_flag )
1085 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1087 Kumu::GenRandomUUID(Info.AssetUUID);
1088 AtmosSyncChannelMixer Mixer(Info.AssetUUID);
1090 // set up essence parser
1091 Result_t result = Mixer.OpenRead(Options.filenames, PictureRate);
1093 // set up MXF writer
1094 if ( ASDCP_SUCCESS(result) )
1096 Mixer.FillAudioDescriptor(ADesc);
1098 ADesc.EditRate = PictureRate;
1099 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
1100 ADesc.ChannelFormat = PCM::CF_CFG_4;
1102 if ( Options.verbose_flag )
1104 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
1105 ADesc.AudioSamplingRate.Quotient() / 1000.0,
1106 Options.szPictureRate(),
1107 PCM::CalcSamplesPerFrame(ADesc));
1108 fputs("AudioDescriptor:\n", stderr);
1109 PCM::AudioDescriptorDump(ADesc);
1113 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1115 Info.LabelSetType = LS_MXF_SMPTE;
1116 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1118 // configure encryption
1119 if( Options.key_flag )
1121 Kumu::GenRandomUUID(Info.ContextID);
1122 Info.EncryptedEssence = true;
1124 if ( Options.key_id_flag )
1125 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1127 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1129 Context = new AESEncContext;
1130 result = Context->InitKey(Options.key_value);
1132 if ( ASDCP_SUCCESS(result) )
1133 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1135 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1137 Info.UsesHMAC = true;
1138 HMAC = new HMACContext;
1139 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1143 if ( ASDCP_SUCCESS(result) )
1144 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
1147 if ( ASDCP_SUCCESS(result) )
1149 result = Mixer.Reset();
1150 ui32_t duration = 0;
1152 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1154 result = Mixer.ReadFrame(FrameBuffer);
1156 if ( ASDCP_SUCCESS(result) )
1158 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
1160 fprintf(stderr, "WARNING: Last frame read was short, PCM input is possibly not frame aligned.\n");
1161 fprintf(stderr, "Expecting %u bytes, got %u.\n", FrameBuffer.Capacity(), FrameBuffer.Size());
1162 result = RESULT_ENDOFFILE;
1166 if ( Options.verbose_flag )
1167 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1169 if ( ! Options.no_write_flag )
1171 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1173 // The Writer class will forward the last block of ciphertext
1174 // to the encryption context for use as the IV for the next
1175 // frame. If you want to use non-sequitur IV values, un-comment
1176 // the following line of code.
1177 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1178 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1183 if ( result == RESULT_ENDOFFILE )
1187 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1188 result = Writer.Finalize();
1194 //------------------------------------------------------------------------------------------
1195 // TimedText essence
1198 // Write one or more plaintext timed text streams to a plaintext ASDCP file
1199 // Write one or more plaintext timed text streams to a ciphertext ASDCP file
1202 write_timed_text_file(CommandOptions& Options)
1204 AESEncContext* Context = 0;
1205 HMACContext* HMAC = 0;
1206 TimedText::DCSubtitleParser Parser;
1207 TimedText::MXFWriter Writer;
1208 TimedText::FrameBuffer FrameBuffer;
1209 TimedText::TimedTextDescriptor TDesc;
1210 byte_t IV_buf[CBC_BLOCK_SIZE];
1211 Kumu::FortunaRNG RNG;
1213 // set up essence parser
1214 Result_t result = Parser.OpenRead(Options.filenames.front());
1216 // set up MXF writer
1217 if ( ASDCP_SUCCESS(result) )
1219 Parser.FillTimedTextDescriptor(TDesc);
1220 FrameBuffer.Capacity(Options.fb_size);
1222 if ( Options.verbose_flag )
1224 fputs("D-Cinema Timed-Text Descriptor:\n", stderr);
1225 TimedText::DescriptorDump(TDesc);
1229 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1231 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1232 if ( Options.asset_id_flag )
1233 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1235 Kumu::GenRandomUUID(Info.AssetUUID);
1237 // 428-7 IN 429-5 always uses SMPTE labels
1238 Info.LabelSetType = LS_MXF_SMPTE;
1239 fprintf(stderr, "ATTENTION! Writing SMPTE Universal Labels\n");
1241 // configure encryption
1242 if( Options.key_flag )
1244 Kumu::GenRandomUUID(Info.ContextID);
1245 Info.EncryptedEssence = true;
1247 if ( Options.key_id_flag )
1248 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1250 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1252 Context = new AESEncContext;
1253 result = Context->InitKey(Options.key_value);
1255 if ( ASDCP_SUCCESS(result) )
1256 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1258 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1260 Info.UsesHMAC = true;
1261 HMAC = new HMACContext;
1262 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1266 if ( ASDCP_SUCCESS(result) )
1267 result = Writer.OpenWrite(Options.out_file, Info, TDesc);
1270 if ( ASDCP_FAILURE(result) )
1274 TimedText::ResourceList_t::const_iterator ri;
1276 result = Parser.ReadTimedTextResource(XMLDoc);
1278 if ( ASDCP_SUCCESS(result) )
1279 result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
1281 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
1283 result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
1285 if ( ASDCP_SUCCESS(result) )
1287 if ( Options.verbose_flag )
1288 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1290 if ( ! Options.no_write_flag )
1292 result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
1294 // The Writer class will forward the last block of ciphertext
1295 // to the encryption context for use as the IV for the next
1296 // frame. If you want to use non-sequitur IV values, un-comment
1297 // the following line of code.
1298 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1299 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1303 if ( result == RESULT_ENDOFFILE )
1307 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1308 result = Writer.Finalize();
1313 // Write one or more plaintext Dolby ATMOS bytestreams to a plaintext ASDCP file
1314 // Write one or more plaintext Dolby ATMOS bytestreams to a ciphertext ASDCP file
1317 write_dolby_atmos_file(CommandOptions& Options)
1319 AESEncContext* Context = 0;
1320 HMACContext* HMAC = 0;
1321 ATMOS::MXFWriter Writer;
1322 DCData::FrameBuffer FrameBuffer(Options.fb_size);
1323 ATMOS::AtmosDescriptor ADesc;
1324 DCData::SequenceParser Parser;
1325 byte_t IV_buf[CBC_BLOCK_SIZE];
1326 Kumu::FortunaRNG RNG;
1328 // set up essence parser
1329 Result_t result = Parser.OpenRead(Options.filenames.front());
1331 // set up MXF writer
1332 if ( ASDCP_SUCCESS(result) )
1334 Parser.FillDCDataDescriptor(ADesc);
1335 ADesc.EditRate = Options.PictureRate();
1336 // TODO: fill AtmosDescriptor
1337 ADesc.FirstFrame = Options.ffoa;
1338 ADesc.MaxChannelCount = Options.max_channel_count;
1339 ADesc.MaxObjectCount = Options.max_object_count;
1340 Kumu::GenRandomUUID(ADesc.AtmosID);
1341 ADesc.AtmosVersion = 1;
1342 if ( Options.verbose_flag )
1344 fprintf(stderr, "Dolby ATMOS Data\n");
1345 fputs("AtmosDescriptor:\n", stderr);
1346 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
1347 ATMOS::AtmosDescriptorDump(ADesc);
1351 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1353 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1354 if ( Options.asset_id_flag )
1355 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1357 Kumu::GenRandomUUID(Info.AssetUUID);
1359 Info.LabelSetType = LS_MXF_SMPTE;
1361 // configure encryption
1362 if( Options.key_flag )
1364 Kumu::GenRandomUUID(Info.ContextID);
1365 Info.EncryptedEssence = true;
1367 if ( Options.key_id_flag )
1368 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1370 RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
1372 Context = new AESEncContext;
1373 result = Context->InitKey(Options.key_value);
1375 if ( ASDCP_SUCCESS(result) )
1376 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1378 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1380 Info.UsesHMAC = true;
1381 HMAC = new HMACContext;
1382 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1386 if ( ASDCP_SUCCESS(result) )
1387 result = Writer.OpenWrite(Options.out_file, Info, ADesc);
1390 if ( ASDCP_SUCCESS(result) )
1392 ui32_t duration = 0;
1393 result = Parser.Reset();
1395 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1397 result = Parser.ReadFrame(FrameBuffer);
1399 if ( ASDCP_SUCCESS(result) )
1401 if ( Options.verbose_flag )
1402 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1404 if ( Options.encrypt_header_flag )
1405 FrameBuffer.PlaintextOffset(0);
1408 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1410 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1412 // The Writer class will forward the last block of ciphertext
1413 // to the encryption context for use as the IV for the next
1414 // frame. If you want to use non-sequitur IV values, un-comment
1415 // the following line of code.
1416 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1417 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1421 if ( result == RESULT_ENDOFFILE )
1425 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1426 result = Writer.Finalize();
1433 main(int argc, const char** argv)
1435 Result_t result = RESULT_OK;
1437 g_dict = &ASDCP::DefaultSMPTEDict();
1439 CommandOptions Options(argc, argv);
1441 if ( Options.version_flag )
1444 if ( Options.help_flag )
1447 if ( Options.show_ul_values_flag )
1449 if ( Options.use_smpte_labels )
1450 DefaultSMPTEDict().Dump(stdout);
1452 DefaultInteropDict().Dump(stdout);
1455 if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
1458 if ( Options.error_flag )
1460 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
1464 EssenceType_t EssenceType;
1465 result = ASDCP::RawEssenceType(Options.filenames.front(), EssenceType);
1467 if ( ASDCP_SUCCESS(result) )
1469 switch ( EssenceType )
1472 result = write_MPEG2_file(Options);
1476 if ( Options.stereo_image_flag )
1478 result = write_JP2K_S_file(Options);
1482 result = write_JP2K_file(Options);
1486 case ESS_PCM_24b_48k:
1487 case ESS_PCM_24b_96k:
1488 if ( Options.dolby_atmos_sync_flag )
1490 result = write_PCM_with_ATMOS_sync_file(Options);
1494 result = write_PCM_file(Options);
1498 case ESS_TIMED_TEXT:
1499 result = write_timed_text_file(Options);
1502 case ESS_DCDATA_DOLBY_ATMOS:
1503 result = write_dolby_atmos_file(Options);
1507 fprintf(stderr, "%s: Unknown file type, not ASDCP-compatible essence.\n",
1508 Options.filenames.front().c_str());
1513 if ( ASDCP_FAILURE(result) )
1515 fputs("Program stopped on error.\n", stderr);
1517 if ( result != RESULT_FAIL )
1519 fputs(result, stderr);
1520 fputc('\n', stderr);
1531 // end asdcp-wrap.cpp