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-wrap.cpp
31 \brief AS-02 file manipulation utility
33 This program wraps IMF essence (picture or sound) in to an AS-02 MXF file.
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>
43 #include <PCMParserList.h>
46 using namespace ASDCP;
48 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
49 const ASDCP::Dictionary *g_dict = 0;
52 RationalToString(const ASDCP::Rational& r, char* buf, const ui32_t& len)
54 snprintf(buf, len, "%d/%d", r.Numerator, r.Denominator);
59 //------------------------------------------------------------------------------------------
61 // command line option parser class
63 static const char* PROGRAM_NAME = "as-02-wrap"; // program name for messages
65 // local program identification info written to file headers
66 class MyInfo : public WriterInfo
71 static byte_t default_ProductUUID_Data[UUIDlen] =
72 { 0x7d, 0x83, 0x6e, 0x16, 0x37, 0xc7, 0x4c, 0x22,
73 0xb2, 0xe0, 0x46, 0xa7, 0x17, 0xe8, 0x4f, 0x42 };
75 memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
76 CompanyName = "WidgetCo";
77 ProductName = "as-02-wrap";
78 ProductVersion = ASDCP::Version();
84 // Increment the iterator, test for an additional non-option command line argument.
85 // Causes the caller to return if there are no remaining arguments or if the next
86 // argument begins with '-'.
87 #define TEST_EXTRA_ARG(i,c) \
88 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
89 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
96 create_random_uuid(byte_t* uuidbuf)
99 GenRandomValue(tmp_id);
100 memcpy(uuidbuf, tmp_id.Value(), tmp_id.Size());
105 banner(FILE* stream = stdout)
108 %s (asdcplib %s)\n\n\
109 Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
110 asdcplib may be copied only under the terms of the license found at\n\
111 the top of every file in the asdcplib distribution kit.\n\n\
112 Specify the -h (help) option for further information about %s\n\n",
113 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
118 usage(FILE* stream = stdout)
121 USAGE: %s [-h|-help] [-V]\n\
123 %s [options] <input-file>+ <output-file>\n\n",
124 PROGRAM_NAME, PROGRAM_NAME);
128 -h | -help - Show help\n\
129 -V - Show version information\n\
130 -a <uuid> - Specify the Asset ID of the file\n\
131 -A <w>/<h> - Set aspect ratio for image (default 4/3)\n\
132 -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
133 Defaults to 4,194,304 (4MB)\n\
134 -c <num> - Select the IMF color system to be signaled:\n\
135 Application 2 (2067-20): 1, 2, or 3\n\
136 Application 2e (2067-21): 4 or 5\n\
137 All color system values assume YCbCr; also use -R for RGB\n\
138 -C <ul> - Set ChannelAssignment UL value\n\
139 -d <duration> - Number of frames to process, default all\n\
140 -D <depth> - Component depth for YCbCr images (default: 10)\n\
141 -e - Encrypt JP2K headers (default)\n\
142 -E - Do not encrypt JP2K headers\n\
143 -F (0|1) - Set field dominance for interlaced image (default: 0)\n\
144 -g <rfc-5646-code>\n\
145 - Create MCA labels having the given RFC 5646 language code\n\
146 (requires option \"-m\") -- Also used with -G to set the\n\
147 value of the TextMIMEMediaType property\n\
148 -G <filename> - Filename of XML resource to be carried per RP 2057 Generic\n\
149 Stream. May be issued multiple times.\n\
150 -i - Indicates input essence is interlaced fields (forces -Y)\n\
151 -j <key-id-str> - Write key ID instead of creating a random value\n\
152 -k <key-string> - Use key for ciphertext operations\n\
153 -l <first>,<second>\n\
154 - Integer values that set the VideoLineMap when creating\n\
155 interlaced YCbCr files\n\
156 -m <expr> - Write MCA labels using <expr>. Example:\n\
157 51(L,R,C,LFE,Ls,Rs,),HI,VIN\n\
158 -M - Do not create HMAC values when writing\n\
159 -n <UL> - Set the TransferCharacteristic UL\n\
160 -o <min>,<max> - Mastering Display luminance, cd*m*m, e.g., \".05,100\"\n\
161 -O <rx>,<ry>,<gx>,<gy>,<bx>,<by>,<wx>,<wy>\n\
162 - Mastering Display Color Primaries and white point\n\
163 e.g., \".64,.33,.3,.6,.15,.06,.3457,.3585\"\n\
164 -p <ul> - Set broadcast profile\n\
165 -P <string> - Set NamespaceURI property when creating timed text MXF\n\
166 -q <UL> - Set the CodingEquations UL\n\
167 -r <n>/<d> - Edit Rate of the output file. 24/1 is the default\n\
168 -R - Indicates RGB image essence (default except with -c)\n\
169 -s <seconds> - Duration of a frame-wrapped partition (default 60)\n\
170 -t <min> - Set RGB component minimum code value (default: 0)\n\
171 -T <max> - Set RGB component maximum code value (default: 1023)\n\
172 -u - Print UL catalog to stdout\n\
173 -u <UL> - ISXD (RDD47) essence coding label\n\
174 -v - Verbose, prints informative messages to stderr\n\
175 -W - Read input file only, do not write source file\n\
176 -x <int> - Horizontal subsampling degree (default: 2)\n\
177 -X <int> - Vertical subsampling degree (default: 2)\n\
178 -y <white-ref>[,<black-ref>[,<color-range>]]\n\
179 - Same as -Y but White Ref, Black Ref and Color Range are\n\
180 set from the given argument\n\
181 -Y - Indicates YCbCr image essence (default with -c), uses\n\
182 default values for White Ref, Black Ref and Color Range,\n\
183 940,64,897, indicating 10 bit standard Video Range\n\
184 -z - Fail if j2c inputs have unequal parameters (default)\n\
185 -Z - Ignore unequal parameters in j2c inputs\n\
187 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
188 o All option arguments must be separated from the option by whitespace.\n\n");
191 const float chromaticity_scale = 50000.0;
194 set_primary_from_token(const std::string& token, ui16_t& primary)
196 float raw_value = strtod(token.c_str(),0);
198 if ( raw_value == 0.0 || raw_value > 1.0 )
200 fprintf(stderr, "Invalid coordinate value \"%s\".\n", token.c_str());
204 primary = floor(0.5 + ( raw_value * chromaticity_scale ));
208 const float luminance_scale = 10000.0;
211 set_luminance_from_token(const std::string& token, ui32_t& luminance)
213 float raw_value = strtod(token.c_str(),0);
215 if ( raw_value == 0.0 || raw_value > 400000.0 )
217 fprintf(stderr, "Invalid luminance value \"%s\".\n", token.c_str());
221 luminance = floor(0.5 + ( raw_value * luminance_scale ));
225 #define SET_LUMINANCE(p,t) \
226 if ( ! set_luminance_from_token(t, p) ) { \
236 bool error_flag; // true if the given options are in error or not complete
237 bool key_flag; // true if an encryption key was given
238 bool asset_id_flag; // true if an asset ID was given
239 bool encrypt_header_flag; // true if j2c headers are to be encrypted
240 bool write_hmac; // true if HMAC values are to be generated and written
241 bool verbose_flag; // true if the verbose option was selected
242 ui32_t fb_dump_size; // number of bytes of frame buffer to dump
243 bool no_write_flag; // true if no output files are to be written
244 bool version_flag; // true if the version display option was selected
245 bool help_flag; // true if the help display option was selected
246 ui32_t duration; // number of frames to be processed
247 bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
248 bool use_cdci_descriptor; //
249 Rational edit_rate; // edit rate of JP2K sequence
250 ui32_t fb_size; // size of picture frame buffer
251 byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
252 bool key_id_flag; // true if a key ID was given
253 byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
254 byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
255 bool show_ul_values_flag; /// if true, dump the UL table before going tp work.
256 Kumu::PathList_t filenames; // list of filenames to be processed
258 UL channel_assignment, picture_coding, transfer_characteristic, color_primaries, coding_equations;
259 ASDCP::MXF::AS02_MCAConfigParser mca_config;
260 std::string language;
265 ui32_t horizontal_subsampling;
266 ui32_t vertical_subsampling;
267 ui32_t component_depth;
269 ASDCP::Rational aspect_ratio;
270 ui8_t field_dominance;
271 ui32_t mxf_header_size;
272 ui32_t cdci_BlackRefLevel;
273 ui32_t cdci_WhiteRefLevel;
274 ui32_t cdci_ColorRange;
276 ui32_t md_min_luminance, md_max_luminance;
277 ASDCP::MXF::ThreeColorPrimaries md_primaries;
278 ASDCP::MXF::ColorPrimary md_white_point;
280 //new attributes for AS-02 support
281 AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip
282 ui32_t partition_space; //Shim parameter partition_spacing
285 UL isxd_essence_coding;
286 std::list<std::string> global_isxd_metadata;
289 MXF::LineMapPair line_map;
290 std::string out_file, profile_name; //
293 bool set_video_line_map(const std::string& arg)
295 const char* sep_str = strrchr(arg.c_str(), ',');
299 fprintf(stderr, "Expecting <first>,<second>\n");
303 line_map.First = Kumu::xabs(strtol(arg.c_str(), 0, 10));
304 line_map.Second = Kumu::xabs(strtol(sep_str+1, 0, 10));
309 bool set_video_ref(const std::string& arg)
311 std::list<std::string> ref_tokens = Kumu::km_token_split(arg, ",");
313 switch ( ref_tokens.size() )
316 cdci_ColorRange = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
317 ref_tokens.pop_back();
319 cdci_BlackRefLevel = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
320 ref_tokens.pop_back();
322 cdci_WhiteRefLevel = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
326 fprintf(stderr, "Expecting <white-ref>[,<black-ref>[,<color-range>]]\n");
330 if ( cdci_WhiteRefLevel > 65535 || cdci_BlackRefLevel > 65535 || cdci_ColorRange > 65535 )
332 fprintf(stderr, "Unexpected CDCI video referece levels.\n");
340 bool set_display_primaries(const std::string& arg)
342 std::list<std::string> coordinate_tokens = Kumu::km_token_split(arg, ",");
343 if ( coordinate_tokens.size() != 8 )
345 fprintf(stderr, "Expecting four coordinate pairs.\n");
349 std::list<std::string>::const_iterator i = coordinate_tokens.begin();
350 if ( ! set_primary_from_token(*(i++), md_primaries.First.X) ) return false;
351 if ( ! set_primary_from_token(*(i++), md_primaries.First.Y) ) return false;
352 if ( ! set_primary_from_token(*(i++), md_primaries.Second.X) ) return false;
353 if ( ! set_primary_from_token(*(i++), md_primaries.Second.Y) ) return false;
354 if ( ! set_primary_from_token(*(i++), md_primaries.Third.X) ) return false;
355 if ( ! set_primary_from_token(*(i++), md_primaries.Third.Y) ) return false;
356 if ( ! set_primary_from_token(*(i++), md_white_point.X) ) return false;
357 if ( ! set_primary_from_token(*i, md_white_point.Y) ) return false;
363 bool set_display_luminance(const std::string& arg)
365 std::list<std::string> luminance_tokens = Kumu::km_token_split(arg, ",");
366 if ( luminance_tokens.size() != 2 )
368 fprintf(stderr, "Expecting a luminance pair.\n");
372 if ( ! set_luminance_from_token(luminance_tokens.front(), md_min_luminance) ) return false;
373 if ( ! set_luminance_from_token(luminance_tokens.back(), md_max_luminance) ) return false;
379 bool set_color_system_from_arg(const char* arg)
385 // Application 2 (ST 2067-20)
387 coding_equations = g_dict->ul(MDD_CodingEquations_601);
388 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_709);
389 color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU470_PAL);
390 use_cdci_descriptor = true;
394 coding_equations = g_dict->ul(MDD_CodingEquations_601);
395 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_709);
396 color_primaries = g_dict->ul(MDD_ColorPrimaries_SMPTE170M);
397 use_cdci_descriptor = true;
401 coding_equations = g_dict->ul(MDD_CodingEquations_709);
402 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_709);
403 color_primaries = g_dict->ul(MDD_ColorPrimaries_BT709);
404 use_cdci_descriptor = true;
407 // Application 2e (ST 2067-21)
409 coding_equations = g_dict->ul(MDD_CodingEquations_709);
410 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_xvYCC);
411 color_primaries = g_dict->ul(MDD_ColorPrimaries_BT709);
412 use_cdci_descriptor = true;
416 coding_equations = g_dict->ul(MDD_CodingEquations_709);
417 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_2020);
418 color_primaries = g_dict->ul(MDD_ColorPrimaries_BT2020);
419 use_cdci_descriptor = true;
423 fprintf(stderr, "Unrecognized color system number, expecting one of 1-5.\n");
430 CommandOptions(int argc, const char** argv) :
431 error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
432 encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0),
433 no_write_flag(false), version_flag(false), help_flag(false),
434 duration(0xffffffff), j2c_pedantic(true), use_cdci_descriptor(false),
435 edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE),
436 show_ul_values_flag(false), index_strategy(AS_02::IS_FOLLOW), partition_space(60),
437 mca_config(g_dict), rgba_MaxRef(1023), rgba_MinRef(0),
438 horizontal_subsampling(2), vertical_subsampling(2), component_depth(10),
439 frame_layout(0), aspect_ratio(ASDCP::Rational(4,3)), field_dominance(0),
440 mxf_header_size(16384), cdci_WhiteRefLevel(940), cdci_BlackRefLevel(64), cdci_ColorRange(897),
441 md_min_luminance(0), md_max_luminance(0), line_map(0,0)
443 memset(key_value, 0, KeyLen);
444 memset(key_id_value, 0, UUIDlen);
446 coding_equations = g_dict->ul(MDD_CodingEquations_709);
447 color_primaries = g_dict->ul(MDD_ColorPrimaries_BT709);
448 transfer_characteristic = g_dict->ul(MDD_TransferCharacteristics_709);
449 std::string mca_config_str;
451 for ( int i = 1; i < argc; i++ )
454 if ( (strcmp( argv[i], "-help") == 0) )
460 if ( argv[i][0] == '-'
461 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
464 switch ( argv[i][1] )
467 TEST_EXTRA_ARG(i, 'A');
468 if ( ! DecodeRational(argv[i], aspect_ratio) )
470 fprintf(stderr, "Error decoding aspect ratio value: %s\n", argv[i]);
476 asset_id_flag = true;
477 TEST_EXTRA_ARG(i, 'a');
480 Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
482 if ( length != UUIDlen )
484 fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
491 TEST_EXTRA_ARG(i, 'b');
492 fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
495 fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
500 TEST_EXTRA_ARG(i, 'c');
501 if ( ! set_color_system_from_arg(argv[i]) )
508 TEST_EXTRA_ARG(i, 'C');
509 if ( ! channel_assignment.DecodeHex(argv[i]) )
511 fprintf(stderr, "Error decoding ChannelAssignment UL value: %s\n", argv[i]);
517 TEST_EXTRA_ARG(i, 'D');
518 component_depth = Kumu::xabs(strtol(argv[i], 0, 10));
522 TEST_EXTRA_ARG(i, 'd');
523 duration = Kumu::xabs(strtol(argv[i], 0, 10));
526 case 'E': encrypt_header_flag = false; break;
527 case 'e': encrypt_header_flag = true; break;
530 TEST_EXTRA_ARG(i, 'F');
531 field_dominance = Kumu::xabs(strtol(argv[i], 0, 10));
532 if ( field_dominance > 1 )
534 fprintf(stderr, "Field dominance value must be \"0\" or \"1\"\n");
540 TEST_EXTRA_ARG(i, 'g');
545 TEST_EXTRA_ARG(i, 'G');
546 global_isxd_metadata.push_back(argv[i]);
549 case 'h': help_flag = true; break;
553 use_cdci_descriptor = true;
558 TEST_EXTRA_ARG(i, 'j');
561 Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
563 if ( length != UUIDlen )
565 fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
571 case 'k': key_flag = true;
572 TEST_EXTRA_ARG(i, 'k');
575 Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
577 if ( length != KeyLen )
579 fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
586 TEST_EXTRA_ARG(i, 'y');
587 if ( ! set_video_line_map(argv[i]) )
593 case 'M': write_hmac = false; break;
596 TEST_EXTRA_ARG(i, 'm');
597 mca_config_str = argv[i];
601 TEST_EXTRA_ARG(i, 'n');
602 if ( ! transfer_characteristic.DecodeHex(argv[i]) )
604 fprintf(stderr, "Error decoding TransferCharacteristic UL value: %s\n", argv[i]);
610 TEST_EXTRA_ARG(i, 'O');
611 if ( ! set_display_primaries(argv[i]) )
618 TEST_EXTRA_ARG(i, 'o');
619 if ( ! set_display_luminance(argv[i]) )
626 TEST_EXTRA_ARG(i, 'P');
627 profile_name = argv[i];
631 TEST_EXTRA_ARG(i, 'p');
632 if ( ! picture_coding.DecodeHex(argv[i]) )
634 fprintf(stderr, "Error decoding PictureEssenceCoding UL value: %s\n", argv[i]);
640 TEST_EXTRA_ARG(i, 'q');
641 if ( ! coding_equations.DecodeHex(argv[i]) )
643 fprintf(stderr, "Error decoding CodingEquations UL value: %s\n", argv[i]);
649 TEST_EXTRA_ARG(i, 'r');
650 if ( ! DecodeRational(argv[i], edit_rate) )
652 fprintf(stderr, "Error decoding edit rate value: %s\n", argv[i]);
659 use_cdci_descriptor = false;
663 TEST_EXTRA_ARG(i, 's');
664 partition_space = Kumu::xabs(strtol(argv[i], 0, 10));
668 TEST_EXTRA_ARG(i, 't');
669 rgba_MinRef = Kumu::xabs(strtol(argv[i], 0, 10));
673 TEST_EXTRA_ARG(i, 'T');
674 rgba_MaxRef = Kumu::xabs(strtol(argv[i], 0, 10));
677 case 'u': show_ul_values_flag = true; break;
680 TEST_EXTRA_ARG(i, 'U');
681 if ( ! isxd_essence_coding.DecodeHex(argv[i]) )
683 fprintf(stderr, "Error decoding UL value: %s\n", argv[i]);
688 case 'V': version_flag = true; break;
689 case 'v': verbose_flag = true; break;
690 case 'W': no_write_flag = true; break;
693 TEST_EXTRA_ARG(i, 'x');
694 horizontal_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
698 TEST_EXTRA_ARG(i, 'X');
699 vertical_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
703 use_cdci_descriptor = true;
704 // default 10 bit video range YUV, ref levels already set
708 // Use values provided as argument, sharp tool, be careful
709 use_cdci_descriptor = true;
710 TEST_EXTRA_ARG(i, 'y');
711 if ( ! set_video_ref(argv[i]) )
717 case 'Z': j2c_pedantic = false; break;
718 case 'z': j2c_pedantic = true; break;
721 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
728 if ( argv[i][0] != '-' )
730 filenames.push_back(argv[i]);
734 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
740 if ( ! mca_config_str.empty() )
742 if ( language.empty() )
744 if ( ! mca_config.DecodeString(mca_config_str) )
751 if ( ! mca_config.DecodeString(mca_config_str, language) )
758 if ( help_flag || version_flag || show_ul_values_flag )
763 if ( filenames.size() < 2 )
765 fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
769 out_file = filenames.back();
770 filenames.pop_back();
772 if ( ! picture_coding.HasValue() )
774 picture_coding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1));
782 //------------------------------------------------------------------------------------------
786 Result_t JP2K_PDesc_to_MD(const ASDCP::JP2K::PictureDescriptor& PDesc,
787 const ASDCP::Dictionary& dict,
788 ASDCP::MXF::GenericPictureEssenceDescriptor& GenericPictureEssenceDescriptor,
789 ASDCP::MXF::JPEG2000PictureSubDescriptor& EssenceSubDescriptor);
791 Result_t PCM_ADesc_to_MD(ASDCP::PCM::AudioDescriptor& ADesc, ASDCP::MXF::WaveAudioDescriptor* ADescObj);
794 // Write one or more plaintext JPEG 2000 codestreams to a plaintext AS-02 file
795 // Write one or more plaintext JPEG 2000 codestreams to a ciphertext AS-02 file
798 write_JP2K_file(CommandOptions& Options)
800 AESEncContext* Context = 0;
801 HMACContext* HMAC = 0;
802 AS_02::JP2K::MXFWriter Writer;
803 JP2K::FrameBuffer FrameBuffer(Options.fb_size);
804 JP2K::SequenceParser Parser;
805 byte_t IV_buf[CBC_BLOCK_SIZE];
806 Kumu::FortunaRNG RNG;
807 ASDCP::MXF::FileDescriptor *essence_descriptor = 0;
808 ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors;
810 // set up essence parser
811 Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
814 if ( ASDCP_SUCCESS(result) )
816 ASDCP::JP2K::PictureDescriptor PDesc;
817 Parser.FillPictureDescriptor(PDesc);
818 PDesc.EditRate = Options.edit_rate;
820 if ( Options.verbose_flag )
822 fprintf(stderr, "JPEG 2000 pictures\n");
823 fputs("PictureDescriptor:\n", stderr);
824 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
825 JP2K::PictureDescriptorDump(PDesc);
828 if ( Options.use_cdci_descriptor )
830 ASDCP::MXF::CDCIEssenceDescriptor* tmp_dscr = new ASDCP::MXF::CDCIEssenceDescriptor(g_dict);
831 essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict));
833 result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict,
834 *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr),
835 *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back()));
837 if ( ASDCP_SUCCESS(result) )
839 tmp_dscr->CodingEquations = Options.coding_equations;
840 tmp_dscr->TransferCharacteristic = Options.transfer_characteristic;
841 tmp_dscr->ColorPrimaries = Options.color_primaries;
842 tmp_dscr->PictureEssenceCoding = Options.picture_coding;
843 tmp_dscr->HorizontalSubsampling = Options.horizontal_subsampling;
844 tmp_dscr->VerticalSubsampling = Options.vertical_subsampling;
845 tmp_dscr->ComponentDepth = Options.component_depth;
846 tmp_dscr->FrameLayout = Options.frame_layout;
847 tmp_dscr->AspectRatio = Options.aspect_ratio;
848 tmp_dscr->FieldDominance = Options.field_dominance;
849 tmp_dscr->WhiteReflevel = Options.cdci_WhiteRefLevel;
850 tmp_dscr->BlackRefLevel = Options.cdci_BlackRefLevel;
851 tmp_dscr->ColorRange = Options.cdci_ColorRange;
852 tmp_dscr->VideoLineMap = Options.line_map;
854 if ( Options.md_min_luminance || Options.md_max_luminance )
856 tmp_dscr->MasteringDisplayMinimumLuminance = Options.md_min_luminance;
857 tmp_dscr->MasteringDisplayMaximumLuminance = Options.md_max_luminance;
860 if ( Options.md_primaries.HasValue() )
862 tmp_dscr->MasteringDisplayPrimaries = Options.md_primaries;
863 tmp_dscr->MasteringDisplayWhitePointChromaticity = Options.md_white_point;
866 essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
871 ASDCP::MXF::RGBAEssenceDescriptor* tmp_dscr = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict);
872 essence_sub_descriptors.push_back(new ASDCP::MXF::JPEG2000PictureSubDescriptor(g_dict));
874 result = ASDCP::JP2K_PDesc_to_MD(PDesc, *g_dict,
875 *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr),
876 *static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back()));
878 if ( ASDCP_SUCCESS(result) )
880 tmp_dscr->CodingEquations = Options.coding_equations;
881 tmp_dscr->TransferCharacteristic = Options.transfer_characteristic;
882 tmp_dscr->ColorPrimaries = Options.color_primaries;
883 tmp_dscr->ScanningDirection = 0;
884 tmp_dscr->PictureEssenceCoding = Options.picture_coding;
885 tmp_dscr->ComponentMaxRef = Options.rgba_MaxRef;
886 tmp_dscr->ComponentMinRef = Options.rgba_MinRef;
888 if ( Options.md_min_luminance || Options.md_max_luminance )
890 tmp_dscr->MasteringDisplayMinimumLuminance = Options.md_min_luminance;
891 tmp_dscr->MasteringDisplayMaximumLuminance = Options.md_max_luminance;
894 if ( Options.md_primaries.HasValue() )
896 tmp_dscr->MasteringDisplayPrimaries = Options.md_primaries;
897 tmp_dscr->MasteringDisplayWhitePointChromaticity = Options.md_white_point;
900 essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
905 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
907 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
908 Info.LabelSetType = LS_MXF_SMPTE;
910 if ( Options.asset_id_flag )
911 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
913 Kumu::GenRandomUUID(Info.AssetUUID);
915 // configure encryption
916 if( Options.key_flag )
918 Kumu::GenRandomUUID(Info.ContextID);
919 Info.EncryptedEssence = true;
921 if ( Options.key_id_flag )
923 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
927 create_random_uuid(Info.CryptographicKeyID);
930 Context = new AESEncContext;
931 result = Context->InitKey(Options.key_value);
933 if ( ASDCP_SUCCESS(result) )
934 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
936 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
938 Info.UsesHMAC = true;
939 HMAC = new HMACContext;
940 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
944 if ( ASDCP_SUCCESS(result) )
946 result = Writer.OpenWrite(Options.out_file, Info, essence_descriptor, essence_sub_descriptors,
947 Options.edit_rate, Options.mxf_header_size, Options.index_strategy, Options.partition_space);
951 if ( ASDCP_SUCCESS(result) )
954 result = Parser.Reset();
956 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
958 result = Parser.ReadFrame(FrameBuffer);
960 if ( ASDCP_SUCCESS(result) )
962 if ( Options.verbose_flag )
963 FrameBuffer.Dump(stderr, Options.fb_dump_size);
965 if ( Options.encrypt_header_flag )
966 FrameBuffer.PlaintextOffset(0);
969 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
971 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
973 // The Writer class will forward the last block of ciphertext
974 // to the encryption context for use as the IV for the next
975 // frame. If you want to use non-sequitur IV values, un-comment
976 // the following line of code.
977 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
978 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
982 if ( result == RESULT_ENDOFFILE )
986 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
987 result = Writer.Finalize();
992 //------------------------------------------------------------------------------------------
996 // Write one or more plaintext PCM audio streams to a plaintext AS-02 file
997 // Write one or more plaintext PCM audio streams to a ciphertext AS-02 file
1000 write_PCM_file(CommandOptions& Options)
1002 AESEncContext* Context = 0;
1003 HMACContext* HMAC = 0;
1004 PCMParserList Parser;
1005 AS_02::PCM::MXFWriter Writer;
1006 PCM::FrameBuffer FrameBuffer;
1007 byte_t IV_buf[CBC_BLOCK_SIZE];
1008 Kumu::FortunaRNG RNG;
1009 ASDCP::MXF::WaveAudioDescriptor *essence_descriptor = 0;
1011 // set up essence parser
1012 Result_t result = Parser.OpenRead(Options.filenames, Options.edit_rate);
1014 // set up MXF writer
1015 if ( ASDCP_SUCCESS(result) )
1017 ASDCP::PCM::AudioDescriptor ADesc;
1018 Parser.FillAudioDescriptor(ADesc);
1020 ADesc.EditRate = Options.edit_rate;
1021 FrameBuffer.Capacity(PCM::CalcFrameBufferSize(ADesc));
1023 if ( Options.verbose_flag )
1026 fprintf(stderr, "%.1fkHz PCM Audio, %s fps (%u spf)\n",
1027 ADesc.AudioSamplingRate.Quotient() / 1000.0,
1028 RationalToString(Options.edit_rate, buf, 64),
1029 PCM::CalcSamplesPerFrame(ADesc));
1030 fputs("AudioDescriptor:\n", stderr);
1031 PCM::AudioDescriptorDump(ADesc);
1034 essence_descriptor = new ASDCP::MXF::WaveAudioDescriptor(g_dict);
1036 result = ASDCP::PCM_ADesc_to_MD(ADesc, essence_descriptor);
1038 if ( Options.mca_config.empty() )
1040 essence_descriptor->ChannelAssignment = Options.channel_assignment;
1044 if ( Options.mca_config.ChannelCount() != essence_descriptor->ChannelCount )
1046 fprintf(stderr, "MCA label count (%d) differs from essence stream channel count (%d).\n",
1047 Options.mca_config.ChannelCount(), essence_descriptor->ChannelCount);
1051 // this is the d-cinema MCA label, what is the one for IMF?
1052 essence_descriptor->ChannelAssignment = g_dict->ul(MDD_IMFAudioChannelCfg_MCA);
1056 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1058 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1059 Info.LabelSetType = LS_MXF_SMPTE;
1061 if ( Options.asset_id_flag )
1062 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1064 Kumu::GenRandomUUID(Info.AssetUUID);
1066 // configure encryption
1067 if( Options.key_flag )
1069 Kumu::GenRandomUUID(Info.ContextID);
1070 Info.EncryptedEssence = true;
1072 if ( Options.key_id_flag )
1074 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1078 create_random_uuid(Info.CryptographicKeyID);
1081 Context = new AESEncContext;
1082 result = Context->InitKey(Options.key_value);
1084 if ( ASDCP_SUCCESS(result) )
1085 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1087 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1089 Info.UsesHMAC = true;
1090 HMAC = new HMACContext;
1091 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1095 if ( ASDCP_SUCCESS(result) )
1097 result = Writer.OpenWrite(Options.out_file.c_str(), Info, essence_descriptor,
1098 Options.mca_config, Options.edit_rate);
1102 if ( ASDCP_SUCCESS(result) )
1104 result = Parser.Reset();
1105 ui32_t duration = 0;
1107 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1109 result = Parser.ReadFrame(FrameBuffer);
1111 if ( ASDCP_SUCCESS(result) )
1113 if ( Options.verbose_flag )
1114 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1116 if ( ! Options.no_write_flag )
1118 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1120 // The Writer class will forward the last block of ciphertext
1121 // to the encryption context for use as the IV for the next
1122 // frame. If you want to use non-sequitur IV values, un-comment
1123 // the following line of code.
1124 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1125 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1130 if ( result == RESULT_ENDOFFILE )
1134 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1135 result = Writer.Finalize();
1143 //------------------------------------------------------------------------------------------
1144 // TimedText essence
1147 // Write one or more plaintext timed text streams to a plaintext AS-02 file
1148 // Write one or more plaintext timed text streams to a ciphertext AS-02 file
1151 write_timed_text_file(CommandOptions& Options)
1153 AESEncContext* Context = 0;
1154 HMACContext* HMAC = 0;
1155 AS_02::TimedText::ST2052_TextParser Parser;
1156 AS_02::TimedText::MXFWriter Writer;
1157 TimedText::FrameBuffer FrameBuffer;
1158 TimedText::TimedTextDescriptor TDesc;
1159 byte_t IV_buf[CBC_BLOCK_SIZE];
1160 Kumu::FortunaRNG RNG;
1162 // set up essence parser
1163 Result_t result = Parser.OpenRead(Options.filenames.front());
1165 // set up MXF writer
1166 if ( ASDCP_SUCCESS(result) )
1168 Parser.FillTimedTextDescriptor(TDesc);
1169 TDesc.EditRate = Options.edit_rate;
1170 TDesc.ContainerDuration = Options.duration;
1171 FrameBuffer.Capacity(Options.fb_size);
1173 if ( ! Options.profile_name.empty() )
1175 TDesc.NamespaceName = Options.profile_name;
1178 if ( Options.verbose_flag )
1180 fputs("IMF Timed-Text Descriptor:\n", stderr);
1181 TimedText::DescriptorDump(TDesc);
1185 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1187 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1188 Info.LabelSetType = LS_MXF_SMPTE;
1190 if ( Options.asset_id_flag )
1191 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1193 Kumu::GenRandomUUID(Info.AssetUUID);
1195 // configure encryption
1196 if( Options.key_flag )
1198 Kumu::GenRandomUUID(Info.ContextID);
1199 Info.EncryptedEssence = true;
1201 if ( Options.key_id_flag )
1203 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1207 create_random_uuid(Info.CryptographicKeyID);
1210 Context = new AESEncContext;
1211 result = Context->InitKey(Options.key_value);
1213 if ( ASDCP_SUCCESS(result) )
1214 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1216 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1218 Info.UsesHMAC = true;
1219 HMAC = new HMACContext;
1220 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1224 if ( ASDCP_SUCCESS(result) )
1225 result = Writer.OpenWrite(Options.out_file.c_str(), Info, TDesc);
1228 if ( ASDCP_FAILURE(result) )
1232 TimedText::ResourceList_t::const_iterator ri;
1234 result = Parser.ReadTimedTextResource(XMLDoc);
1236 if ( ASDCP_SUCCESS(result) )
1237 result = Writer.WriteTimedTextResource(XMLDoc, Context, HMAC);
1239 for ( ri = TDesc.ResourceList.begin() ; ri != TDesc.ResourceList.end() && ASDCP_SUCCESS(result); ri++ )
1241 result = Parser.ReadAncillaryResource((*ri).ResourceID, FrameBuffer);
1243 if ( ASDCP_SUCCESS(result) )
1245 if ( Options.verbose_flag )
1246 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1248 if ( ! Options.no_write_flag )
1250 result = Writer.WriteAncillaryResource(FrameBuffer, Context, HMAC);
1252 // The Writer class will forward the last block of ciphertext
1253 // to the encryption context for use as the IV for the next
1254 // frame. If you want to use non-sequitur IV values, un-comment
1255 // the following line of code.
1256 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1257 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1261 if ( result == RESULT_ENDOFFILE )
1265 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1266 result = Writer.Finalize();
1273 get_current_dms_text_descriptor(AS_02::ISXD::MXFWriter& writer, ASDCP::MXF::GenericStreamTextBasedSet *&text_object)
1275 std::list<MXF::InterchangeObject*> object_list;
1276 writer.OP1aHeader().GetMDObjectsByType(DefaultSMPTEDict().ul(MDD_GenericStreamTextBasedSet), object_list);
1278 if ( object_list.empty() )
1283 text_object = dynamic_cast<MXF::GenericStreamTextBasedSet*>(object_list.back());
1284 assert(text_object != 0);
1289 // Write one or more plaintext Aux Data bytestreams to a plaintext AS-02 file
1290 // Write one or more plaintext Aux Data bytestreams to a ciphertext AS-02 file
1293 write_isxd_file(CommandOptions& Options)
1295 AESEncContext* Context = 0;
1296 HMACContext* HMAC = 0;
1297 AS_02::ISXD::MXFWriter Writer;
1298 DCData::FrameBuffer FrameBuffer(Options.fb_size);
1299 DCData::SequenceParser Parser;
1300 byte_t IV_buf[CBC_BLOCK_SIZE];
1301 Kumu::FortunaRNG RNG;
1303 // set up essence parser
1304 Result_t result = Parser.OpenRead(Options.filenames.front());
1306 // set up MXF writer
1307 if ( ASDCP_SUCCESS(result) )
1310 if ( Options.verbose_flag )
1312 fprintf(stderr, "Aux Data\n");
1313 fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
1317 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1319 WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
1320 if ( Options.asset_id_flag )
1321 memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
1323 Kumu::GenRandomUUID(Info.AssetUUID);
1325 Info.LabelSetType = LS_MXF_SMPTE;
1327 // configure encryption
1328 if( Options.key_flag )
1330 Kumu::GenRandomUUID(Info.ContextID);
1331 Info.EncryptedEssence = true;
1333 if ( Options.key_id_flag )
1335 memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
1339 create_random_uuid(Info.CryptographicKeyID);
1342 Context = new AESEncContext;
1343 result = Context->InitKey(Options.key_value);
1345 if ( ASDCP_SUCCESS(result) )
1346 result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1348 if ( ASDCP_SUCCESS(result) && Options.write_hmac )
1350 Info.UsesHMAC = true;
1351 HMAC = new HMACContext;
1352 result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
1356 if ( ASDCP_SUCCESS(result) )
1358 result = Writer.OpenWrite(Options.out_file, Info, Options.isxd_essence_coding, Options.edit_rate);
1362 if ( ASDCP_SUCCESS(result) )
1364 ui32_t duration = 0;
1365 result = Parser.Reset();
1367 while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
1369 result = Parser.ReadFrame(FrameBuffer);
1371 if ( ASDCP_SUCCESS(result) )
1373 if ( Options.verbose_flag )
1374 FrameBuffer.Dump(stderr, Options.fb_dump_size);
1376 if ( Options.encrypt_header_flag )
1377 FrameBuffer.PlaintextOffset(0);
1380 if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
1382 result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
1384 // The Writer class will forward the last block of ciphertext
1385 // to the encryption context for use as the IV for the next
1386 // frame. If you want to use non-sequitur IV values, un-comment
1387 // the following line of code.
1388 // if ( ASDCP_SUCCESS(result) && Options.key_flag )
1389 // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
1393 if ( result == RESULT_ENDOFFILE )
1399 if ( KM_SUCCESS(result) && ! Options.no_write_flag )
1401 ASDCP::FrameBuffer global_metadata;
1402 std::list<std::string>::iterator i;
1404 for ( i = Options.global_isxd_metadata.begin(); i != Options.global_isxd_metadata.end(); ++i )
1406 ui32_t file_size = Kumu::FileSize(*i);
1407 result = global_metadata.Capacity(file_size);
1409 if ( KM_SUCCESS(result) )
1411 ui32_t read_count = 0;
1412 Kumu::FileReader Reader;
1413 std::string namespace_name;
1415 result = Reader.OpenRead(*i);
1417 if ( KM_SUCCESS(result) )
1419 result = Reader.Read(global_metadata.Data(), file_size, &read_count);
1422 if ( KM_SUCCESS(result) )
1424 if ( file_size != read_count)
1425 return RESULT_READFAIL;
1427 global_metadata.Size(read_count);
1429 std::string ns_prefix, type_name;
1430 Kumu::AttributeList doc_attr_list;
1431 result = GetXMLDocType(global_metadata.RoData(), global_metadata.Size(), ns_prefix, type_name,
1432 namespace_name, doc_attr_list) ? RESULT_OK : RESULT_FAIL;
1435 if ( KM_SUCCESS(result) )
1437 result = Writer.AddDmsGenericPartUtf8Text(global_metadata, Context, HMAC);
1440 if ( KM_SUCCESS(result) )
1442 ASDCP::MXF::GenericStreamTextBasedSet *text_object = 0;
1443 get_current_dms_text_descriptor(Writer, text_object);
1444 assert(text_object);
1445 text_object->TextMIMEMediaType = "text/xml";
1446 text_object->TextDataDescription = namespace_name;
1447 text_object->RFC5646TextLanguageCode = Options.language;
1452 if ( KM_SUCCESS(result) )
1454 result = Writer.Finalize();
1463 main(int argc, const char** argv)
1465 Result_t result = RESULT_OK;
1467 g_dict = &ASDCP::DefaultSMPTEDict();
1470 CommandOptions Options(argc, argv);
1472 if ( Options.version_flag )
1475 if ( Options.help_flag )
1478 if ( Options.show_ul_values_flag )
1480 g_dict->Dump(stdout);
1483 if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
1486 if ( Options.error_flag )
1488 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
1492 EssenceType_t EssenceType;
1493 result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType);
1495 if ( ASDCP_SUCCESS(result) )
1497 switch ( EssenceType )
1500 result = write_JP2K_file(Options);
1503 case ESS_PCM_24b_48k:
1504 case ESS_PCM_24b_96k:
1505 result = write_PCM_file(Options);
1508 case ESS_TIMED_TEXT:
1509 result = write_timed_text_file(Options);
1512 case ESS_DCDATA_UNKNOWN:
1513 if ( Options.isxd_essence_coding.HasValue() )
1515 result = write_isxd_file(Options);
1519 fprintf(stderr, "%s: Unknown synchronous data file type, not AS-02-compatible essence.\n",
1520 Options.filenames.front().c_str());
1526 fprintf(stderr, "%s: Unknown file type, not AS-02-compatible essence.\n",
1527 Options.filenames.front().c_str());
1532 if ( ASDCP_FAILURE(result) )
1534 fputs("Program stopped on error.\n", stderr);
1536 if ( result != RESULT_FAIL )
1538 fputs(result, stderr);
1539 fputc('\n', stderr);
1550 // end as-02-wrap.cpp