2 Copyright (c) 2003-2016, 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-unwrap.cpp
29 \brief AS-DCP file manipulation utility
31 This program extracts picture, sound and text essence from AS-DCP files.
33 For more information about asdcplib, please refer to the header file AS_DCP.h
36 #include <KM_fileio.h>
37 #include <WavFileWriter.h>
39 using namespace ASDCP;
41 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
43 //------------------------------------------------------------------------------------------
45 // command line option parser class
47 static const char* PROGRAM_NAME = "asdcp-unwrap"; // program name for messages
49 // Increment the iterator, test for an additional non-option command line argument.
50 // Causes the caller to return if there are no remaining arguments or if the next
51 // argument begins with '-'.
52 #define TEST_EXTRA_ARG(i,c) \
53 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
54 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
60 banner(FILE* stream = stdout)
64 Copyright (c) 2003-2015 John Hurst\n\n\
65 asdcplib may be copied only under the terms of the license found at\n\
66 the top of every file in the asdcplib distribution kit.\n\n\
67 Specify the -h (help) option for further information about %s\n\n",
68 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
73 usage(FILE* stream = stdout)
76 USAGE: %s [-h|-help] [-V]\n\
78 %s -G [-v] <input-file>\n\
80 %s [-1|-2] [-3] [-b <buffer-size>] [-d <duration>]\n\
81 [-f <starting-frame>] [-m] [-p <frame-rate>] [-R] [-s <size>] [-v] [-W]\n\
82 [-w] <input-file> [<file-prefix>]\n\n",
83 PROGRAM_NAME, PROGRAM_NAME, PROGRAM_NAME);
87 -1 - Split Wave essence to mono WAV files during extract.\n\
88 Default is multichannel WAV\n\
89 -2 - Split Wave essence to stereo WAV files during extract.\n\
90 Default is multichannel WAV\n\
91 -3 - Force stereoscopic interpretation of a JP2K file.\n\
92 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
93 Defaults to 4,194,304 (4MB)\n\
94 -d <duration> - Number of frames to process, default all\n\
95 -e <extension> - Extension to use for Unknown D-Cinema Data files. default dcdata\n\
96 -f <start-frame> - Starting frame number, default 0\n \
97 -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\
98 -h | -help - Show help\n\
99 -k <key-string> - Use key for ciphertext operations\n\
100 -m - verify HMAC values when reading\n\
101 -p <rate> - Alternative picture rate when unwrapping PCM:\n\
102 Use one of [23|24|25|30|48|50|60], 24 is default\n\
103 -s <size> - Number of bytes to dump to output when -v is given\n\
104 -V - Show version information\n\
105 -v - Verbose, prints informative messages to stderr\n\
106 -W - Read input file only, do not write destination file\n\
107 -w <width> - Width of numeric element in a series of frame file names\n\
109 -z - Fail if j2c inputs have unequal parameters (default)\n\
110 -Z - Ignore unequal parameters in j2c inputs\n\
112 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
113 o All option arguments must be separated from the option by whitespace.\n\
114 o An argument of \"23\" to the -p option will be interpreted\n\
115 as 24000/1001 fps.\n\n");
133 bool error_flag; // true if the given options are in error or not complete
134 bool key_flag; // true if an encryption key was given
135 bool read_hmac; // true if HMAC values are to be validated
136 bool split_wav; // true if PCM is to be extracted to stereo WAV files
137 bool mono_wav; // true if PCM is to be extracted to mono WAV files
138 bool verbose_flag; // true if the verbose option was selected
139 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
140 bool no_write_flag; // true if no output files are to be written
141 bool version_flag; // true if the version display option was selected
142 bool help_flag; // true if the help display option was selected
143 bool stereo_image_flag; // if true, expect stereoscopic JP2K input (left eye first)
144 ui32_t number_width; // number of digits in a serialized filename (for JPEG extract)
145 ui32_t start_frame; // frame number to begin processing
146 ui32_t duration; // number of frames to be processed
147 bool duration_flag; // true if duration argument given
148 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
149 ui32_t picture_rate; // fps of picture when wrapping PCM
150 ui32_t fb_size; // size of picture frame buffer
151 const char* file_prefix; // filename pre for files written by the extract mode
152 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
153 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
154 PCM::ChannelFormat_t channel_fmt; // audio channel arrangement
155 const char* input_filename;
156 std::string prefix_buffer;
157 const char* extension; // file extension to use for unknown D-Cinema Data track files.
160 Rational PictureRate()
162 if ( picture_rate == 16 ) return EditRate_16;
163 if ( picture_rate == 18 ) return EditRate_18;
164 if ( picture_rate == 20 ) return EditRate_20;
165 if ( picture_rate == 22 ) return EditRate_22;
166 if ( picture_rate == 23 ) return EditRate_23_98;
167 if ( picture_rate == 24 ) return EditRate_24;
168 if ( picture_rate == 25 ) return EditRate_25;
169 if ( picture_rate == 30 ) return EditRate_30;
170 if ( picture_rate == 48 ) return EditRate_48;
171 if ( picture_rate == 50 ) return EditRate_50;
172 if ( picture_rate == 60 ) return EditRate_60;
173 if ( picture_rate == 96 ) return EditRate_96;
174 if ( picture_rate == 100 ) return EditRate_100;
175 if ( picture_rate == 120 ) return EditRate_120;
176 if ( picture_rate == 192 ) return EditRate_192;
177 if ( picture_rate == 200 ) return EditRate_200;
178 if ( picture_rate == 240 ) return EditRate_240;
183 CommandOptions(int argc, const char** argv) :
184 mode(MMT_EXTRACT), error_flag(true), key_flag(false), read_hmac(false), split_wav(false),
185 mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false),
186 version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6),
187 start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
188 picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
189 channel_fmt(PCM::CF_NONE), input_filename(0), extension("dcdata")
191 memset(key_value, 0, KeyLen);
192 memset(key_id_value, 0, UUIDlen);
194 for ( int i = 1; i < argc; ++i )
197 if ( (strcmp( argv[i], "-help") == 0) )
203 if ( argv[i][0] == '-'
204 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
207 switch ( argv[i][1] )
209 case '1': mono_wav = true; break;
210 case '2': split_wav = true; break;
211 case '3': stereo_image_flag = true; break;
214 TEST_EXTRA_ARG(i, 'b');
215 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
219 TEST_EXTRA_ARG(i, 'd');
220 duration_flag = true;
221 duration = Kumu::xabs(strtol(argv[i], 0, 10));
225 TEST_EXTRA_ARG(i, 'e');
230 TEST_EXTRA_ARG(i, 'f');
231 start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
234 case 'G': mode = MMT_GOP_START; break;
235 case 'h': help_flag = true; break;
237 case 'k': key_flag = true;
238 TEST_EXTRA_ARG(i, 'k');
241 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
243 if ( length != KeyLen )
245 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
251 case 'm': read_hmac = true; break;
254 TEST_EXTRA_ARG(i, 'p');
255 picture_rate = Kumu::xabs(strtol(argv[i], 0, 10));
259 TEST_EXTRA_ARG(i, 's');
260 fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
263 case 'V': version_flag = true; break;
264 case 'v': verbose_flag = true; break;
265 case 'W': no_write_flag = true; break;
268 TEST_EXTRA_ARG(i, 'w');
269 number_width = Kumu::xabs(strtol(argv[i], 0, 10));
272 case 'Z': j2c_pedantic = false; break;
273 case 'z': j2c_pedantic = true; break;
276 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
282 if ( argv[i][0] != '-' )
284 if ( input_filename == 0 )
286 input_filename = argv[i];
288 else if ( file_prefix == 0 )
290 file_prefix = argv[i];
295 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
301 if ( help_flag || version_flag )
304 if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 )
306 fputs("Option requires at least one filename argument.\n", stderr);
310 if ( mode == MMT_EXTRACT && file_prefix == 0 )
312 prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
313 file_prefix = prefix_buffer.c_str();
320 //------------------------------------------------------------------------------------------
323 // Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
324 // Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
325 // Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
328 read_MPEG2_file(CommandOptions& Options)
330 AESDecContext* Context = 0;
331 HMACContext* HMAC = 0;
332 MPEG2::MXFReader Reader;
333 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
334 Kumu::FileWriter OutFile;
335 ui32_t frame_count = 0;
337 Result_t result = Reader.OpenRead(Options.input_filename);
339 if ( ASDCP_SUCCESS(result) )
341 MPEG2::VideoDescriptor VDesc;
342 Reader.FillVideoDescriptor(VDesc);
343 frame_count = VDesc.ContainerDuration;
345 if ( Options.verbose_flag )
347 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
348 MPEG2::VideoDescriptorDump(VDesc);
352 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
355 snprintf(filename, 256, "%s.ves", Options.file_prefix);
356 result = OutFile.OpenWrite(filename);
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 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
387 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
389 if ( ASDCP_SUCCESS(result) )
391 if ( Options.verbose_flag )
392 FrameBuffer.Dump(stderr, Options.fb_dump_size);
394 if ( ! Options.no_write_flag )
396 ui32_t write_count = 0;
397 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
408 gop_start_test(CommandOptions& Options)
410 using namespace ASDCP::MPEG2;
413 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
414 ui32_t frame_count = 0;
416 Result_t result = Reader.OpenRead(Options.input_filename);
418 if ( ASDCP_SUCCESS(result) )
420 MPEG2::VideoDescriptor VDesc;
421 Reader.FillVideoDescriptor(VDesc);
422 frame_count = VDesc.ContainerDuration;
424 if ( Options.verbose_flag )
426 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
427 MPEG2::VideoDescriptorDump(VDesc);
431 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
432 if ( last_frame > frame_count )
433 last_frame = frame_count;
435 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
437 result = Reader.ReadFrameGOPStart(i, FrameBuffer);
439 if ( ASDCP_SUCCESS(result) )
441 if ( Options.verbose_flag )
442 FrameBuffer.Dump(stderr, Options.fb_dump_size);
444 if ( FrameBuffer.FrameType() != FRAME_I )
445 fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType()));
447 fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber());
454 //------------------------------------------------------------------------------------------
458 // Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file
459 // Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
460 // Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
462 read_JP2K_S_file(CommandOptions& Options)
464 AESDecContext* Context = 0;
465 HMACContext* HMAC = 0;
466 JP2K::MXFSReader Reader;
467 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
468 ui32_t frame_count = 0;
470 Result_t result = Reader.OpenRead(Options.input_filename);
472 if ( ASDCP_SUCCESS(result) )
474 JP2K::PictureDescriptor PDesc;
475 Reader.FillPictureDescriptor(PDesc);
477 frame_count = PDesc.ContainerDuration;
479 if ( Options.verbose_flag )
481 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
482 JP2K::PictureDescriptorDump(PDesc);
486 if ( ASDCP_SUCCESS(result) && Options.key_flag )
488 Context = new AESDecContext;
489 result = Context->InitKey(Options.key_value);
491 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
494 Reader.FillWriterInfo(Info);
498 HMAC = new HMACContext;
499 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
503 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
508 const int filename_max = 1024;
509 char filename[filename_max];
510 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
511 if ( last_frame > frame_count )
512 last_frame = frame_count;
514 char left_format[64]; char right_format[64];
515 snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width);
516 snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width);
518 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
520 result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC);
522 if ( ASDCP_SUCCESS(result) )
524 if ( ! Options.no_write_flag )
526 Kumu::FileWriter OutFile;
528 snprintf(filename, filename_max, left_format, Options.file_prefix, i);
529 result = OutFile.OpenWrite(filename);
531 if ( ASDCP_SUCCESS(result) )
532 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
535 if ( Options.verbose_flag )
536 FrameBuffer.Dump(stderr, Options.fb_dump_size);
539 if ( ASDCP_SUCCESS(result) )
540 result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC);
542 if ( ASDCP_SUCCESS(result) )
544 if ( ! Options.no_write_flag )
546 Kumu::FileWriter OutFile;
548 snprintf(filename, filename_max, right_format, Options.file_prefix, i);
549 result = OutFile.OpenWrite(filename);
551 if ( ASDCP_SUCCESS(result) )
552 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
555 if ( Options.verbose_flag )
556 FrameBuffer.Dump(stderr, Options.fb_dump_size);
563 // Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
564 // Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
565 // Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
568 read_JP2K_file(CommandOptions& Options)
570 AESDecContext* Context = 0;
571 HMACContext* HMAC = 0;
572 JP2K::MXFReader Reader;
573 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
574 ui32_t frame_count = 0;
576 Result_t result = Reader.OpenRead(Options.input_filename);
578 if ( ASDCP_SUCCESS(result) )
580 JP2K::PictureDescriptor PDesc;
581 Reader.FillPictureDescriptor(PDesc);
583 frame_count = PDesc.ContainerDuration;
585 if ( Options.verbose_flag )
587 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
588 JP2K::PictureDescriptorDump(PDesc);
592 if ( ASDCP_SUCCESS(result) && Options.key_flag )
594 Context = new AESDecContext;
595 result = Context->InitKey(Options.key_value);
597 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
600 Reader.FillWriterInfo(Info);
604 HMAC = new HMACContext;
605 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
609 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
614 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
615 if ( last_frame > frame_count )
616 last_frame = frame_count;
618 char name_format[64];
619 snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
621 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
623 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
625 if ( ASDCP_SUCCESS(result) )
627 if ( ! Options.no_write_flag )
629 Kumu::FileWriter OutFile;
632 snprintf(filename, 256, name_format, Options.file_prefix, i);
633 result = OutFile.OpenWrite(filename);
635 if ( ASDCP_SUCCESS(result) )
636 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
639 if ( Options.verbose_flag )
640 FrameBuffer.Dump(stderr, Options.fb_dump_size);
647 //------------------------------------------------------------------------------------------
650 // Read one or more plaintext PCM audio streams from a plaintext ASDCP file
651 // Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
652 // Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
655 read_PCM_file(CommandOptions& Options)
657 AESDecContext* Context = 0;
658 HMACContext* HMAC = 0;
659 PCM::MXFReader Reader;
660 PCM::FrameBuffer FrameBuffer;
661 WavFileWriter OutWave;
662 PCM::AudioDescriptor ADesc;
663 ui32_t last_frame = 0;
665 Result_t result = Reader.OpenRead(Options.input_filename);
667 if ( ASDCP_SUCCESS(result) )
669 Reader.FillAudioDescriptor(ADesc);
671 if ( ADesc.EditRate != EditRate_23_98
672 && ADesc.EditRate != EditRate_24
673 && ADesc.EditRate != EditRate_25
674 && ADesc.EditRate != EditRate_30
675 && ADesc.EditRate != EditRate_48
676 && ADesc.EditRate != EditRate_50
677 && ADesc.EditRate != EditRate_60 )
678 ADesc.EditRate = Options.PictureRate();
680 if ( Options.fb_size != FRAME_BUFFER_SIZE )
682 FrameBuffer.Capacity(Options.fb_size);
686 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
689 if ( Options.verbose_flag )
691 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
692 PCM::AudioDescriptorDump(ADesc);
696 if ( ASDCP_SUCCESS(result) )
698 last_frame = ADesc.ContainerDuration;
700 if ( Options.duration > 0 && Options.duration < last_frame )
701 last_frame = Options.duration;
703 if ( Options.start_frame > 0 )
705 if ( Options.start_frame > ADesc.ContainerDuration )
707 fprintf(stderr, "Start value greater than file duration.\n");
711 last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration);
714 ADesc.ContainerDuration = last_frame - Options.start_frame;
716 if ( ! Options.no_write_flag )
718 OutWave.OpenWrite(ADesc, Options.file_prefix,
719 ( Options.split_wav ? WavFileWriter::ST_STEREO :
720 ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
724 if ( ASDCP_SUCCESS(result) && Options.key_flag )
726 Context = new AESDecContext;
727 result = Context->InitKey(Options.key_value);
729 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
732 Reader.FillWriterInfo(Info);
736 HMAC = new HMACContext;
737 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
741 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
746 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
748 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
750 if ( ASDCP_SUCCESS(result) )
752 if ( Options.verbose_flag )
753 FrameBuffer.Dump(stderr, Options.fb_dump_size);
755 if ( ! Options.no_write_flag )
757 result = OutWave.WriteFrame(FrameBuffer);
766 //------------------------------------------------------------------------------------------
769 // Read one or more timed text streams from a plaintext ASDCP file
770 // Read one or more timed text streams from a ciphertext ASDCP file
771 // Read one or more timed text streams from a ciphertext ASDCP file
774 read_timed_text_file(CommandOptions& Options)
776 AESDecContext* Context = 0;
777 HMACContext* HMAC = 0;
778 TimedText::MXFReader Reader;
779 TimedText::FrameBuffer FrameBuffer;
780 TimedText::TimedTextDescriptor TDesc;
782 Result_t result = Reader.OpenRead(Options.input_filename);
784 if ( ASDCP_SUCCESS(result) )
786 Reader.FillTimedTextDescriptor(TDesc);
787 FrameBuffer.Capacity(Options.fb_size);
789 if ( Options.verbose_flag )
790 TimedText::DescriptorDump(TDesc);
793 if ( ASDCP_SUCCESS(result) && Options.key_flag )
795 Context = new AESDecContext;
796 result = Context->InitKey(Options.key_value);
798 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
801 Reader.FillWriterInfo(Info);
805 HMAC = new HMACContext;
806 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
810 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
815 if ( ASDCP_FAILURE(result) )
819 std::string out_path = Kumu::PathDirname(Options.file_prefix);
822 TimedText::ResourceList_t::const_iterator ri;
824 result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC);
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 result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
844 if ( ASDCP_SUCCESS(result) )
845 result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
847 if ( Options.verbose_flag )
848 FrameBuffer.Dump(stderr, Options.fb_dump_size);
855 // Read one or more plaintext DCData bytestreams from a plaintext ASDCP file
856 // Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file
857 // Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file
860 read_DCData_file(CommandOptions& Options)
862 AESDecContext* Context = 0;
863 HMACContext* HMAC = 0;
864 DCData::MXFReader Reader;
865 DCData::FrameBuffer FrameBuffer(Options.fb_size);
866 ui32_t frame_count = 0;
868 Result_t result = Reader.OpenRead(Options.input_filename);
870 if ( ASDCP_SUCCESS(result) )
872 DCData::DCDataDescriptor DDesc;
873 Reader.FillDCDataDescriptor(DDesc);
875 frame_count = DDesc.ContainerDuration;
877 if ( Options.verbose_flag )
879 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
880 DCData::DCDataDescriptorDump(DDesc);
884 if ( ASDCP_SUCCESS(result) && Options.key_flag )
886 Context = new AESDecContext;
887 result = Context->InitKey(Options.key_value);
889 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
892 Reader.FillWriterInfo(Info);
896 HMAC = new HMACContext;
897 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
901 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
906 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
907 if ( last_frame > frame_count )
908 last_frame = frame_count;
910 char name_format[64];
911 snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension);
913 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
915 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
917 if ( ASDCP_SUCCESS(result) )
919 if ( ! Options.no_write_flag )
921 Kumu::FileWriter OutFile;
924 snprintf(filename, 256, name_format, Options.file_prefix, i);
925 result = OutFile.OpenWrite(filename);
927 if ( ASDCP_SUCCESS(result) )
928 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
931 if ( Options.verbose_flag )
932 FrameBuffer.Dump(stderr, Options.fb_dump_size);
941 main(int argc, const char** argv)
943 Result_t result = RESULT_OK;
945 CommandOptions Options(argc, argv);
947 if ( Options.version_flag )
950 if ( Options.help_flag )
953 if ( Options.version_flag || Options.help_flag )
956 if ( Options.error_flag )
958 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
962 if ( Options.mode == MMT_GOP_START )
964 result = gop_start_test(Options);
966 else if ( Options.mode == MMT_EXTRACT )
968 EssenceType_t EssenceType;
969 result = ASDCP::EssenceType(Options.input_filename, EssenceType);
971 if ( ASDCP_SUCCESS(result) )
973 switch ( EssenceType )
976 result = read_MPEG2_file(Options);
980 if ( Options.stereo_image_flag )
981 result = read_JP2K_S_file(Options);
983 result = read_JP2K_file(Options);
986 case ESS_JPEG_2000_S:
987 result = read_JP2K_S_file(Options);
990 case ESS_PCM_24b_48k:
991 case ESS_PCM_24b_96k:
992 result = read_PCM_file(Options);
996 result = read_timed_text_file(Options);
999 case ESS_DCDATA_UNKNOWN:
1000 result = read_DCData_file(Options);
1003 case ESS_DCDATA_DOLBY_ATMOS:
1004 Options.extension = "atmos";
1005 result = read_DCData_file(Options);
1009 fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
1016 fprintf(stderr, "Unhandled mode: %d.\n", Options.mode);
1020 if ( ASDCP_FAILURE(result) )
1022 fputs("Program stopped on error.\n", stderr);
1024 if ( result == RESULT_SFORMAT )
1026 fputs("Use option '-3' to force stereoscopic mode.\n", stderr);
1028 else if ( result != RESULT_FAIL )
1030 fputs(result, stderr);
1031 fputc('\n', stderr);
1042 // end asdcp-unwrap.cpp