Modified to enforce execution order of the predicates
[asdcplib.git] / src / phdr-wrap.cpp
1 /*
2 Copyright (c) 2011-2018, John Hurst
3
4 All rights reserved.
5
6 Redistribution and use in source and binary forms, with or without
7 modification, are permitted provided that the following conditions
8 are met:
9 1. Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 2. Redistributions in binary form must reproduce the above copyright
12    notice, this list of conditions and the following disclaimer in the
13    documentation and/or other materials provided with the distribution.
14 3. The name of the author may not be used to endorse or promote products
15    derived from this software without specific prior written permission.
16
17 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 */
28 /*! \file    phdr-wrap.cpp
29     \version $Id$       
30     \brief   prototype wrapping for HDR images in AS-02
31
32   This program wraps IMF essence (P-HDR picture) in to an AS-02 MXF file.
33 */
34
35 #include <KM_fileio.h>
36 #include <KM_prng.h>
37 #include <AS_02_PHDR.h>
38
39 using namespace ASDCP;
40
41 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
42 const ASDCP::Dictionary *g_dict = 0;
43
44
45 const char*
46 RationalToString(const ASDCP::Rational& r, char* buf, const ui32_t& len)
47 {
48   snprintf(buf, len, "%d/%d", r.Numerator, r.Denominator);
49   return buf;
50 }
51
52
53
54 //------------------------------------------------------------------------------------------
55 //
56 // command line option parser class
57
58 static const char* PROGRAM_NAME = "as-02-wrap";  // program name for messages
59
60 // local program identification info written to file headers
61 class MyInfo : public WriterInfo
62 {
63 public:
64   MyInfo()
65   {
66       static byte_t default_ProductUUID_Data[UUIDlen] =
67       { 0xef, 0xe4, 0x59, 0xab, 0xbe, 0x0f, 0x4c, 0x7d,
68         0xb3, 0xa2, 0xb8, 0x96, 0x79, 0xe2, 0x3e, 0x8e };
69       
70       memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
71       CompanyName = "WidgetCo";
72       ProductName = "phdr-wrap";
73       ProductVersion = ASDCP::Version();
74   }
75 } s_MyInfo;
76
77
78
79 // Increment the iterator, test for an additional non-option command line argument.
80 // Causes the caller to return if there are no remaining arguments or if the next
81 // argument begins with '-'.
82 #define TEST_EXTRA_ARG(i,c)                                             \
83   if ( ++i >= argc || argv[(i)][0] == '-' ) {                           \
84     fprintf(stderr, "Argument not found for option -%c.\n", (c));       \
85     return;                                                             \
86   }
87
88 //
89 static void
90 create_random_uuid(byte_t* uuidbuf)
91 {
92   Kumu::UUID tmp_id;
93   GenRandomValue(tmp_id);
94   memcpy(uuidbuf, tmp_id.Value(), tmp_id.Size());
95 }
96
97 //
98 void
99 banner(FILE* stream = stdout)
100 {
101   fprintf(stream, "\n\
102 %s (asdcplib %s)\n\n\
103 Copyright (c) 2011-2018, John Hurst\n\n\
104 asdcplib may be copied only under the terms of the license found at\n\
105 the top of every file in the asdcplib distribution kit.\n\n\
106 Specify the -h (help) option for further information about %s\n\n",
107           PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
108 }
109
110 //
111 void
112 usage(FILE* stream = stdout)
113 {
114   fprintf(stream, "\
115 USAGE: %s [-h|-help] [-V]\n\
116 \n\
117        %s [-a <uuid>] [-A <w>/<h>] [-b <buffer-size>] [-C <UL>] [-d <duration>]\n\
118             [-D <depth>] [-e|-E] [-i] [-j <key-id-string>] [-k <key-string>]\n\
119             [-M] [-m <expr>] [-p <ul>] [-r <n>/<d>] [-R] [-s <seconds>]\n\
120             [-t <min>] [-T <max>] [-u] [-v] [-W] [-x <int>] [-X <int>] [-Y]\n\
121             [-z|-Z] <input-file>+ <output-file>\n\n",
122           PROGRAM_NAME, PROGRAM_NAME);
123
124   fprintf(stream, "\
125 Options:\n\
126   -h | -help        - Show help\n\
127   -V                - Show version information\n\
128   -a <uuid>         - Specify the Asset ID of the file\n\
129   -A <w>/<h>        - Set aspect ratio for image (default 4/3)\n\
130   -b <buffer-size>  - Specify size in bytes of picture frame buffer\n\
131                       Defaults to 4,194,304 (4MB)\n\
132   -C <ul>           - Set ChannelAssignment UL value\n\
133   -d <duration>     - Number of frames to process, default all\n\
134   -D <depth>        - Component depth for YCbCr images (default: 10)\n\
135   -e                - Encrypt JP2K headers (default)\n\
136   -E                - Do not encrypt JP2K headers\n\
137   -F (0|1)          - Set field dominance for interlaced image (default: 0)\n\
138   -i                - Indicates input essence is interlaced fields (forces -Y)\n\
139   -j <key-id-str>   - Write key ID instead of creating a random value\n\
140   -k <key-string>   - Use key for ciphertext operations\n\
141   -M                - Do not create HMAC values when writing\n\
142   -m <filename>     - Filename of master metadata instance (the contents of\n\
143                         which will be placed in the MXF wrapper)\n\
144   -p <ul>           - Set broadcast profile\n\
145   -r <n>/<d>        - Edit Rate of the output file.  24/1 is the default\n\
146   -R                - Indicates RGB image essence (default)\n\
147   -s <seconds>      - Duration of a frame-wrapped partition (default 60)\n\
148   -t <min>          - Set RGB component minimum code value (default: 0)\n\
149   -T <max>          - Set RGB component maximum code value (default: 1023)\n\
150   -u                - Print UL catalog to stderr\n\
151   -v                - Verbose, prints informative messages to stderr\n\
152   -W                - Read input file only, do not write source file\n\
153   -x <int>          - Horizontal subsampling degree (default: 2)\n\
154   -X <int>          - Vertical subsampling degree (default: 2)\n\
155   -Y                - Indicates YCbCr image essence (default: RGB)\n\
156   -z                - Fail if j2c inputs have unequal parameters (default)\n\
157   -Z                - Ignore unequal parameters in j2c inputs\n\
158 \n\
159   NOTES: o There is no option grouping, all options must be distinct arguments.\n\
160          o All option arguments must be separated from the option by whitespace.\n\n");
161 }
162
163 //
164 //
165 class CommandOptions
166 {
167   CommandOptions();
168
169 public:
170   bool   error_flag;     // true if the given options are in error or not complete
171   bool   key_flag;       // true if an encryption key was given
172   bool   asset_id_flag;  // true if an asset ID was given
173   bool   encrypt_header_flag; // true if j2c headers are to be encrypted
174   bool   write_hmac;     // true if HMAC values are to be generated and written
175   bool   verbose_flag;   // true if the verbose option was selected
176   ui32_t fb_dump_size;   // number of bytes of frame buffer to dump
177   bool   no_write_flag;  // true if no output files are to be written
178   bool   version_flag;   // true if the version display option was selected
179   bool   help_flag;      // true if the help display option was selected
180   ui32_t duration;       // number of frames to be processed
181   bool   j2c_pedantic;   // passed to JP2K::SequenceParser::OpenRead
182   bool use_cdci_descriptor; // 
183   Rational edit_rate;    // edit rate of JP2K sequence
184   ui32_t fb_size;        // size of picture frame buffer
185   byte_t key_value[KeyLen];  // value of given encryption key (when key_flag is true)
186   bool   key_id_flag;    // true if a key ID was given
187   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
188   byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
189   std::string out_file; //
190   bool show_ul_values_flag;    /// if true, dump the UL table before going tp work.
191   Kumu::PathList_t filenames;  // list of filenames to be processed
192
193   UL picture_coding;
194   ui32_t rgba_MaxRef;
195   ui32_t rgba_MinRef;
196
197   ui32_t horizontal_subsampling;
198   ui32_t vertical_subsampling;
199   ui32_t component_depth;
200   ui8_t frame_layout;
201   ASDCP::Rational aspect_ratio;
202   ui8_t field_dominance;
203   ui32_t mxf_header_size;
204
205   //new attributes for AS-02 support 
206   AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip
207   ui32_t partition_space; //Shim parameter partition_spacing
208
209   std::string PHDR_master_metadata;
210   std::string global_metadata_filename;
211
212   //
213   CommandOptions(int argc, const char** argv) :
214     error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
215     encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0),
216     no_write_flag(false), version_flag(false), help_flag(false),
217     duration(0xffffffff), j2c_pedantic(true), use_cdci_descriptor(false), edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE),
218     show_ul_values_flag(false), index_strategy(AS_02::IS_FOLLOW), partition_space(60),
219     rgba_MaxRef(1023), rgba_MinRef(0),
220     horizontal_subsampling(2), vertical_subsampling(2), component_depth(10),
221     frame_layout(0), aspect_ratio(ASDCP::Rational(4,3)), field_dominance(0),
222     mxf_header_size(16384)
223   {
224     memset(key_value, 0, KeyLen);
225     memset(key_id_value, 0, UUIDlen);
226
227     for ( int i = 1; i < argc; i++ )
228       {
229
230         if ( (strcmp( argv[i], "-help") == 0) )
231           {
232             help_flag = true;
233             continue;
234           }
235          
236         if ( argv[i][0] == '-'
237              && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
238              && argv[i][2] == 0 )
239           {
240             switch ( argv[i][1] )
241               {
242               case 'A':
243                 TEST_EXTRA_ARG(i, 'A');
244                 if ( ! DecodeRational(argv[i], aspect_ratio) )
245                   {
246                     fprintf(stderr, "Error decoding aspect ratio value: %s\n", argv[i]);
247                     return;
248                   }
249                 break;
250
251               case 'a':
252                 asset_id_flag = true;
253                 TEST_EXTRA_ARG(i, 'a');
254                 {
255                   ui32_t length;
256                   Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
257
258                   if ( length != UUIDlen )
259                     {
260                       fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
261                       return;
262                     }
263                 }
264                 break;
265
266               case 'b':
267                 TEST_EXTRA_ARG(i, 'b');
268                 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
269
270                 if ( verbose_flag )
271                   fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
272
273                 break;
274
275               case 'D':
276                 TEST_EXTRA_ARG(i, 'D');
277                 component_depth = Kumu::xabs(strtol(argv[i], 0, 10));
278                 break;
279
280               case 'd':
281                 TEST_EXTRA_ARG(i, 'd');
282                 duration = Kumu::xabs(strtol(argv[i], 0, 10));
283                 break;
284
285               case 'E': encrypt_header_flag = false; break;
286               case 'e': encrypt_header_flag = true; break;
287
288               case 'F':
289                 TEST_EXTRA_ARG(i, 'F');
290                 field_dominance = Kumu::xabs(strtol(argv[i], 0, 10));
291                 if ( field_dominance > 1 )
292                   {
293                     fprintf(stderr, "Field dominance value must be \"0\" or \"1\"\n");
294                     return;
295                   }
296                 break;
297
298               case 'g':
299                 TEST_EXTRA_ARG(i, 'g');
300                 global_metadata_filename = argv[i];
301                 break;
302
303               case 'h': help_flag = true; break;
304
305               case 'i':
306                 frame_layout = 1;
307                 use_cdci_descriptor = true;
308                 break;
309
310               case 'j':
311                 key_id_flag = true;
312                 TEST_EXTRA_ARG(i, 'j');
313                 {
314                   ui32_t length;
315                   Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
316
317                   if ( length != UUIDlen )
318                     {
319                       fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
320                       return;
321                     }
322                 }
323                 break;
324
325               case 'k': key_flag = true;
326                 TEST_EXTRA_ARG(i, 'k');
327                 {
328                   ui32_t length;
329                   Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
330
331                   if ( length != KeyLen )
332                     {
333                       fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
334                       return;
335                     }
336                 }
337                 break;
338
339               case 'M': write_hmac = false; break;
340
341               case 'm':
342                 TEST_EXTRA_ARG(i, 'm');
343                 if ( KM_FAILURE(Kumu::ReadFileIntoString(argv[i], PHDR_master_metadata) ) )
344                   {
345                     fprintf(stderr, "Unable to read metadata file %s\n", argv[i]);
346                     return;
347                   }
348                 break;
349
350               case 'p':
351                 TEST_EXTRA_ARG(i, 'p');
352                 if ( ! picture_coding.DecodeHex(argv[i]) )
353                   {
354                     fprintf(stderr, "Error decoding PictureEssenceCoding UL value: %s\n", argv[i]);
355                     return;
356                   }
357                 break;
358
359               case 'r':
360                 TEST_EXTRA_ARG(i, 'r');
361                 if ( ! DecodeRational(argv[i], edit_rate) )
362                   {
363                     fprintf(stderr, "Error decoding edit rate value: %s\n", argv[i]);
364                     return;
365                   }
366
367                 break;
368
369               case 'R':
370                 use_cdci_descriptor = false;
371                 break;
372
373               case 's':
374                 TEST_EXTRA_ARG(i, 's');
375                 partition_space = Kumu::xabs(strtol(argv[i], 0, 10));
376                 break;
377
378               case 't':
379                 TEST_EXTRA_ARG(i, 't');
380                 rgba_MinRef = Kumu::xabs(strtol(argv[i], 0, 10));
381                 break;
382
383               case 'T':
384                 TEST_EXTRA_ARG(i, 'T');
385                 rgba_MaxRef = Kumu::xabs(strtol(argv[i], 0, 10));
386                 break;
387
388               case 'u': show_ul_values_flag = true; break;
389               case 'V': version_flag = true; break;
390               case 'v': verbose_flag = true; break;
391               case 'W': no_write_flag = true; break;
392
393               case 'x':
394                 TEST_EXTRA_ARG(i, 'x');
395                 horizontal_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
396                 break;
397
398               case 'X':
399                 TEST_EXTRA_ARG(i, 'X');
400                 vertical_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
401                 break;
402
403               case 'Y':
404                 use_cdci_descriptor = true;
405                 break;
406
407               case 'Z': j2c_pedantic = false; break;
408               case 'z': j2c_pedantic = true; break;
409
410               default:
411                 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
412                 return;
413               }
414           }
415         else
416           {
417
418             if ( argv[i][0] != '-' )
419               {
420                 filenames.push_back(argv[i]);
421               }
422             else
423               {
424                 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
425                 return;
426               }
427           }
428       }
429
430     if ( help_flag || version_flag )
431       return;
432     
433     if ( filenames.size() < 2 )
434       {
435         fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
436         return;
437       }
438
439     out_file = filenames.back();
440     filenames.pop_back();
441
442     if ( ! picture_coding.HasValue() )
443       {
444         picture_coding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1));
445       }
446
447     error_flag = false;
448   }
449 };
450
451
452 //------------------------------------------------------------------------------------------
453 // JPEG 2000 essence
454
455 namespace ASDCP {
456   Result_t JP2K_PDesc_to_MD(const ASDCP::JP2K::PictureDescriptor& PDesc,
457                             const ASDCP::Dictionary& dict,
458                             ASDCP::MXF::GenericPictureEssenceDescriptor& GenericPictureEssenceDescriptor,
459                             ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
460 }
461
462 // Write one or more plaintext JPEG 2000 codestreams to a plaintext AS-02 file
463 // Write one or more plaintext JPEG 2000 codestreams to a ciphertext AS-02 file
464 //
465 Result_t
466 write_JP2K_file(CommandOptions& Options)
467 {
468   AS_02::PHDR::MXFWriter  Writer;
469   AS_02::PHDR::FrameBuffer FrameBuffer(Options.fb_size);
470   AS_02::PHDR::SequenceParser Parser;
471
472   AESEncContext* Context = 0;
473   HMACContext* HMAC = 0;
474   byte_t IV_buf[CBC_BLOCK_SIZE];
475   Kumu::FortunaRNG RNG;
476
477   ASDCP::MXF::FileDescriptor *essence_descriptor = 0;
478   ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors;
479
480   // set up essence parser
481   Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
482
483   // set up MXF writer
484   if ( ASDCP_SUCCESS(result) )
485     {
486       ASDCP::JP2K::PictureDescriptor PDesc;
487       Parser.FillPictureDescriptor(PDesc);
488       PDesc.EditRate = Options.edit_rate;
489
490       if ( Options.verbose_flag )
491         {
492           fprintf(stderr, "JPEG 2000 P-HDR pictures\n");
493           fputs("PictureDescriptor:\n", stderr);
494           fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
495           JP2K::PictureDescriptorDump(PDesc);
496         }
497
498       if ( Options.use_cdci_descriptor )
499         {
500           ASDCP::MXF::CDCIEssenceDescriptor* tmp_dscr = new ASDCP::MXF::CDCIEssenceDescriptor(g_dict);
501           essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict));
502           
503           result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict,
504                                            *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr),
505                                            *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back()));
506
507           if ( ASDCP_SUCCESS(result) )
508             {
509               tmp_dscr->PictureEssenceCoding = Options.picture_coding;
510               tmp_dscr->HorizontalSubsampling = Options.horizontal_subsampling;
511               tmp_dscr->VerticalSubsampling = Options.vertical_subsampling;
512               tmp_dscr->ComponentDepth = Options.component_depth;
513               tmp_dscr->FrameLayout = Options.frame_layout;
514               tmp_dscr->AspectRatio = Options.aspect_ratio;
515               tmp_dscr->FieldDominance = Options.field_dominance;
516               essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
517             }
518         }
519       else
520         { // use RGB
521           ASDCP::MXF::RGBAEssenceDescriptor* tmp_dscr = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict);
522           essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict));
523           
524           result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict,
525                                            *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr),
526                                            *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back()));
527
528           if ( ASDCP_SUCCESS(result) )
529             {
530               tmp_dscr->PictureEssenceCoding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1));
531               tmp_dscr->ComponentMaxRef = Options.rgba_MaxRef;
532               tmp_dscr->ComponentMinRef = Options.rgba_MinRef;
533               essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
534             }
535         }
536     }
537
538   if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
539     {
540       WriterInfo Info = s_MyInfo;  // fill in your favorite identifiers here
541       Info.LabelSetType = LS_MXF_SMPTE;
542
543       if ( Options.asset_id_flag )
544         memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
545       else
546         Kumu::GenRandomUUID(Info.AssetUUID);
547
548       // configure encryption
549       if( Options.key_flag )
550         {
551           Kumu::GenRandomUUID(Info.ContextID);
552           Info.EncryptedEssence = true;
553
554           if ( Options.key_id_flag )
555             memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
556           else
557             RNG.FillRandom(Info.CryptographicKeyID, UUIDlen);
558
559           Context = new AESEncContext;
560           result = Context->InitKey(Options.key_value);
561
562           if ( ASDCP_SUCCESS(result) )
563             result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
564
565           if ( ASDCP_SUCCESS(result) && Options.write_hmac )
566             {
567               Info.UsesHMAC = true;
568               HMAC = new HMACContext;
569               result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
570             }
571         }
572
573       if ( ASDCP_SUCCESS(result) )
574         {
575           result = Writer.OpenWrite(Options.out_file, Info, essence_descriptor, essence_sub_descriptors,
576                                     Options.edit_rate, Options.mxf_header_size, Options.index_strategy, Options.partition_space);
577         }
578     }
579
580   if ( ASDCP_SUCCESS(result) )
581     {
582       ui32_t duration = 0;
583       result = Parser.Reset();
584
585       while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
586         {
587           result = Parser.ReadFrame(FrameBuffer);
588           
589           if ( ASDCP_SUCCESS(result) )
590             {
591               if ( Options.verbose_flag )
592                 FrameBuffer.Dump(stderr, Options.fb_dump_size);
593               
594               if ( Options.encrypt_header_flag )
595                 FrameBuffer.PlaintextOffset(0);
596             }
597
598           if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
599             {
600               result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
601
602               // The Writer class will forward the last block of ciphertext
603               // to the encryption context for use as the IV for the next
604               // frame. If you want to use non-sequitur IV values, un-comment
605               // the following  line of code.
606               // if ( ASDCP_SUCCESS(result) && Options.key_flag )
607               //   Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
608             }
609         }
610
611       if ( result == RESULT_ENDOFFILE )
612         result = RESULT_OK;
613     }
614
615   if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
616     result = Writer.Finalize(Options.PHDR_master_metadata);
617
618   return result;
619 }
620
621
622 //
623 int
624 main(int argc, const char** argv)
625 {
626   Result_t result = RESULT_OK;
627   char     str_buf[64];
628   g_dict = &ASDCP::DefaultSMPTEDict();
629   assert(g_dict);
630
631   CommandOptions Options(argc, argv);
632
633   if ( Options.version_flag )
634     banner();
635
636   if ( Options.help_flag )
637     usage();
638
639   if ( Options.show_ul_values_flag )
640     {
641       g_dict->Dump(stdout);
642     }
643
644   if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
645     return 0;
646
647   if ( Options.error_flag )
648     {
649       fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
650       return 3;
651     }
652
653   EssenceType_t EssenceType;
654   result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType);
655
656   if ( ASDCP_SUCCESS(result) )
657     {
658       switch ( EssenceType )
659         {
660         case ESS_JPEG_2000:
661           result = write_JP2K_file(Options);
662           break;
663
664         default:
665           fprintf(stderr, "%s: Unknown file type, not P-HDR-compatible essence.\n",
666                   Options.filenames.front().c_str());
667           return 5;
668         }
669     }
670
671   if ( ASDCP_FAILURE(result) )
672     {
673       fputs("Program stopped on error.\n", stderr);
674
675       if ( result != RESULT_FAIL )
676         {
677           fputs(result, stderr);
678           fputc('\n', stderr);
679         }
680
681       return 1;
682     }
683
684   return 0;
685 }
686
687
688 //
689 // end phdr-wrap.cpp
690 //