2 Copyright (c) 2003-2014, John Hurst
5 Redistribution and use in source and binary forms, with or without
6 modification, are permitted provided that the following conditions
8 1. Redistributions of source code must retain the above copyright
9 notice, this list of conditions and the following disclaimer.
10 2. Redistributions in binary form must reproduce the above copyright
11 notice, this list of conditions and the following disclaimer in the
12 documentation and/or other materials provided with the distribution.
13 3. The name of the author may not be used to endorse or promote products
14 derived from this software without specific prior written permission.
16 THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
17 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
18 OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
19 IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
20 INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
21 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
22 DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
23 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
24 (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
25 THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
27 /*! \file asdcp-unwrap.cpp
28 \version $Id: asdcp-unwrap.cpp,v 1.7 2015/10/07 16:41:23 jhurst Exp $
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> - fps of picture when wrapping PCM or JP2K:\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;
180 CommandOptions(int argc, const char** argv) :
181 mode(MMT_EXTRACT), error_flag(true), key_flag(false), read_hmac(false), split_wav(false),
182 mono_wav(false), verbose_flag(false), fb_dump_size(0), no_write_flag(false),
183 version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6),
184 start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true),
185 picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0),
186 channel_fmt(PCM::CF_NONE), input_filename(0), extension("dcdata")
188 memset(key_value, 0, KeyLen);
189 memset(key_id_value, 0, UUIDlen);
191 for ( int i = 1; i < argc; ++i )
194 if ( (strcmp( argv[i], "-help") == 0) )
200 if ( argv[i][0] == '-'
201 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
204 switch ( argv[i][1] )
206 case '1': mono_wav = true; break;
207 case '2': split_wav = true; break;
208 case '3': stereo_image_flag = true; break;
211 TEST_EXTRA_ARG(i, 'b');
212 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
216 TEST_EXTRA_ARG(i, 'd');
217 duration_flag = true;
218 duration = Kumu::xabs(strtol(argv[i], 0, 10));
222 TEST_EXTRA_ARG(i, 'e');
227 TEST_EXTRA_ARG(i, 'f');
228 start_frame = Kumu::xabs(strtol(argv[i], 0, 10));
231 case 'G': mode = MMT_GOP_START; break;
232 case 'h': help_flag = true; break;
234 case 'k': key_flag = true;
235 TEST_EXTRA_ARG(i, 'k');
238 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
240 if ( length != KeyLen )
242 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
248 case 'm': read_hmac = true; break;
251 TEST_EXTRA_ARG(i, 'p');
252 picture_rate = Kumu::xabs(strtol(argv[i], 0, 10));
256 TEST_EXTRA_ARG(i, 's');
257 fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10));
260 case 'V': version_flag = true; break;
261 case 'v': verbose_flag = true; break;
262 case 'W': no_write_flag = true; break;
265 TEST_EXTRA_ARG(i, 'w');
266 number_width = Kumu::xabs(strtol(argv[i], 0, 10));
269 case 'Z': j2c_pedantic = false; break;
270 case 'z': j2c_pedantic = true; break;
273 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
279 if ( argv[i][0] != '-' )
281 if ( input_filename == 0 )
283 input_filename = argv[i];
285 else if ( file_prefix == 0 )
287 file_prefix = argv[i];
292 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
298 if ( help_flag || version_flag )
301 if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 )
303 fputs("Option requires at least one filename argument.\n", stderr);
307 if ( mode == MMT_EXTRACT && file_prefix == 0 )
309 prefix_buffer = Kumu::PathSetExtension(input_filename, "") + "_";
310 file_prefix = prefix_buffer.c_str();
317 //------------------------------------------------------------------------------------------
320 // Read a plaintext MPEG2 Video Elementary Stream from a plaintext ASDCP file
321 // Read a plaintext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
322 // Read a ciphertext MPEG2 Video Elementary Stream from a ciphertext ASDCP file
325 read_MPEG2_file(CommandOptions& Options)
327 AESDecContext* Context = 0;
328 HMACContext* HMAC = 0;
329 MPEG2::MXFReader Reader;
330 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
331 Kumu::FileWriter OutFile;
332 ui32_t frame_count = 0;
334 Result_t result = Reader.OpenRead(Options.input_filename);
336 if ( ASDCP_SUCCESS(result) )
338 MPEG2::VideoDescriptor VDesc;
339 Reader.FillVideoDescriptor(VDesc);
340 frame_count = VDesc.ContainerDuration;
342 if ( Options.verbose_flag )
344 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
345 MPEG2::VideoDescriptorDump(VDesc);
349 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
352 snprintf(filename, 256, "%s.ves", Options.file_prefix);
353 result = OutFile.OpenWrite(filename);
356 if ( ASDCP_SUCCESS(result) && Options.key_flag )
358 Context = new AESDecContext;
359 result = Context->InitKey(Options.key_value);
361 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
364 Reader.FillWriterInfo(Info);
368 HMAC = new HMACContext;
369 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
373 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
378 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
379 if ( last_frame > frame_count )
380 last_frame = frame_count;
382 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
384 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
386 if ( ASDCP_SUCCESS(result) )
388 if ( Options.verbose_flag )
389 FrameBuffer.Dump(stderr, Options.fb_dump_size);
391 if ( ! Options.no_write_flag )
393 ui32_t write_count = 0;
394 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
405 gop_start_test(CommandOptions& Options)
407 using namespace ASDCP::MPEG2;
410 MPEG2::FrameBuffer FrameBuffer(Options.fb_size);
411 ui32_t frame_count = 0;
413 Result_t result = Reader.OpenRead(Options.input_filename);
415 if ( ASDCP_SUCCESS(result) )
417 MPEG2::VideoDescriptor VDesc;
418 Reader.FillVideoDescriptor(VDesc);
419 frame_count = VDesc.ContainerDuration;
421 if ( Options.verbose_flag )
423 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
424 MPEG2::VideoDescriptorDump(VDesc);
428 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
429 if ( last_frame > frame_count )
430 last_frame = frame_count;
432 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
434 result = Reader.ReadFrameGOPStart(i, FrameBuffer);
436 if ( ASDCP_SUCCESS(result) )
438 if ( Options.verbose_flag )
439 FrameBuffer.Dump(stderr, Options.fb_dump_size);
441 if ( FrameBuffer.FrameType() != FRAME_I )
442 fprintf(stderr, "Expecting an I frame, got %c\n", FrameTypeChar(FrameBuffer.FrameType()));
444 fprintf(stderr, "Requested frame %u, got %u\n", i, FrameBuffer.FrameNumber());
451 //------------------------------------------------------------------------------------------
455 // Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a plaintext ASDCP file
456 // Read one or more plaintext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
457 // Read one or more ciphertext JPEG 2000 stereoscopic codestream pairs from a ciphertext ASDCP file
459 read_JP2K_S_file(CommandOptions& Options)
461 AESDecContext* Context = 0;
462 HMACContext* HMAC = 0;
463 JP2K::MXFSReader Reader;
464 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
465 ui32_t frame_count = 0;
467 Result_t result = Reader.OpenRead(Options.input_filename);
469 if ( ASDCP_SUCCESS(result) )
471 JP2K::PictureDescriptor PDesc;
472 Reader.FillPictureDescriptor(PDesc);
474 frame_count = PDesc.ContainerDuration;
476 if ( Options.verbose_flag )
478 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
479 JP2K::PictureDescriptorDump(PDesc);
483 if ( ASDCP_SUCCESS(result) && Options.key_flag )
485 Context = new AESDecContext;
486 result = Context->InitKey(Options.key_value);
488 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
491 Reader.FillWriterInfo(Info);
495 HMAC = new HMACContext;
496 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
500 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
505 const int filename_max = 1024;
506 char filename[filename_max];
507 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
508 if ( last_frame > frame_count )
509 last_frame = frame_count;
511 char left_format[64]; char right_format[64];
512 snprintf(left_format, 64, "%%s%%0%duL.j2c", Options.number_width);
513 snprintf(right_format, 64, "%%s%%0%duR.j2c", Options.number_width);
515 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
517 result = Reader.ReadFrame(i, JP2K::SP_LEFT, FrameBuffer, Context, HMAC);
519 if ( ASDCP_SUCCESS(result) )
521 if ( ! Options.no_write_flag )
523 Kumu::FileWriter OutFile;
525 snprintf(filename, filename_max, left_format, Options.file_prefix, i);
526 result = OutFile.OpenWrite(filename);
528 if ( ASDCP_SUCCESS(result) )
529 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
532 if ( Options.verbose_flag )
533 FrameBuffer.Dump(stderr, Options.fb_dump_size);
536 if ( ASDCP_SUCCESS(result) )
537 result = Reader.ReadFrame(i, JP2K::SP_RIGHT, FrameBuffer, Context, HMAC);
539 if ( ASDCP_SUCCESS(result) )
541 if ( ! Options.no_write_flag )
543 Kumu::FileWriter OutFile;
545 snprintf(filename, filename_max, right_format, Options.file_prefix, i);
546 result = OutFile.OpenWrite(filename);
548 if ( ASDCP_SUCCESS(result) )
549 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
552 if ( Options.verbose_flag )
553 FrameBuffer.Dump(stderr, Options.fb_dump_size);
560 // Read one or more plaintext JPEG 2000 codestreams from a plaintext ASDCP file
561 // Read one or more plaintext JPEG 2000 codestreams from a ciphertext ASDCP file
562 // Read one or more ciphertext JPEG 2000 codestreams from a ciphertext ASDCP file
565 read_JP2K_file(CommandOptions& Options)
567 AESDecContext* Context = 0;
568 HMACContext* HMAC = 0;
569 JP2K::MXFReader Reader;
570 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
571 ui32_t frame_count = 0;
573 Result_t result = Reader.OpenRead(Options.input_filename);
575 if ( ASDCP_SUCCESS(result) )
577 JP2K::PictureDescriptor PDesc;
578 Reader.FillPictureDescriptor(PDesc);
580 frame_count = PDesc.ContainerDuration;
582 if ( Options.verbose_flag )
584 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
585 JP2K::PictureDescriptorDump(PDesc);
589 if ( ASDCP_SUCCESS(result) && Options.key_flag )
591 Context = new AESDecContext;
592 result = Context->InitKey(Options.key_value);
594 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
597 Reader.FillWriterInfo(Info);
601 HMAC = new HMACContext;
602 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
606 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
611 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
612 if ( last_frame > frame_count )
613 last_frame = frame_count;
615 char name_format[64];
616 snprintf(name_format, 64, "%%s%%0%du.j2c", Options.number_width);
618 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
620 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
622 if ( ASDCP_SUCCESS(result) )
624 if ( ! Options.no_write_flag )
626 Kumu::FileWriter OutFile;
629 snprintf(filename, 256, name_format, Options.file_prefix, i);
630 result = OutFile.OpenWrite(filename);
632 if ( ASDCP_SUCCESS(result) )
633 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
636 if ( Options.verbose_flag )
637 FrameBuffer.Dump(stderr, Options.fb_dump_size);
644 //------------------------------------------------------------------------------------------
647 // Read one or more plaintext PCM audio streams from a plaintext ASDCP file
648 // Read one or more plaintext PCM audio streams from a ciphertext ASDCP file
649 // Read one or more ciphertext PCM audio streams from a ciphertext ASDCP file
652 read_PCM_file(CommandOptions& Options)
654 AESDecContext* Context = 0;
655 HMACContext* HMAC = 0;
656 PCM::MXFReader Reader;
657 PCM::FrameBuffer FrameBuffer;
658 WavFileWriter OutWave;
659 PCM::AudioDescriptor ADesc;
660 ui32_t last_frame = 0;
662 Result_t result = Reader.OpenRead(Options.input_filename);
664 if ( ASDCP_SUCCESS(result) )
666 Reader.FillAudioDescriptor(ADesc);
668 if ( ADesc.EditRate != EditRate_23_98
669 && ADesc.EditRate != EditRate_24
670 && ADesc.EditRate != EditRate_25
671 && ADesc.EditRate != EditRate_30
672 && ADesc.EditRate != EditRate_48
673 && ADesc.EditRate != EditRate_50
674 && ADesc.EditRate != EditRate_60 )
675 ADesc.EditRate = Options.PictureRate();
677 if ( Options.fb_size != FRAME_BUFFER_SIZE )
679 FrameBuffer.Capacity(Options.fb_size);
683 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
686 if ( Options.verbose_flag )
688 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
689 PCM::AudioDescriptorDump(ADesc);
693 if ( ASDCP_SUCCESS(result) )
695 last_frame = ADesc.ContainerDuration;
697 if ( Options.duration > 0 && Options.duration < last_frame )
698 last_frame = Options.duration;
700 if ( Options.start_frame > 0 )
702 if ( Options.start_frame > ADesc.ContainerDuration )
704 fprintf(stderr, "Start value greater than file duration.\n");
708 last_frame = Kumu::xmin(Options.start_frame + last_frame, ADesc.ContainerDuration);
711 ADesc.ContainerDuration = last_frame - Options.start_frame;
713 if ( ! Options.no_write_flag )
715 OutWave.OpenWrite(ADesc, Options.file_prefix,
716 ( Options.split_wav ? WavFileWriter::ST_STEREO :
717 ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) ));
721 if ( ASDCP_SUCCESS(result) && Options.key_flag )
723 Context = new AESDecContext;
724 result = Context->InitKey(Options.key_value);
726 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
729 Reader.FillWriterInfo(Info);
733 HMAC = new HMACContext;
734 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
738 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
743 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
745 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
747 if ( ASDCP_SUCCESS(result) )
749 if ( Options.verbose_flag )
750 FrameBuffer.Dump(stderr, Options.fb_dump_size);
752 if ( ! Options.no_write_flag )
754 result = OutWave.WriteFrame(FrameBuffer);
763 //------------------------------------------------------------------------------------------
766 // Read one or more timed text streams from a plaintext ASDCP file
767 // Read one or more timed text streams from a ciphertext ASDCP file
768 // Read one or more timed text streams from a ciphertext ASDCP file
771 read_timed_text_file(CommandOptions& Options)
773 AESDecContext* Context = 0;
774 HMACContext* HMAC = 0;
775 TimedText::MXFReader Reader;
776 TimedText::FrameBuffer FrameBuffer;
777 TimedText::TimedTextDescriptor TDesc;
779 Result_t result = Reader.OpenRead(Options.input_filename);
781 if ( ASDCP_SUCCESS(result) )
783 Reader.FillTimedTextDescriptor(TDesc);
784 FrameBuffer.Capacity(Options.fb_size);
786 if ( Options.verbose_flag )
787 TimedText::DescriptorDump(TDesc);
790 if ( ASDCP_SUCCESS(result) && Options.key_flag )
792 Context = new AESDecContext;
793 result = Context->InitKey(Options.key_value);
795 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
798 Reader.FillWriterInfo(Info);
802 HMAC = new HMACContext;
803 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
807 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
812 if ( ASDCP_FAILURE(result) )
816 std::string out_path = Kumu::PathDirname(Options.file_prefix);
819 TimedText::ResourceList_t::const_iterator ri;
821 result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC);
823 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
825 Kumu::FileWriter Writer;
826 result = Writer.OpenWrite(Options.file_prefix);
828 if ( ASDCP_SUCCESS(result) )
829 result = Writer.Write(reinterpret_cast<const byte_t*>(XMLDoc.c_str()), XMLDoc.size(), &write_count);
832 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
834 result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC);
836 if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) )
838 Kumu::FileWriter Writer;
839 result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str());
841 if ( ASDCP_SUCCESS(result) )
842 result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count);
844 if ( Options.verbose_flag )
845 FrameBuffer.Dump(stderr, Options.fb_dump_size);
852 // Read one or more plaintext DCData bytestreams from a plaintext ASDCP file
853 // Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file
854 // Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file
857 read_DCData_file(CommandOptions& Options)
859 AESDecContext* Context = 0;
860 HMACContext* HMAC = 0;
861 DCData::MXFReader Reader;
862 DCData::FrameBuffer FrameBuffer(Options.fb_size);
863 ui32_t frame_count = 0;
865 Result_t result = Reader.OpenRead(Options.input_filename);
867 if ( ASDCP_SUCCESS(result) )
869 DCData::DCDataDescriptor DDesc;
870 Reader.FillDCDataDescriptor(DDesc);
872 frame_count = DDesc.ContainerDuration;
874 if ( Options.verbose_flag )
876 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
877 DCData::DCDataDescriptorDump(DDesc);
881 if ( ASDCP_SUCCESS(result) && Options.key_flag )
883 Context = new AESDecContext;
884 result = Context->InitKey(Options.key_value);
886 if ( ASDCP_SUCCESS(result) && Options.read_hmac )
889 Reader.FillWriterInfo(Info);
893 HMAC = new HMACContext;
894 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
898 fputs("File does not contain HMAC values, ignoring -m option.\n", stderr);
903 ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count);
904 if ( last_frame > frame_count )
905 last_frame = frame_count;
907 char name_format[64];
908 snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension);
910 for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ )
912 result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC);
914 if ( ASDCP_SUCCESS(result) )
916 if ( ! Options.no_write_flag )
918 Kumu::FileWriter OutFile;
921 snprintf(filename, 256, name_format, Options.file_prefix, i);
922 result = OutFile.OpenWrite(filename);
924 if ( ASDCP_SUCCESS(result) )
925 result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count);
928 if ( Options.verbose_flag )
929 FrameBuffer.Dump(stderr, Options.fb_dump_size);
938 main(int argc, const char** argv)
940 Result_t result = RESULT_OK;
942 CommandOptions Options(argc, argv);
944 if ( Options.version_flag )
947 if ( Options.help_flag )
950 if ( Options.version_flag || Options.help_flag )
953 if ( Options.error_flag )
955 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
959 if ( Options.mode == MMT_GOP_START )
961 result = gop_start_test(Options);
963 else if ( Options.mode == MMT_EXTRACT )
965 EssenceType_t EssenceType;
966 result = ASDCP::EssenceType(Options.input_filename, EssenceType);
968 if ( ASDCP_SUCCESS(result) )
970 switch ( EssenceType )
973 result = read_MPEG2_file(Options);
977 if ( Options.stereo_image_flag )
978 result = read_JP2K_S_file(Options);
980 result = read_JP2K_file(Options);
983 case ESS_JPEG_2000_S:
984 result = read_JP2K_S_file(Options);
987 case ESS_PCM_24b_48k:
988 case ESS_PCM_24b_96k:
989 result = read_PCM_file(Options);
993 result = read_timed_text_file(Options);
996 case ESS_DCDATA_UNKNOWN:
997 result = read_DCData_file(Options);
1000 case ESS_DCDATA_DOLBY_ATMOS:
1001 Options.extension = "atmos";
1002 result = read_DCData_file(Options);
1006 fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename);
1013 fprintf(stderr, "Unhandled mode: %d.\n", Options.mode);
1017 if ( ASDCP_FAILURE(result) )
1019 fputs("Program stopped on error.\n", stderr);
1021 if ( result == RESULT_SFORMAT )
1023 fputs("Use option '-3' to force stereoscopic mode.\n", stderr);
1025 else if ( result != RESULT_FAIL )
1027 fputs(result, stderr);
1028 fputc('\n', stderr);
1039 // end asdcp-unwrap.cpp