X-Git-Url: https://git.carlh.net/gitweb/?a=blobdiff_plain;f=src%2Fasdcp-unwrap.cpp;h=a24219f0d7fb50119003e964d13766b8a0eaca53;hb=5f38f82f9bfc69fdbae47a71f587ab5b7e80e594;hp=55d291be073070c2b783bf808dc3b6f6052a8a83;hpb=e0f46a5384974afa6f0be8a738e4989853323fbe;p=asdcplib.git diff --git a/src/asdcp-unwrap.cpp b/src/asdcp-unwrap.cpp index 55d291b..a24219f 100755 --- a/src/asdcp-unwrap.cpp +++ b/src/asdcp-unwrap.cpp @@ -1,5 +1,5 @@ /* -Copyright (c) 2003-2012, John Hurst +Copyright (c) 2003-2016, John Hurst All rights reserved. Redistribution and use in source and binary forms, with or without @@ -25,7 +25,7 @@ THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ /*! \file asdcp-unwrap.cpp - \version $Id$ + \version $Id$ \brief AS-DCP file manipulation utility This program extracts picture, sound and text essence from AS-DCP files. @@ -61,7 +61,7 @@ banner(FILE* stream = stdout) { fprintf(stream, "\n\ %s (asdcplib %s)\n\n\ -Copyright (c) 2003-2012 John Hurst\n\n\ +Copyright (c) 2003-2015 John Hurst\n\n\ asdcplib may be copied only under the terms of the license found at\n\ the top of every file in the asdcplib distribution kit.\n\n\ Specify the -h (help) option for further information about %s\n\n", @@ -89,22 +89,23 @@ Options:\n\ -2 - Split Wave essence to stereo WAV files during extract.\n\ Default is multichannel WAV\n\ -3 - Force stereoscopic interpretation of a JP2K file.\n\ - -b - Specify size in bytes of picture frame buffer.\n\ + -b - Specify size in bytes of picture frame buffer\n\ Defaults to 4,194,304 (4MB)\n\ -d - Number of frames to process, default all\n\ - -f - Starting frame number, default 0\n\ + -e - Extension to use for Unknown D-Cinema Data files. default dcdata\n\ + -f - Starting frame number, default 0\n \ -G - Perform GOP start lookup test on MXF+Interop MPEG file\n\ -h | -help - Show help\n\ -k - Use key for ciphertext operations\n\ -m - verify HMAC values when reading\n\ - -p - fps of picture when wrapping PCM or JP2K:\n\ + -p - Alternative picture rate when unwrapping PCM:\n\ Use one of [23|24|25|30|48|50|60], 24 is default\n\ -s - Number of bytes to dump to output when -v is given\n\ -V - Show version information\n\ -v - Verbose, prints informative messages to stderr\n\ -W - Read input file only, do not write destination file\n\ -w - Width of numeric element in a series of frame file names\n\ - (default 6).\n\ + (default 6)\n\ -z - Fail if j2c inputs have unequal parameters (default)\n\ -Z - Ignore unequal parameters in j2c inputs\n\ \n\ @@ -153,10 +154,15 @@ public: PCM::ChannelFormat_t channel_fmt; // audio channel arrangement const char* input_filename; std::string prefix_buffer; + const char* extension; // file extension to use for unknown D-Cinema Data track files. // Rational PictureRate() { + if ( picture_rate == 16 ) return EditRate_16; + if ( picture_rate == 18 ) return EditRate_18; + if ( picture_rate == 20 ) return EditRate_20; + if ( picture_rate == 22 ) return EditRate_22; if ( picture_rate == 23 ) return EditRate_23_98; if ( picture_rate == 24 ) return EditRate_24; if ( picture_rate == 25 ) return EditRate_25; @@ -167,6 +173,9 @@ public: if ( picture_rate == 96 ) return EditRate_96; if ( picture_rate == 100 ) return EditRate_100; if ( picture_rate == 120 ) return EditRate_120; + if ( picture_rate == 192 ) return EditRate_192; + if ( picture_rate == 200 ) return EditRate_200; + if ( picture_rate == 240 ) return EditRate_240; return EditRate_24; } @@ -177,7 +186,7 @@ public: version_flag(false), help_flag(false), stereo_image_flag(false), number_width(6), start_frame(0), duration(0xffffffff), duration_flag(false), j2c_pedantic(true), picture_rate(24), fb_size(FRAME_BUFFER_SIZE), file_prefix(0), - channel_fmt(PCM::CF_NONE), input_filename(0) + channel_fmt(PCM::CF_NONE), input_filename(0), extension("dcdata") { memset(key_value, 0, KeyLen); memset(key_id_value, 0, UUIDlen); @@ -190,7 +199,7 @@ public: help_flag = true; continue; } - + if ( argv[i][0] == '-' && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) ) && argv[i][2] == 0 ) @@ -203,37 +212,52 @@ public: case 'b': TEST_EXTRA_ARG(i, 'b'); - fb_size = abs(atoi(argv[i])); - - if ( verbose_flag ) - fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size); - + fb_size = Kumu::xabs(strtol(argv[i], 0, 10)); break; case 'd': TEST_EXTRA_ARG(i, 'd'); duration_flag = true; - duration = abs(atoi(argv[i])); + duration = Kumu::xabs(strtol(argv[i], 0, 10)); + break; + + case 'e': + TEST_EXTRA_ARG(i, 'e'); + extension = argv[i]; break; case 'f': TEST_EXTRA_ARG(i, 'f'); - start_frame = abs(atoi(argv[i])); + start_frame = Kumu::xabs(strtol(argv[i], 0, 10)); break; case 'G': mode = MMT_GOP_START; break; case 'h': help_flag = true; break; + case 'k': key_flag = true; + TEST_EXTRA_ARG(i, 'k'); + { + ui32_t length; + Kumu::hex2bin(argv[i], key_value, KeyLen, &length); + + if ( length != KeyLen ) + { + fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen); + return; + } + } + break; + case 'm': read_hmac = true; break; case 'p': TEST_EXTRA_ARG(i, 'p'); - picture_rate = abs(atoi(argv[i])); + picture_rate = Kumu::xabs(strtol(argv[i], 0, 10)); break; case 's': TEST_EXTRA_ARG(i, 's'); - fb_dump_size = abs(atoi(argv[i])); + fb_dump_size = Kumu::xabs(strtol(argv[i], 0, 10)); break; case 'V': version_flag = true; break; @@ -242,7 +266,7 @@ public: case 'w': TEST_EXTRA_ARG(i, 'w'); - number_width = abs(atoi(argv[i])); + number_width = Kumu::xabs(strtol(argv[i], 0, 10)); break; case 'Z': j2c_pedantic = false; break; @@ -276,7 +300,7 @@ public: if ( help_flag || version_flag ) return; - + if ( ( mode == MMT_EXTRACT || mode == MMT_GOP_START ) && input_filename == 0 ) { fputs("Option requires at least one filename argument.\n", stderr); @@ -325,7 +349,7 @@ read_MPEG2_file(CommandOptions& Options) } } - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { char filename[256]; snprintf(filename, 256, "%s.ves", Options.file_prefix); @@ -367,10 +391,13 @@ read_MPEG2_file(CommandOptions& Options) if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); + if ( ! Options.no_write_flag ) + { ui32_t write_count = 0; result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); } } + } return result; } @@ -494,6 +521,8 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { + if ( ! Options.no_write_flag ) + { Kumu::FileWriter OutFile; ui32_t write_count; snprintf(filename, filename_max, left_format, Options.file_prefix, i); @@ -501,6 +530,7 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); @@ -511,6 +541,8 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { + if ( ! Options.no_write_flag ) + { Kumu::FileWriter OutFile; ui32_t write_count; snprintf(filename, filename_max, right_format, Options.file_prefix, i); @@ -519,6 +551,10 @@ read_JP2K_S_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } } return result; @@ -588,6 +624,8 @@ read_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) { + if ( ! Options.no_write_flag ) + { Kumu::FileWriter OutFile; char filename[256]; ui32_t write_count; @@ -596,6 +634,7 @@ read_JP2K_file(CommandOptions& Options) if ( ASDCP_SUCCESS(result) ) result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); @@ -638,11 +677,21 @@ read_PCM_file(CommandOptions& Options) && ADesc.EditRate != EditRate_60 ) ADesc.EditRate = Options.PictureRate(); + if ( Options.fb_size != FRAME_BUFFER_SIZE ) + { + FrameBuffer.Capacity(Options.fb_size); + } + else + { FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc)); + } if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); PCM::AudioDescriptorDump(ADesc); } + } if ( ASDCP_SUCCESS(result) ) { @@ -663,10 +712,14 @@ read_PCM_file(CommandOptions& Options) } ADesc.ContainerDuration = last_frame - Options.start_frame; + + if ( ! Options.no_write_flag ) + { OutWave.OpenWrite(ADesc, Options.file_prefix, - ( Options.split_wav ? WavFileWriter::ST_STEREO : + ( Options.split_wav ? WavFileWriter::ST_STEREO : ( Options.mono_wav ? WavFileWriter::ST_MONO : WavFileWriter::ST_NONE ) )); } + } if ( ASDCP_SUCCESS(result) && Options.key_flag ) { @@ -699,9 +752,12 @@ read_PCM_file(CommandOptions& Options) if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); + if ( ! Options.no_write_flag ) + { result = OutWave.WriteFrame(FrameBuffer); } } + } return result; } @@ -767,7 +823,7 @@ read_timed_text_file(CommandOptions& Options) result = Reader.ReadTimedTextResource(XMLDoc, Context, HMAC); - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { Kumu::FileWriter Writer; result = Writer.OpenWrite(Options.file_prefix); @@ -780,21 +836,103 @@ read_timed_text_file(CommandOptions& Options) { result = Reader.ReadAncillaryResource(ri->ResourceID, FrameBuffer, Context, HMAC); - if ( ASDCP_SUCCESS(result) ) + if ( ASDCP_SUCCESS(result) && ( ! Options.no_write_flag ) ) { Kumu::FileWriter Writer; result = Writer.OpenWrite(Kumu::PathJoin(out_path, Kumu::UUID(ri->ResourceID).EncodeHex(buf, 64)).c_str()); if ( ASDCP_SUCCESS(result) ) - { + result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); + if ( Options.verbose_flag ) FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + } + + return result; +} + +// Read one or more plaintext DCData bytestreams from a plaintext ASDCP file +// Read one or more plaintext DCData bytestreams from a ciphertext ASDCP file +// Read one or more ciphertext DCData byestreams from a ciphertext ASDCP file +// +Result_t +read_DCData_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + DCData::MXFReader Reader; + DCData::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if ( ASDCP_SUCCESS(result) ) + { + DCData::DCDataDescriptor DDesc; + Reader.FillDCDataDescriptor(DDesc); + + frame_count = DDesc.ContainerDuration; - result = Writer.Write(FrameBuffer.RoData(), FrameBuffer.Size(), &write_count); + if ( Options.verbose_flag ) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + DCData::DCDataDescriptorDump(DDesc); + } + } + + if ( ASDCP_SUCCESS(result) && Options.key_flag ) + { + Context = new AESDecContext; + result = Context->InitKey(Options.key_value); + + if ( ASDCP_SUCCESS(result) && Options.read_hmac ) + { + WriterInfo Info; + Reader.FillWriterInfo(Info); + + if ( Info.UsesHMAC ) + { + HMAC = new HMACContext; + result = HMAC->InitKey(Options.key_value, Info.LabelSetType); + } + else + { + fputs("File does not contain HMAC values, ignoring -m option.\n", stderr); } } } + ui32_t last_frame = Options.start_frame + ( Options.duration ? Options.duration : frame_count); + if ( last_frame > frame_count ) + last_frame = frame_count; + + char name_format[64]; + snprintf(name_format, 64, "%%s%%0%du.%s", Options.number_width, Options.extension); + + for ( ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++ ) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + if ( ASDCP_SUCCESS(result) ) + { + if ( ! Options.no_write_flag ) + { + Kumu::FileWriter OutFile; + char filename[256]; + ui32_t write_count; + snprintf(filename, 256, name_format, Options.file_prefix, i); + result = OutFile.OpenWrite(filename); + + if ( ASDCP_SUCCESS(result) ) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + } + + if ( Options.verbose_flag ) + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + } + return result; } @@ -858,6 +996,15 @@ main(int argc, const char** argv) result = read_timed_text_file(Options); break; + case ESS_DCDATA_UNKNOWN: + result = read_DCData_file(Options); + break; + + case ESS_DCDATA_DOLBY_ATMOS: + Options.extension = "atmos"; + result = read_DCData_file(Options); + break; + default: fprintf(stderr, "%s: Unknown file type, not ASDCP essence.\n", Options.input_filename); return 5;