2 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
7 Redistribution and use in source and binary forms, with or without
8 modification, are permitted provided that the following conditions
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.
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.
29 /*! \file as-02-unwrap.cpp
31 \brief AS-02 file manipulation utility
33 This program extracts picture and sound from AS-02 files.
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
39 #include <KM_fileio.h>
41 #include "AS_02_ACES.h"
42 #include <WavFileWriter.h>
45 Result_t MD_to_PCM_ADesc(ASDCP::MXF::WaveAudioDescriptor* ADescObj, ASDCP::PCM::AudioDescriptor& ADesc);
48 using namespace ASDCP;
50 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
52 //------------------------------------------------------------------------------------------
54 // command line option parser class
56 static const char* PROGRAM_NAME = "as-02-unwrap"; // program name for messages
58 // Increment the iterator, test for an additional non-option command line argument.
59 // Causes the caller to return if there are no remaining arguments or if the next
60 // argument begins with '-'.
61 #define TEST_EXTRA_ARG(i,c) \
62 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
63 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
69 banner(FILE* stream = stdout)
73 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
74 asdcplib may be copied only under the terms of the license found at\n\
75 the top of every file in the asdcplib distribution kit.\n\n\
76 Specify the -h (help) option for further information about %s\n\n",
77 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
82 usage(FILE* stream = stdout)
85 USAGE: %s [-h|-help] [-V]\n\
87 %s [-1|-2] [-b <buffer-size>] [-d <duration>]\n\
88 [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\
89 [-w] <input-file> [<file-prefix>]\n\n",
90 PROGRAM_NAME, PROGRAM_NAME);
94 -1 - Split Wave essence to mono WAV files during extract.\n\
95 Default is multichannel WAV\n\
96 -2 - Split Wave essence to stereo WAV files during extract.\n\
97 Default is multichannel WAV\n\
98 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
99 Defaults to 4,194,304 (4MB)\n\
100 -d <duration> - Number of frames to process, default all\n\
101 -f <start-frame> - Starting frame number, default 0\n\
102 -g <SID> - Extract the Generic Stream Partition payload\n\
103 -h | -help - Show help\n\
104 -k <key-string> - Use key for ciphertext operations\n\
105 -m - verify HMAC values when reading\n\
106 -s <size> - Number of bytes to dump to output when -v is given\n\
107 -V - Show version information\n\
108 -v - Verbose, prints informative messages to stderr\n\
109 -W - Read input file only, do not write destination file\n\
110 -w <width> - Width of numeric element in a series of frame file names\n\
112 -z - Fail if j2c inputs have unequal parameters (default)\n\
113 -Z - Ignore unequal parameters in j2c inputs\n\
115 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
116 o All option arguments must be separated from the option by whitespace.\n\n");
125 bool error_flag; // true if the given options are in error or not complete
126 bool key_flag; // true if an encryption key was given
127 bool read_hmac; // true if HMAC values are to be validated
128 bool split_wav; // true if PCM is to be extracted to stereo WAV files
129 bool mono_wav; // true if PCM is to be extracted to mono WAV files
130 bool verbose_flag; // true if the verbose option was selected
131 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
132 bool no_write_flag; // true if no output files are to be written
133 bool version_flag; // true if the version display option was selected
134 bool help_flag; // true if the help display option was selected
135 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
136 ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
137 ui32_t start_frame; // frame number to begin processing
138 ui32_t duration; // number of frames to be processed
139 bool duration_flag; // true if duration argument given
140 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
141 ui32_t picture_rate; // fps of picture when wrapping PCM
142 ui32_t fb_size; // size of picture frame buffer
143 Rational edit_rate; // frame buffer size for reading clip-wrapped PCM
144 const char* file_prefix; // filename pre for files written by the extract mode
145 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
146 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
147 const char* input_filename;
148 const char* extension;
149 i32_t g_stream_sid; // Stream ID of a generic stream partition payload to be extracted
150 std::string prefix_buffer;
153 CommandOptions(int argc, const char** argv) :
154 error_flag(true), key_flag(false), read_hmac(false), split_wav(false),
155 mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false),
156 version_flag(false), help_flag(false), number_width(6),
157 start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
158 picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
159 input_filename(0), extension(0), g_stream_sid(0)
161 memset(key_value, 0, KeyLen);
162 memset(key_id_value, 0, UUIDlen);
164 for ( int i = 1; i < argc; ++i )
167 if ( (strcmp( argv[i], "-help") == 0) )
173 if ( argv[i][0] == '-'
174 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
177 switch ( argv[i][1] )
179 case '1': mono_wav = true; break;
180 case '2': split_wav = true; break;
183 TEST_EXTRA_ARG(i, 'b');
184 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
187 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
192 TEST_EXTRA_ARG(i, 'd');
193 duration_flag = true;
194 duration = Kumu::xabs(strtol(argv[i], 0, 10));
198 TEST_EXTRA_ARG(i, 'e');
203 TEST_EXTRA_ARG(i, 'f');
204 start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
208 TEST_EXTRA_ARG(i, 'g');
209 g_stream_sid = strtol(argv[i], 0, 10);
212 case 'h': help_flag = true; break;
213 case 'm': read_hmac = true; break;
216 TEST_EXTRA_ARG(i, 'p');
217 picture_rate = Kumu::xabs(strtol(argv[i], 0, 10));
221 TEST_EXTRA_ARG(i, 's');
222 fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
225 case 'V': version_flag = true; break;
226 case 'v': verbose_flag = true; break;
227 case 'W': no_write_flag = true; break;
230 TEST_EXTRA_ARG(i, 'w');
231 number_width = Kumu::xabs(strtol(argv[i], 0, 10));
234 case 'Z': j2c_pedantic = false; break;
235 case 'z': j2c_pedantic = true; break;
238 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
244 if ( argv[i][0] != '-' )
246 if ( input_filename == 0 )
248 input_filename = argv[i];
250 else if ( file_prefix == 0 )
252 file_prefix = argv[i];
257 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
263 if ( help_flag || version_flag )
266 if ( input_filename == 0 )
268 fputs("At least one filename argument is required.\n", stderr);
272 if ( file_prefix == 0 )
274 prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
275 file_prefix = prefix_buffer.c_str();
283 //------------------------------------------------------------------------------------------
287 // Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
288 // Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
289 // Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
292 read_JP2K_file(CommandOptions& Options)
294 AESDecContext* Context = 0;
295 HMACContext* HMAC = 0;
296 AS_02::JP2K::MXFReader Reader;
297 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
298 ui32_t frame_count = 0;
300 Result_t result = Reader.OpenRead(Options.input_filename);
302 if ( ASDCP_SUCCESS(result) )
304 if ( Options.verbose_flag )
306 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
309 ASDCP::MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
310 ASDCP::MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
312 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
313 reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
315 if ( KM_SUCCESS(result) )
317 assert(rgba_descriptor);
318 frame_count = (ui32_t)rgba_descriptor->ContainerDuration;
320 if ( Options.verbose_flag )
322 rgba_descriptor->Dump();
327 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
328 reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
330 if ( KM_SUCCESS(result) )
332 assert(cdci_descriptor);
333 frame_count = (ui32_t)cdci_descriptor->ContainerDuration;
335 if ( Options.verbose_flag )
337 cdci_descriptor->Dump();
342 fprintf(stderr, "File does not contain an essence descriptor.\n");
343 frame_count = Reader.AS02IndexReader().GetDuration();
347 if ( frame_count == 0 )
349 frame_count = Reader.AS02IndexReader().GetDuration();
352 if ( frame_count == 0 )
354 fprintf(stderr, "Unable to determine file duration.\n");
359 if ( ASDCP_SUCCESS(result) && Options.key_flag )
361 Context = new AESDecContext;
362 result = Context->InitKey(Options.key_value);
364 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
367 Reader.FillWriterInfo(Info);
371 HMAC = new HMACContext;
372 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
376 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
381 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
382 if ( last_frame > frame_count )
383 last_frame = frame_count;
385 char name_format[64];
386 snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
388 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
390 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
393 snprintf(filename, 1024, name_format, Options.file_prefix, i);
395 if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
397 printf("Frame %d, %d bytes", i, FrameBuffer.Size());
399 if ( ! Options.no_write_flag )
401 printf(" -> %s", filename);
407 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
409 Kumu::FileWriter OutFile;
411 result = OutFile.OpenWrite(filename);
413 if ( ASDCP_SUCCESS(result) )
414 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
416 if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
418 FrameBuffer.Dump(stderr, Options.fb_dump_size);
427 //------------------------------------------------------------------------------------------
432 read_ACES_file(CommandOptions& Options)
434 AESDecContext* Context = 0;
435 HMACContext* HMAC = 0;
436 AS_02::ACES::MXFReader Reader;
437 AS_02::ACES::FrameBuffer FrameBuffer(Options.fb_size);
438 ui64_t frame_count = 0;
439 AS_02::ACES::ResourceList_t resource_list_t;
441 Result_t result = Reader.OpenRead(Options.input_filename);
443 if (ASDCP_SUCCESS(result))
445 if (Options.verbose_flag)
447 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
449 ASDCP::MXF::RGBAEssenceDescriptor *aces_descriptor = 0;
451 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
452 reinterpret_cast<MXF::InterchangeObject**>(&aces_descriptor));
454 if (KM_SUCCESS(result))
456 assert(aces_descriptor);
457 frame_count = aces_descriptor->ContainerDuration;
459 if (Options.verbose_flag)
461 aces_descriptor->Dump();
466 fprintf(stderr, "File does not contain an essence descriptor.\n");
467 frame_count = Reader.AS02IndexReader().GetDuration();
470 if (frame_count == 0)
472 frame_count = Reader.AS02IndexReader().GetDuration();
475 if (frame_count == 0)
477 fprintf(stderr, "Unable to determine file duration.\n");
482 if (ASDCP_SUCCESS(result) && Options.key_flag)
484 Context = new AESDecContext;
485 result = Context->InitKey(Options.key_value);
487 if (ASDCP_SUCCESS(result) && Options.read_hmac)
490 Reader.FillWriterInfo(Info);
494 HMAC = new HMACContext;
495 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
499 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
504 ui32_t last_frame = Options.start_frame + (Options.duration ? Options.duration : frame_count);
505 if (last_frame > frame_count)
506 last_frame = frame_count;
508 char name_format[64];
509 snprintf(name_format, 64, "%%s%%0%du.exr", Options.number_width);
511 for (ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++)
513 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
516 snprintf(filename, 1024, name_format, Options.file_prefix, i);
518 if (ASDCP_SUCCESS(result) && Options.verbose_flag)
520 printf("Frame %d, %d bytes", i, FrameBuffer.Size());
522 if (!Options.no_write_flag)
524 printf(" -> %s", filename);
530 if (ASDCP_SUCCESS(result) && (!Options.no_write_flag))
532 Kumu::FileWriter OutFile;
534 result = OutFile.OpenWrite(filename);
536 if (ASDCP_SUCCESS(result))
537 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
539 if (ASDCP_SUCCESS(result) && Options.verbose_flag)
541 FrameBuffer.Dump(stderr, Options.fb_dump_size);
546 snprintf(name_format, 64, "TargetFrame_%%s.%%s");
547 result = Reader.FillAncillaryResourceList(resource_list_t);
548 if (ASDCP_SUCCESS(result))
550 AS_02::ACES::ResourceList_t::iterator it;
551 for (it = resource_list_t.begin(); it != resource_list_t.end(); it++)
554 resource_id.Set(it->ResourceID);
555 result = Reader.ReadAncillaryResource(resource_id, FrameBuffer);
559 resource_id.EncodeString(buf, 64);
560 std::string extension;
563 case AS_02::ACES::MT_PNG:
566 case AS_02::ACES::MT_TIFF:
572 snprintf(filename, 1024, name_format, buf, extension.c_str());
574 if (ASDCP_SUCCESS(result) && Options.verbose_flag)
576 printf("Read Anc resource, size: %d\n", FrameBuffer.Size() );
578 if (!Options.no_write_flag)
580 printf(" -> %s", filename);
586 if (ASDCP_SUCCESS(result) && (!Options.no_write_flag))
588 Kumu::FileWriter OutFile;
590 result = OutFile.OpenWrite(filename);
592 if (ASDCP_SUCCESS(result))
593 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
595 if (ASDCP_SUCCESS(result) && Options.verbose_flag)
597 FrameBuffer.Dump(stderr, Options.fb_dump_size);
610 //------------------------------------------------------------------------------------------
613 // Read one or more plaintext PCM audio streams from a plaintext ASDCP file
614 // Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
615 // Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
618 read_PCM_file(CommandOptions& Options)
620 AESDecContext* Context = 0;
621 HMACContext* HMAC = 0;
622 AS_02::PCM::MXFReader Reader;
623 PCM::FrameBuffer FrameBuffer;
624 WavFileWriter OutWave;
625 ui32_t last_frame = 0;
626 ASDCP::MXF::WaveAudioDescriptor *wave_descriptor = 0;
628 if ( Options.edit_rate == Rational(0,0) ) // todo, make this available to the CLI
630 Options.edit_rate = EditRate_24;
633 Result_t result = Reader.OpenRead(Options.input_filename, Options.edit_rate);
635 if ( KM_SUCCESS(result) )
637 if ( Options.verbose_flag )
639 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
642 ASDCP::MXF::InterchangeObject* tmp_obj = 0;
644 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor), &tmp_obj);
646 if ( KM_SUCCESS(result) )
648 wave_descriptor = dynamic_cast<ASDCP::MXF::WaveAudioDescriptor*>(tmp_obj);
650 if ( wave_descriptor == 0 )
652 fprintf(stderr, "File does not contain an essence descriptor.\n");
656 if ( Options.verbose_flag )
658 wave_descriptor->Dump();
661 if ( wave_descriptor->ContainerDuration.get() == 0 )
663 fprintf(stderr, "ContainerDuration not set in file descriptor, attempting to use index duration.\n");
664 last_frame = Reader.AS02IndexReader().GetDuration();
668 last_frame = (ui32_t)wave_descriptor->ContainerDuration;
671 if ( last_frame == 0 )
673 fprintf(stderr, "ContainerDuration not set in index, attempting to use Duration from SourceClip.\n");
674 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_SourceClip), &tmp_obj);
675 if ( KM_SUCCESS(result))
677 ASDCP::MXF::SourceClip *sourceClip = dynamic_cast<ASDCP::MXF::SourceClip*>(tmp_obj);
678 if ( ! sourceClip->Duration.empty() )
680 last_frame = (ui32_t)sourceClip->Duration;
685 if ( last_frame == 0 )
687 fprintf(stderr, "Unable to determine file duration.\n");
691 assert(wave_descriptor);
692 FrameBuffer.Capacity(AS_02::MXF::CalcFrameBufferSize(*wave_descriptor, Options.edit_rate));
693 last_frame = AS_02::MXF::CalcFramesFromDurationInSamples(last_frame, *wave_descriptor, Options.edit_rate);
697 if ( ASDCP_SUCCESS(result) )
699 if ( Options.duration > 0 && Options.duration < last_frame )
700 last_frame = Options.duration;
702 if ( Options.start_frame > 0 )
704 if ( Options.start_frame > last_frame )
706 fprintf(stderr, "Start value greater than file duration.\n");
710 last_frame = Kumu::xmin(Options.start_frame + last_frame, last_frame);
713 last_frame = last_frame - Options.start_frame;
715 PCM::AudioDescriptor ADesc;
717 result = MD_to_PCM_ADesc(wave_descriptor, ADesc);
719 if ( ASDCP_SUCCESS(result) )
721 ADesc.ContainerDuration = last_frame;
722 ADesc.EditRate = Options.edit_rate;
724 result = OutWave.OpenWrite(ADesc, Options.file_prefix,
725 ( Options.split_wav ? WavFileWriter::ST_STEREO :
726 ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
730 if ( ASDCP_SUCCESS(result) && Options.key_flag )
732 Context = new AESDecContext;
733 result = Context->InitKey(Options.key_value);
735 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
738 Reader.FillWriterInfo(Info);
742 HMAC = new HMACContext;
743 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
747 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
752 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
754 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
756 if ( ASDCP_SUCCESS(result) )
758 if ( Options.verbose_flag )
760 FrameBuffer.FrameNumber(i);
761 FrameBuffer.Dump(stderr, Options.fb_dump_size);
764 if ( FrameBuffer.Size() != FrameBuffer.Capacity() )
766 fprintf(stderr, "Last frame is incomplete, padding with zeros.\n");
767 // actually, it has already been zeroed for us, we just need to recognize the appropriate size
768 FrameBuffer.Size(FrameBuffer.Capacity());
771 result = OutWave.WriteFrame(FrameBuffer);
779 //------------------------------------------------------------------------------------------
782 // Read one or more timed text streams from a plaintext AS-02 file
785 read_timed_text_file(CommandOptions& Options)
787 AESDecContext* Context = 0;
788 HMACContext* HMAC = 0;
789 AS_02::TimedText::MXFReader Reader;
790 TimedText::FrameBuffer FrameBuffer(Options.fb_size);
791 //ASDCP::TimedText::FrameBuffer FrameBuffer(Options.fb_size);
792 AS_02::TimedText::TimedTextDescriptor TDesc;
793 ASDCP::MXF::TimedTextDescriptor *tt_descriptor = 0;
795 Result_t result = Reader.OpenRead(Options.input_filename);
797 if ( ASDCP_SUCCESS(result) )
799 result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_TimedTextDescriptor),
800 reinterpret_cast<MXF::InterchangeObject**>(&tt_descriptor));
801 if ( Options.verbose_flag ) {
802 tt_descriptor->Dump();
806 if ( ASDCP_FAILURE(result) )
810 std::string out_path = Kumu::PathDirname(Options.file_prefix);
813 TimedText::ResourceList_t::const_iterator ri;
815 result = Reader.ReadTimedTextResource(XMLDoc);
817 if ( ASDCP_SUCCESS(result) )
819 Reader.FillTimedTextDescriptor(TDesc);
820 FrameBuffer.Capacity(Options.fb_size);
822 if ( Options.verbose_flag )
823 TimedText::DescriptorDump(TDesc);
826 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
828 Kumu::FileWriter Writer;
829 result = Writer.OpenWrite(Options.file_prefix);
831 if ( ASDCP_SUCCESS(result) )
832 result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
835 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
837 result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
839 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
841 Kumu::FileWriter Writer;
842 if (out_path != "") {
843 result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
845 // Workaround for a bug in Kumu::PathJoin
846 result = Writer.OpenWrite(Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64));
849 if ( ASDCP_SUCCESS(result) )
850 result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
852 if ( Options.verbose_flag )
853 FrameBuffer.Dump(stderr, Options.fb_dump_size);
862 read_isxd_file(CommandOptions& Options)
864 AESDecContext* Context = 0;
865 HMACContext* HMAC = 0;
866 AS_02::ISXD::MXFReader Reader;
867 ASDCP::FrameBuffer FrameBuffer;
868 ui32_t frame_count = 0;
870 Result_t result = Reader.OpenRead(Options.input_filename);
872 if ( ASDCP_SUCCESS(result) )
874 result = FrameBuffer.Capacity(Options.fb_size);
877 if ( ASDCP_SUCCESS(result) )
879 std::list<MXF::InterchangeObject*> object_list;
880 Reader.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list);
882 std::list<MXF::InterchangeObject*>::iterator i;
883 for ( i = object_list.begin(); i != object_list.end(); ++i )
885 MXF::GenericStreamTextBasedSet *text_object = dynamic_cast<MXF::GenericStreamTextBasedSet*>(*i);
887 text_object->Dump(stderr);
891 if ( ASDCP_SUCCESS(result) && Options.key_flag )
893 Context = new AESDecContext;
894 result = Context->InitKey(Options.key_value);
896 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
899 Reader.FillWriterInfo(Info);
903 HMAC = new HMACContext;
904 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
908 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
913 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
914 if ( last_frame > frame_count )
915 last_frame = frame_count;
917 char name_format[64];
918 snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension);
920 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
922 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
924 if ( ASDCP_SUCCESS(result) )
926 if ( ! Options.no_write_flag )
928 Kumu::FileWriter OutFile;
931 snprintf(filename, 256, name_format, Options.file_prefix, i);
932 result = OutFile.OpenWrite(filename);
934 if ( ASDCP_SUCCESS(result) )
935 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
944 extract_generic_stream_partition_payload(const std::string& in_filename, const ui32_t sid, const std::string& out_filename)
946 ASDCP::FrameBuffer payload;
947 AS_02::ISXD::MXFReader reader;
949 Result_t result = reader.OpenRead(in_filename);
951 if ( KM_SUCCESS(result) )
953 result = reader.ReadGenericStreamPartitionPayload(sid, payload);
956 if ( KM_SUCCESS(result) )
958 Kumu::FileWriter writer;
959 ui32_t write_count = 0;
960 result = writer.OpenWrite(out_filename);
962 if ( KM_SUCCESS(result) )
964 result = writer.Write(payload.RoData(), payload.Size(), &write_count);
974 main(int argc, const char** argv)
976 CommandOptions Options(argc, argv);
978 if ( Options.version_flag )
981 if ( Options.help_flag )
984 if ( Options.version_flag || Options.help_flag )
987 if ( Options.error_flag )
989 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
993 EssenceType_t EssenceType;
994 Result_t result = ASDCP::EssenceType(Options.input_filename, EssenceType);
996 if ( ASDCP_SUCCESS(result) )
998 switch ( EssenceType )
1000 case ESS_AS02_JPEG_2000:
1001 result = read_JP2K_file(Options);
1005 result = read_ACES_file(Options);
1008 case ESS_AS02_PCM_24b_48k:
1009 case ESS_AS02_PCM_24b_96k:
1010 result = read_PCM_file(Options);
1013 case ESS_AS02_TIMED_TEXT:
1014 result = read_timed_text_file(Options);
1018 if ( Options.g_stream_sid == 0 )
1020 result = read_isxd_file(Options);
1024 result = extract_generic_stream_partition_payload(Options.input_filename,
1025 Options.g_stream_sid,
1026 Options.file_prefix);
1031 fprintf(stderr, "%s: Unknown file type (%d), not AS-02 essence.\n", Options.input_filename, EssenceType);
1036 if ( ASDCP_FAILURE(result) )
1038 fputs("Program stopped on error.\n", stderr);
1040 if ( result != RESULT_FAIL )
1042 fputs(result, stderr);
1043 fputc('\n', stderr);
1054 // end as-02-unwrap.cpp