1104be06ad8fbf879d7a57d8b937c840cf3d4fde
[asdcplib.git] / src / as-02-unwrap.cpp
1 /*
2 Copyright (c) 2011-2016, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
3 John Hurst
4
5 All rights reserved.
6
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
9 are met:
10 1. Redistributions of source code must retain the above copyright
11    notice, this list of conditions and the following disclaimer.
12 2. Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 3. The name of the author may not be used to endorse or promote products
16    derived from this software without specific prior written permission.
17
18 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29 /*! \file    as-02-unwrap.cpp
30     \version $Id$       
31     \brief   AS-02 file manipulation utility
32
33   This program extracts picture and sound from AS-02 files.
34
35   For more information about AS-02, please refer to the header file AS_02.h
36   For more information about asdcplib, please refer to the header file AS_DCP.h
37 */
38
39 #include <KM_fileio.h>
40 #include <AS_02.h>
41 #include <WavFileWriter.h>
42
43 namespace ASDCP {
44   Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, ASDCP::PCM::AudioDescriptor& ADesc);
45 }
46
47 using namespace ASDCP;
48
49 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
50
51 //------------------------------------------------------------------------------------------
52 //
53 // command line option parser class
54
55 static const char* PROGRAM_NAME = "as-02-unwrap";  // program name for messages
56
57 // Increment the iterator, test for an additional non-option command line argument.
58 // Causes the caller to return if there are no remaining arguments or if the next
59 // argument begins with '-'.
60 #define TEST_EXTRA_ARG(i,c)                                             \
61   if ( ++i >= argc || argv[(i)][0] == '-' ) {                           \
62     fprintf(stderr, "Argument not found for option -%c.\n", (c));       \
63     return;                                                             \
64   }
65
66 //
67 void
68 banner(FILE* stream = stdout)
69 {
70   fprintf(stream, "\n\
71 %s (asdcplib %s)\n\n\
72 Copyright (c) 2011-2015, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
73 asdcplib may be copied only under the terms of the license found at\n\
74 the top of every file in the asdcplib distribution kit.\n\n\
75 Specify the -h (help) option for further information about %s\n\n",
76           PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
77 }
78
79 //
80 void
81 usage(FILE* stream = stdout)
82 {
83   fprintf(stream, "\
84 USAGE: %s [-h|-help] [-V]\n\
85 \n\
86        %s [-1|-2] [-b <buffer-size>] [-d <duration>]\n\
87        [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\
88        [-w] <input-file> [<file-prefix>]\n\n",
89           PROGRAM_NAME, PROGRAM_NAME);
90
91   fprintf(stream, "\
92 Options:\n\
93   -1                - Split Wave essence to mono WAV files during extract.\n\
94                       Default is multichannel WAV\n\
95   -2                - Split Wave essence to stereo WAV files during extract.\n\
96                       Default is multichannel WAV\n\
97   -b <buffer-size>  - Specify size in bytes of picture frame buffer\n\
98                       Defaults to 4,194,304 (4MB)\n\
99   -d <duration>     - Number of frames to process, default all\n\
100   -f <start-frame>  - Starting frame number, default 0\n\
101   -h | -help        - Show help\n\
102   -k <key-string>   - Use key for ciphertext operations\n\
103   -m                - verify HMAC values when reading\n\
104   -s <size>         - Number of bytes to dump to output when -v is given\n\
105   -V                - Show version information\n\
106   -v                - Verbose, prints informative messages to stderr\n\
107   -W                - Read input file only, do not write destination file\n\
108   -w <width>        - Width of numeric element in a series of frame file names\n\
109                       (default 6)\n\
110   -z                - Fail if j2c inputs have unequal parameters (default)\n\
111   -Z                - Ignore unequal parameters in j2c inputs\n\
112 \n\
113   NOTES: o There is no option grouping, all options must be distinct arguments.\n\
114          o All option arguments must be separated from the option by whitespace.\n\n");
115 }
116
117 //
118 class CommandOptions
119 {
120   CommandOptions();
121
122 public:
123   bool   error_flag;     // true if the given options are in error or not complete
124   bool   key_flag;       // true if an encryption key was given
125   bool   read_hmac;      // true if HMAC values are to be validated
126   bool   split_wav;      // true if PCM is to be extracted to stereo WAV files
127   bool   mono_wav;       // true if PCM is to be extracted to mono WAV files
128   bool   verbose_flag;   // true if the verbose option was selected
129   ui32_t fb_dump_size;   // number of bytes of frame buffer to dump
130   bool   no_write_flag;  // true if no output files are to be written
131   bool   version_flag;   // true if the version display option was selected
132   bool   help_flag;      // true if the help display option was selected
133   bool   stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
134   ui32_t number_width;   // number of digits in a serialized filename (for JPEG extract)
135   ui32_t start_frame;    // frame number to begin processing
136   ui32_t duration;       // number of frames to be processed
137   bool   duration_flag;  // true if duration argument given
138   bool   j2c_pedantic;   // passed to JP2K::SequenceParser::OpenRead
139   ui32_t picture_rate;   // fps of picture when wrapping PCM
140   ui32_t fb_size;        // size of picture frame buffer
141   Rational edit_rate;    // frame buffer size for reading clip-wrapped PCM
142   const char* file_prefix; // filename pre for files written by the extract mode
143   byte_t key_value[KeyLen];  // value of given encryption key (when key_flag is true)
144   byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
145   PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
146   const char* input_filename;
147   const char* extension;
148   std::string prefix_buffer;
149
150   //
151   CommandOptions(int argc, const char** argv) :
152     error_flag(true), key_flag(false), read_hmac(false), split_wav(false),
153     mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false),
154     version_flag(false), help_flag(false), number_width(6),
155     start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
156     picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
157     input_filename(0)
158   {
159     memset(key_value, 0, KeyLen);
160     memset(key_id_value, 0, UUIDlen);
161
162     for ( int i = 1; i < argc; ++i )
163       {
164
165         if ( (strcmp( argv[i], "-help") == 0) )
166           {
167             help_flag = true;
168             continue;
169           }
170          
171         if ( argv[i][0] == '-'
172              && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
173              && argv[i][2] == 0 )
174           {
175             switch ( argv[i][1] )
176               {
177               case '1': mono_wav = true; break;
178               case '2': split_wav = true; break;
179
180               case 'b':
181                 TEST_EXTRA_ARG(i, 'b');
182                 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
183
184                 if ( verbose_flag )
185                   fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
186
187                 break;
188
189               case 'd':
190                 TEST_EXTRA_ARG(i, 'd');
191                 duration_flag = true;
192                 duration = Kumu::xabs(strtol(argv[i], 0, 10));
193                 break;
194
195               case 'e':
196                 TEST_EXTRA_ARG(i, 'e');
197                 extension = argv[i];
198                 break;
199
200               case 'f':
201                 TEST_EXTRA_ARG(i, 'f');
202                 start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
203                 break;
204
205               case 'h': help_flag = true; break;
206               case 'm': read_hmac = true; break;
207
208               case 'p':
209                 TEST_EXTRA_ARG(i, 'p');
210                 picture_rate = Kumu::xabs(strtol(argv[i], 0, 10));
211                 break;
212
213               case 's':
214                 TEST_EXTRA_ARG(i, 's');
215                 fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
216                 break;
217
218               case 'V': version_flag = true; break;
219               case 'v': verbose_flag = true; break;
220               case 'W': no_write_flag = true; break;
221
222               case 'w':
223                 TEST_EXTRA_ARG(i, 'w');
224                 number_width = Kumu::xabs(strtol(argv[i], 0, 10));
225                 break;
226
227               case 'Z': j2c_pedantic = false; break;
228               case 'z': j2c_pedantic = true; break;
229
230               default:
231                 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
232                 return;
233               }
234           }
235         else
236           {
237             if ( argv[i][0] != '-' )
238               {
239                 if ( input_filename == 0 )
240                   {
241                     input_filename = argv[i];
242                   }
243                 else if ( file_prefix == 0 )
244                   {
245                     file_prefix = argv[i];
246                   }
247               }
248             else
249               {
250                 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
251                 return;
252               }
253           }
254       }
255
256     if ( help_flag || version_flag )
257       return;
258     
259     if ( input_filename == 0 )
260       {
261         fputs("At least one filename argument is required.\n", stderr);
262         return;
263       }
264
265     if ( file_prefix == 0 )
266       {
267         prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
268         file_prefix = prefix_buffer.c_str();
269       }
270
271     error_flag = false;
272   }
273 };
274
275
276 //------------------------------------------------------------------------------------------
277 // JPEG 2000 essence
278
279
280 // Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
281 // Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
282 // Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
283 //
284 Result_t
285 read_JP2K_file(CommandOptions& Options)
286 {
287   AESDecContext*     Context = 0;
288   HMACContext*       HMAC = 0;
289   AS_02::JP2K::MXFReader    Reader;
290   JP2K::FrameBuffer  FrameBuffer(Options.fb_size);
291   ui32_t             frame_count = 0;
292
293   Result_t result = Reader.OpenRead(Options.input_filename);
294
295   if ( ASDCP_SUCCESS(result) )
296     {
297       if ( Options.verbose_flag )
298         {
299           fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
300         }
301
302       ASDCP::MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
303       ASDCP::MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
304
305       result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
306                                                      reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
307
308       if ( KM_SUCCESS(result) )
309         {
310           assert(rgba_descriptor);
311           frame_count = rgba_descriptor->ContainerDuration;
312
313           if ( Options.verbose_flag )
314             {
315               rgba_descriptor->Dump();
316             }
317         }
318       else
319         {
320           result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
321                                                          reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
322
323           if ( KM_SUCCESS(result) )
324             {
325               assert(cdci_descriptor);
326               frame_count = cdci_descriptor->ContainerDuration;
327
328               if ( Options.verbose_flag )
329                 {
330                   cdci_descriptor->Dump();
331                 }
332             }
333           else
334             {
335               fprintf(stderr, "File does not contain an essence descriptor.\n");
336               frame_count = Reader.AS02IndexReader().GetDuration();
337             }
338         }
339
340       if ( frame_count == 0 )
341         {
342           frame_count = Reader.AS02IndexReader().GetDuration();
343         }
344
345       if ( frame_count == 0 )
346         {
347           fprintf(stderr, "Unable to determine file duration.\n");
348           return RESULT_FAIL;
349         }
350     }
351
352   if ( ASDCP_SUCCESS(result) && Options.key_flag )
353     {
354       Context = new AESDecContext;
355       result = Context->InitKey(Options.key_value);
356
357       if ( ASDCP_SUCCESS(result) && Options.read_hmac )
358         {
359           WriterInfo Info;
360           Reader.FillWriterInfo(Info);
361
362           if ( Info.UsesHMAC )
363             {
364               HMAC = new HMACContext;
365               result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
366             }
367           else
368             {
369               fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
370             }
371         }
372     }
373
374   ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
375   if ( last_frame > frame_count )
376     last_frame = frame_count;
377
378   char name_format[64];
379   snprintf(name_format,  64, "%%s%%0%du.j2c", Options.number_width);
380
381   for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
382     {
383       result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
384
385       char filename[1024];
386       snprintf(filename, 1024, name_format, Options.file_prefix, i);
387
388       if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
389         {
390           printf("Frame %d, %d bytes", i, FrameBuffer.Size());
391
392           if ( ! Options.no_write_flag )
393             {
394               printf(" -> %s", filename);
395             }
396
397           printf("\n");
398         }
399
400       if ( ASDCP_SUCCESS(result)  && ( ! Options.no_write_flag ) )
401         {
402           Kumu::FileWriter OutFile;
403           ui32_t write_count;
404           result = OutFile.OpenWrite(filename);
405
406           if ( ASDCP_SUCCESS(result) )
407             result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
408
409           if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
410             {
411               FrameBuffer.Dump(stderr, Options.fb_dump_size);
412             }
413         }
414     }
415
416   return result;
417 }
418
419 //------------------------------------------------------------------------------------------
420 // PCM essence
421
422 // Read one or more plaintext PCM audio streams from a plaintext ASDCP file
423 // Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
424 // Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
425 //
426 Result_t
427 read_PCM_file(CommandOptions& Options)
428 {
429   AESDecContext*     Context = 0;
430   HMACContext*       HMAC = 0;
431   AS_02::PCM::MXFReader     Reader;
432   PCM::FrameBuffer   FrameBuffer;
433   WavFileWriter      OutWave;
434   ui32_t last_frame = 0;
435   ASDCP::MXF::WaveAudioDescriptor *wave_descriptor = 0;
436
437   if ( Options.edit_rate == Rational(0,0) ) // todo, make this available to the CLI
438     {
439       Options.edit_rate = EditRate_24;
440     }
441
442   Result_t result = Reader.OpenRead(Options.input_filename, Options.edit_rate);
443
444   if ( KM_SUCCESS(result) )
445     {
446       if ( Options.verbose_flag )
447         {
448           fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
449         }
450       
451       ASDCP::MXF::InterchangeObject* tmp_obj = 0;
452
453       result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor), &tmp_obj);
454
455       if ( KM_SUCCESS(result) )
456         {
457           wave_descriptor = dynamic_cast<ASDCP::MXF::WaveAudioDescriptor*>(tmp_obj);
458
459           if ( wave_descriptor == 0 )
460             {
461               fprintf(stderr, "File does not contain an essence descriptor.\n");
462               return RESULT_FAIL;
463             }
464       
465           if ( Options.verbose_flag )
466             {
467               wave_descriptor->Dump();
468             }
469
470           if ( wave_descriptor->ContainerDuration.get() == 0 )
471             {
472               fprintf(stderr, "ContainerDuration not set in file descriptor, attempting to use index duration.\n");
473               last_frame = Reader.AS02IndexReader().GetDuration();
474             }
475           else
476             {
477               last_frame = wave_descriptor->ContainerDuration;
478             }
479
480           if ( last_frame == 0 )
481             {
482               fprintf(stderr, "ContainerDuration not set in index, attempting to use Duration from SourceClip.\n");
483               result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_SourceClip), &tmp_obj);
484               if ( KM_SUCCESS(result))
485                 {
486                   ASDCP::MXF::SourceClip *sourceClip = dynamic_cast<ASDCP::MXF::SourceClip*>(tmp_obj);
487                   if ( ! sourceClip->Duration.empty() )
488                     {
489                       last_frame = sourceClip->Duration;
490                     }
491                 }
492             }
493
494           if ( last_frame == 0 )
495             {
496               fprintf(stderr, "Unable to determine file duration.\n");
497               return RESULT_FAIL;
498             }
499
500           assert(wave_descriptor);
501           FrameBuffer.Capacity(AS_02::MXF::CalcFrameBufferSize(*wave_descriptor, Options.edit_rate));
502           last_frame = AS_02::MXF::CalcFramesFromDurationInSamples(last_frame, *wave_descriptor, Options.edit_rate);
503         }
504     }
505
506   if ( ASDCP_SUCCESS(result) )
507     {
508       if ( Options.duration > 0 && Options.duration < last_frame )
509         last_frame = Options.duration;
510
511       if ( Options.start_frame > 0 )
512         {
513           if ( Options.start_frame > last_frame )
514             {
515               fprintf(stderr, "Start value greater than file duration.\n");
516               return RESULT_FAIL;
517             }
518
519           last_frame = Kumu::xmin(Options.start_frame + last_frame, last_frame);
520         }
521
522       last_frame = last_frame - Options.start_frame;
523
524       PCM::AudioDescriptor ADesc;
525
526       result = MD_to_PCM_ADesc(wave_descriptor, ADesc);
527
528       if ( ASDCP_SUCCESS(result) )
529         {
530           ADesc.ContainerDuration = last_frame;
531           ADesc.EditRate = Options.edit_rate;
532
533           result = OutWave.OpenWrite(ADesc, Options.file_prefix,
534                                      ( Options.split_wav ? WavFileWriter::ST_STEREO : 
535                                        ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
536         }
537     }
538
539   if ( ASDCP_SUCCESS(result) && Options.key_flag )
540     {
541       Context = new AESDecContext;
542       result = Context->InitKey(Options.key_value);
543
544       if ( ASDCP_SUCCESS(result) && Options.read_hmac )
545         {
546           WriterInfo Info;
547           Reader.FillWriterInfo(Info);
548
549           if ( Info.UsesHMAC )
550             {
551               HMAC = new HMACContext;
552               result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
553             }
554           else
555             {
556               fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
557             }
558         }
559     }
560
561   for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
562     {
563       result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
564
565       if ( ASDCP_SUCCESS(result) )
566         {
567           if ( Options.verbose_flag )
568             {
569               FrameBuffer.FrameNumber(i);
570               FrameBuffer.Dump(stderr, Options.fb_dump_size);
571             }
572
573           if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
574             {
575               fprintf(stderr, "Last frame is incomplete, padding with zeros.\n");
576               // actually, it has already been zeroed for us, we just need to recognize the appropriate size
577               FrameBuffer.Size(FrameBuffer.Capacity());
578             }
579
580           result = OutWave.WriteFrame(FrameBuffer);
581         }
582     }
583
584   return result;
585 }
586
587
588 //------------------------------------------------------------------------------------------
589 // TimedText essence
590
591 // Read one or more timed text streams from a plaintext AS-02 file
592 //
593 Result_t
594 read_timed_text_file(CommandOptions& Options)
595 {
596   AESDecContext*     Context = 0;
597   HMACContext*       HMAC = 0;
598   AS_02::TimedText::MXFReader     Reader;
599   TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
600   //ASDCP::TimedText::FrameBuffer   FrameBuffer(Options.fb_size);
601   AS_02::TimedText::TimedTextDescriptor TDesc;
602   ASDCP::MXF::TimedTextDescriptor *tt_descriptor = 0;
603
604   Result_t result = Reader.OpenRead(Options.input_filename);
605
606   if ( ASDCP_SUCCESS(result) )
607     {
608       result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_TimedTextDescriptor),
609                                                      reinterpret_cast<MXF::InterchangeObject**>(&tt_descriptor));
610     if ( Options.verbose_flag ) {
611         tt_descriptor->Dump();
612     }
613
614
615   if ( ASDCP_FAILURE(result) )
616     return result;
617
618   std::string XMLDoc;
619   std::string out_path = Kumu::PathDirname(Options.file_prefix);
620   ui32_t write_count;
621   char buf[64];
622   TimedText::ResourceList_t::const_iterator ri;
623
624   result = Reader.ReadTimedTextResource(XMLDoc);
625
626   if ( ASDCP_SUCCESS(result) )
627     {
628       Reader.FillTimedTextDescriptor(TDesc);
629       FrameBuffer.Capacity(Options.fb_size);
630
631       if ( Options.verbose_flag )
632         TimedText::DescriptorDump(TDesc);
633     }
634
635   if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
636     {
637       Kumu::FileWriter Writer;
638       result = Writer.OpenWrite(Options.file_prefix);
639
640       if ( ASDCP_SUCCESS(result) )
641         result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
642     }
643
644   for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
645     {
646       result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
647
648       if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
649         {
650           Kumu::FileWriter Writer;
651           if (out_path != "") {
652                   result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
653           } else {
654                   // Workaround for a bug in Kumu::PathJoin
655                   result = Writer.OpenWrite(Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64));
656           }
657
658           if ( ASDCP_SUCCESS(result) )
659             result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
660
661               if ( Options.verbose_flag )
662                 FrameBuffer.Dump(stderr, Options.fb_dump_size);
663         }
664     }
665     }
666   return result;
667 }
668
669 //
670 int
671 main(int argc, const char** argv)
672 {
673   char     str_buf[64];
674   CommandOptions Options(argc, argv);
675
676   if ( Options.version_flag )
677     banner();
678
679   if ( Options.help_flag )
680     usage();
681
682   if ( Options.version_flag || Options.help_flag )
683     return 0;
684
685   if ( Options.error_flag )
686     {
687       fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
688       return 3;
689     }
690
691   EssenceType_t EssenceType;
692   Result_t result = ASDCP::EssenceType(Options.input_filename, EssenceType);
693
694   if ( ASDCP_SUCCESS(result) )
695     {
696       switch ( EssenceType )
697         {
698         case ESS_AS02_JPEG_2000:
699           result = read_JP2K_file(Options);
700           break;
701
702         case ESS_AS02_PCM_24b_48k:
703         case ESS_AS02_PCM_24b_96k:
704           result = read_PCM_file(Options);
705           break;
706
707         case ESS_AS02_TIMED_TEXT:
708           result = read_timed_text_file(Options);
709           break;
710
711         default:
712           fprintf(stderr, "%s: Unknown file type (%d), not AS-02 essence.\n", Options.input_filename, EssenceType);
713           return 5;
714         }
715     }
716
717   if ( ASDCP_FAILURE(result) )
718     {
719       fputs("Program stopped on error.\n", stderr);
720
721       if ( result != RESULT_FAIL )
722         {
723           fputs(result, stderr);
724           fputc('\n', stderr);
725         }
726
727       return 1;
728     }
729
730   return 0;
731 }
732
733
734 //
735 // end as-02-unwrap.cpp
736 //