2 Copyright (c) 2003-2016, John Hurst, Wolfgang Ruppel
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 as-02-info.cpp
29 \brief AS-02 file metadata utility
31 This program provides metadata information about an AS-02 file.
33 For more information about asdcplib, please refer to the header file AS_DCP.h
36 #include <KM_fileio.h>
46 using namespace ASDCP;
48 const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
50 //------------------------------------------------------------------------------------------
52 // command line option parser class
54 static const char* PROGRAM_NAME = "as-02-info"; // program name for messages
57 // Increment the iterator, test for an additional non-option command line argument.
58 // Causes the caller to return if there are no remaining arguments or if the next
59 // argument begins with '-'.
60 #define TEST_EXTRA_ARG(i,c) \
61 if ( ++i >= argc || argv[(i)][0] == '-' ) { \
62 fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
68 banner(FILE* stream = stdout)
72 Copyright (c) 2003-2015 John Hurst\n\n\
73 asdcplib may be copied only under the terms of the license found at\n\
74 the top of every file in the asdcplib distribution kit.\n\n\
75 Specify the -h (help) option for further information about %s\n\n",
76 PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
81 usage(FILE* stream = stdout)
84 USAGE:%s [-h|-help] [-V]\n\
86 %s [options] <input-file>+\n\
89 -c - Show essence coding UL\n\
90 -d - Show essence descriptor info\n\
91 -h | -help - Show help\n\
92 -H - Show MXF header metadata\n\
93 -i - Show identity info\n\
95 -r - Show bit-rate (Mb/s)\n\
96 -t <int> - Set high-bitrate threshold (Mb/s)\n\
97 -V - Show version information\n\
99 NOTES: o There is no option grouping, all options must be distinct arguments.\n\
100 o All option arguments must be separated from the option by whitespace.\n\n",
101 PROGRAM_NAME, PROGRAM_NAME);
111 bool error_flag; // true if the given options are in error or not complete
112 bool version_flag; // true if the version display option was selected
113 bool help_flag; // true if the help display option was selected
114 bool verbose_flag; // true if the verbose option was selected
115 PathList_t filenames; // list of filenames to be processed
116 bool showindex_flag; // true if index is to be displayed
117 bool showheader_flag; // true if MXF file header is to be displayed
118 bool showid_flag; // if true, show file identity info (the WriterInfo struct)
119 bool showdescriptor_flag; // if true, show the essence descriptor
120 bool showcoding_flag; // if true, show the coding UL
121 bool showrate_flag; // if true and is image file, show bit rate
122 bool max_bitrate_flag; // true if -t option given
123 double max_bitrate; // if true and is image file, max bit rate for rate test
126 CommandOptions(int argc, const char** argv) :
127 error_flag(true), version_flag(false), help_flag(false), verbose_flag(false),
128 showindex_flag(false), showheader_flag(false),
129 showid_flag(false), showdescriptor_flag(false), showcoding_flag(false),
130 showrate_flag(false), max_bitrate_flag(false), max_bitrate(0.0)
132 for ( int i = 1; i < argc; ++i )
135 if ( (strcmp( argv[i], "-help") == 0) )
141 if ( argv[i][0] == '-'
142 && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
145 switch ( argv[i][1] )
147 case 'c': showcoding_flag = true; break;
148 case 'd': showdescriptor_flag = true; break;
149 case 'H': showheader_flag = true; break;
150 case 'h': help_flag = true; break;
151 case 'i': showid_flag = true; break;
152 case 'n': showindex_flag = true; break;
153 case 'r': showrate_flag = true; break;
156 TEST_EXTRA_ARG(i, 't');
157 max_bitrate = Kumu::xabs(strtol(argv[i], 0, 10));
158 max_bitrate_flag = true;
161 case 'V': version_flag = true; break;
162 case 'v': verbose_flag = true; break;
165 fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
171 if ( argv[i][0] != '-' )
173 filenames.push_back(argv[i]);
177 fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
183 if ( help_flag || version_flag )
186 if ( filenames.empty() )
188 fputs("At least one filename argument is required.\n", stderr);
196 //------------------------------------------------------------------------------------------
200 // These classes wrap the irregular names in the asdcplib API
201 // so that I can use a template to simplify the implementation
202 // of show_file_info()
204 static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
206 using namespace ASDCP::MXF;
208 template <class ReaderType, class DescriptorType>
209 DescriptorType *get_descriptor_by_type(ReaderType& reader, const UL& type_ul)
211 InterchangeObject *obj = 0;
212 reader.OP1aHeader().GetMDObjectByType(type_ul.Value(), &obj);
213 return dynamic_cast<DescriptorType*>(obj);
216 class MyPictureDescriptor : public JP2K::PictureDescriptor
218 RGBAEssenceDescriptor *m_RGBADescriptor;
219 CDCIEssenceDescriptor *m_CDCIDescriptor;
220 JPEG2000PictureSubDescriptor *m_JP2KSubDescriptor;
223 MyPictureDescriptor() :
226 m_JP2KSubDescriptor(0) {}
228 void FillDescriptor(AS_02::JP2K::MXFReader& Reader)
230 m_CDCIDescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, CDCIEssenceDescriptor>
231 (Reader, DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor));
233 m_RGBADescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, RGBAEssenceDescriptor>
234 (Reader, DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor));
236 if ( m_RGBADescriptor != 0 )
238 SampleRate = m_RGBADescriptor->SampleRate;
239 ContainerDuration = m_RGBADescriptor->ContainerDuration;
241 else if ( m_CDCIDescriptor != 0 )
243 SampleRate = m_CDCIDescriptor->SampleRate;
244 ContainerDuration = m_CDCIDescriptor->ContainerDuration;
248 DefaultLogSink().Error("Picture descriptor not found.\n");
251 m_JP2KSubDescriptor = get_descriptor_by_type<AS_02::JP2K::MXFReader, JPEG2000PictureSubDescriptor>
252 (Reader, DefaultCompositeDict().ul(MDD_JPEG2000PictureSubDescriptor));
254 if ( m_JP2KSubDescriptor == 0 )
256 DefaultLogSink().Error("JPEG2000PictureSubDescriptor not found.\n");
259 std::list<InterchangeObject*> ObjectList;
260 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), ObjectList);
262 if ( ObjectList.empty() )
264 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
267 EditRate = ((Track*)ObjectList.front())->EditRate;
270 void MyDump(FILE* stream) {
276 if ( m_CDCIDescriptor != 0 )
278 m_CDCIDescriptor->Dump(stream);
280 else if ( m_RGBADescriptor != 0 )
282 m_RGBADescriptor->Dump(stream);
289 if ( m_JP2KSubDescriptor != 0 )
291 m_JP2KSubDescriptor->Dump(stream);
293 fprintf(stream, " ImageComponents: (max=%d)\n", JP2K::MaxComponents);
296 ui32_t component_sizing = m_JP2KSubDescriptor->PictureComponentSizing.const_get().Length();
297 JP2K::ImageComponent_t image_components[JP2K::MaxComponents];
299 if ( component_sizing == 17 ) // ( 2 * sizeof(ui32_t) ) + 3 components * 3 byte each
301 memcpy(&image_components,
302 m_JP2KSubDescriptor->PictureComponentSizing.const_get().RoData() + 8,
303 component_sizing - 8);
307 DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", component_sizing);
310 fprintf(stream, " bits h-sep v-sep\n");
312 for ( int i = 0; i < m_JP2KSubDescriptor->Csize && i < JP2K::MaxComponents; i++ )
314 fprintf(stream, " %4d %5d %5d\n",
315 image_components[i].Ssize + 1, // See ISO 15444-1, Table A11, for the origin of '+1'
316 image_components[i].XRsize,
317 image_components[i].YRsize
322 JP2K::CodingStyleDefault_t coding_style_default;
324 memcpy(&coding_style_default,
325 m_JP2KSubDescriptor->CodingStyleDefault.const_get().RoData(),
326 m_JP2KSubDescriptor->CodingStyleDefault.const_get().Length());
328 fprintf(stream, " Scod: %hhu\n", coding_style_default.Scod);
329 fprintf(stream, " ProgressionOrder: %hhu\n", coding_style_default.SGcod.ProgressionOrder);
330 fprintf(stream, " NumberOfLayers: %hd\n",
331 KM_i16_BE(Kumu::cp2i<ui16_t>(coding_style_default.SGcod.NumberOfLayers)));
333 fprintf(stream, " MultiCompTransform: %hhu\n", coding_style_default.SGcod.MultiCompTransform);
334 fprintf(stream, "DecompositionLevels: %hhu\n", coding_style_default.SPcod.DecompositionLevels);
335 fprintf(stream, " CodeblockWidth: %hhu\n", coding_style_default.SPcod.CodeblockWidth);
336 fprintf(stream, " CodeblockHeight: %hhu\n", coding_style_default.SPcod.CodeblockHeight);
337 fprintf(stream, " CodeblockStyle: %hhu\n", coding_style_default.SPcod.CodeblockStyle);
338 fprintf(stream, " Transformation: %hhu\n", coding_style_default.SPcod.Transformation);
340 ui32_t precinct_set_size = 0;
342 for ( int i = 0; coding_style_default.SPcod.PrecinctSize[i] != 0 && i < JP2K::MaxPrecincts; ++i )
347 fprintf(stream, " Precincts: %u\n", precinct_set_size);
348 fprintf(stream, "precinct dimensions:\n");
350 for ( unsigned int i = 0; i < precinct_set_size && i < JP2K::MaxPrecincts; i++ )
351 fprintf(stream, " %d: %d x %d\n", i + 1,
352 s_exp_lookup[coding_style_default.SPcod.PrecinctSize[i]&0x0f],
353 s_exp_lookup[(coding_style_default.SPcod.PrecinctSize[i]>>4)&0x0f]
359 class MyAudioDescriptor : public PCM::AudioDescriptor
361 WaveAudioDescriptor *m_WaveAudioDescriptor;
362 std::list<MCALabelSubDescriptor*> m_ChannelDescriptorList;
365 MyAudioDescriptor() : m_WaveAudioDescriptor(0) {}
366 void FillDescriptor(AS_02::PCM::MXFReader& Reader)
368 m_WaveAudioDescriptor = get_descriptor_by_type<AS_02::PCM::MXFReader, WaveAudioDescriptor>
369 (Reader, DefaultCompositeDict().ul(MDD_WaveAudioDescriptor));
371 if ( m_WaveAudioDescriptor != 0 )
373 AudioSamplingRate = m_WaveAudioDescriptor->SampleRate;
374 ContainerDuration = m_WaveAudioDescriptor->ContainerDuration;
378 DefaultLogSink().Error("Audio descriptor not found.\n");
381 std::list<InterchangeObject*> object_list;
382 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_AudioChannelLabelSubDescriptor), object_list);
383 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_SoundfieldGroupLabelSubDescriptor), object_list);
384 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), object_list);
386 std::list<InterchangeObject*>::iterator i = object_list.begin();
387 for ( ; i != object_list.end(); ++i )
389 MCALabelSubDescriptor *p = dynamic_cast<MCALabelSubDescriptor*>(*i);
393 m_ChannelDescriptorList.push_back(p);
398 DefaultLogSink().Error("Audio sub-descriptor type error.\n", (**i).InstanceUID.EncodeHex(buf, 64));
403 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), object_list);
405 if ( object_list.empty() )
407 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
410 EditRate = ((Track*)object_list.front())->EditRate;
413 void MyDump(FILE* stream) {
419 if ( m_WaveAudioDescriptor != 0 )
421 m_WaveAudioDescriptor->Dump(stream);
424 if ( ! m_ChannelDescriptorList.empty() )
426 fprintf(stream, "Audio Channel Subdescriptors:\n");
428 std::list<MCALabelSubDescriptor*>::const_iterator i = m_ChannelDescriptorList.begin();
429 for ( ; i != m_ChannelDescriptorList.end(); ++i )
437 class MyTextDescriptor : public TimedText::TimedTextDescriptor
440 void FillDescriptor(TimedText::MXFReader& Reader) {
441 Reader.FillTimedTextDescriptor(*this);
444 void Dump(FILE* stream) {
445 TimedText::DescriptorDump(*this, stream);
455 RateInfo(const UL& u, const double& b, const std::string& l) {
456 ul = u; bitrate = b; label = l;
461 static const double dci_max_bitrate = 250.0;
462 static const double p_hfr_max_bitrate = 400.0;
463 typedef std::map<const UL, const RateInfo> rate_info_map;
464 static rate_info_map g_rate_info;
470 UL rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_1);
471 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 1")));
473 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_2);
474 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 2")));
476 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_3);
477 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 3")));
479 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_4);
480 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 400.0, "ISO/IEC 15444-1 Amendment 3 Level 4")));
482 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_5);
483 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 800.0, "ISO/IEC 15444-1 Amendment 3 Level 5")));
485 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_6);
486 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 1600.0, "ISO/IEC 15444-1 Amendment 3 Level 6")));
488 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_7);
489 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ISO/IEC 15444-1 Amendment 3 Level 7")));
495 template<class ReaderT, class DescriptorT>
496 class FileInfoWrapper
500 WriterInfo m_WriterInfo;
501 double m_MaxBitrate, m_AvgBitrate;
502 UL m_PictureEssenceCoding;
504 KM_NO_COPY_CONSTRUCT(FileInfoWrapper);
507 Result_t OpenRead(const T& m, const CommandOptions& Options)
509 return m.OpenRead(Options.filenames.front().c_str());
511 Result_t OpenRead(const AS_02::PCM::MXFReader& m, const CommandOptions& Options)
513 return m.OpenRead(Options.filenames.front().c_str(), EditRate_24);
514 //Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
518 FileInfoWrapper() : m_MaxBitrate(0.0), m_AvgBitrate(0.0) {}
519 virtual ~FileInfoWrapper() {}
522 file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0)
530 Result_t result = RESULT_OK;
531 result = OpenRead(m_Reader, Options);
533 if ( ASDCP_SUCCESS(result) )
535 m_Desc.FillDescriptor(m_Reader);
536 m_Reader.FillWriterInfo(m_WriterInfo);
538 fprintf(stdout, "%s file essence type is %s, (%d edit unit%s).\n",
539 ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 2067-5" : "Unknown" ),
541 (m_Desc.ContainerDuration != 0 ? m_Desc.ContainerDuration : m_Reader.AS02IndexReader().GetDuration()),
542 (m_Desc.ContainerDuration == (ui64_t)1 ? "":"s"));
544 if ( Options.showheader_flag )
546 m_Reader.DumpHeaderMetadata(stream);
549 if ( Options.showid_flag )
551 WriterInfoDump(m_WriterInfo, stream);
554 if ( Options.showdescriptor_flag )
556 m_Desc.MyDump(stream);
559 if ( Options.showindex_flag )
561 m_Reader.DumpIndex(stream);
564 else if ( result == RESULT_FORMAT && Options.showheader_flag )
566 m_Reader.DumpHeaderMetadata(stream);
573 void get_PictureEssenceCoding(FILE* stream = 0)
575 const Dictionary& Dict = DefaultCompositeDict();
576 MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
577 MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
579 Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
580 reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
582 if ( KM_SUCCESS(result) && rgba_descriptor)
583 m_PictureEssenceCoding = rgba_descriptor->PictureEssenceCoding;
585 result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
586 reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
587 if ( KM_SUCCESS(result) && cdci_descriptor)
588 m_PictureEssenceCoding = cdci_descriptor->PictureEssenceCoding;
594 void dump_PictureEssenceCoding(FILE* stream = 0)
598 if ( m_PictureEssenceCoding.HasValue() )
600 std::string encoding_ul_type = "**UNKNOWN**";
602 rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
603 if ( rate_i == g_rate_info.end() )
605 fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
609 encoding_ul_type = rate_i->second.label;
612 fprintf(stream, "PictureEssenceCoding: %s (%s)\n",
613 m_PictureEssenceCoding.EncodeString(buf, 64),
614 encoding_ul_type.c_str());
620 test_rates(CommandOptions& Options, FILE* stream = 0)
622 double max_bitrate = 0; //Options.max_bitrate_flag ? Options.max_bitrate : dci_max_bitrate;
626 rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
627 if ( rate_i == g_rate_info.end() )
629 fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
633 max_bitrate = rate_i->second.bitrate;
636 max_bitrate = Options.max_bitrate_flag ? Options.max_bitrate : max_bitrate;
638 if ( m_MaxBitrate > max_bitrate )
640 fprintf(stream, "Bitrate %0.0f Mb/s exceeds maximum %0.0f Mb/s\n", m_MaxBitrate, max_bitrate);
644 return errors ? RESULT_FAIL : RESULT_OK;
649 calc_Bitrate(FILE* stream = 0)
651 //MXF::OP1aHeader& footer = m_Reader.OP1aHeader();
652 AS_02::MXF::AS02IndexReader& footer = m_Reader.AS02IndexReader();
653 ui64_t total_frame_bytes = 0, last_stream_offset = 0;
654 ui32_t largest_frame = 0;
655 Result_t result = RESULT_OK;
658 if ( m_Desc.EditRate.Numerator == 0 || m_Desc.EditRate.Denominator == 0 )
660 fprintf(stderr, "Broken edit rate, unable to calculate essence bitrate.\n");
664 duration = m_Desc.ContainerDuration;
667 fprintf(stderr, "ContainerDuration not set in file descriptor, attempting to use index duration.\n");
668 duration = m_Reader.AS02IndexReader().GetDuration();
671 for ( ui32_t i = 0; KM_SUCCESS(result) && i < duration; ++i )
673 MXF::IndexTableSegment::IndexEntry entry;
674 result = footer.Lookup(i, entry);
676 if ( KM_SUCCESS(result) )
678 if ( last_stream_offset != 0 )
680 ui64_t this_frame_size = entry.StreamOffset - last_stream_offset - 20; // do not count the bytes that represent the KLV wrapping
681 total_frame_bytes += this_frame_size;
683 if ( this_frame_size > largest_frame )
684 largest_frame = (ui32_t)this_frame_size;
687 last_stream_offset = entry.StreamOffset;
691 if ( KM_SUCCESS(result) )
693 // scale bytes to megabits
694 static const double mega_const = 1.0 / ( 1000000 / 8.0 );
696 // we did not accumulate the last, so duration -= 1
697 double avg_bytes_frame = (double)(total_frame_bytes / ( duration - 1 ));
699 m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient();
700 m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient();
706 dump_Bitrate(FILE* stream = 0)
708 fprintf(stream, "Max BitRate: %0.2f Mb/s\n", m_MaxBitrate);
709 fprintf(stream, "Average BitRate: %0.2f Mb/s\n", m_AvgBitrate);
713 void dump_WaveAudioDescriptor(FILE* stream = 0)
715 const Dictionary& Dict = DefaultCompositeDict();
716 MXF::WaveAudioDescriptor *descriptor = 0;
718 Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
719 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
721 if ( KM_SUCCESS(result) )
724 fprintf(stream, "ChannelAssignment: %s\n", descriptor->ChannelAssignment.const_get().EncodeString(buf, 64));
731 // Read header metadata from an ASDCP file
734 show_file_info(CommandOptions& Options)
736 EssenceType_t EssenceType;
737 Result_t result = ASDCP::EssenceType(Options.filenames.front().c_str(), EssenceType);
739 if ( ASDCP_FAILURE(result) )
742 if ( EssenceType == ESS_AS02_JPEG_2000 )
744 FileInfoWrapper<AS_02::JP2K::MXFReader, MyPictureDescriptor> wrapper;
745 result = wrapper.file_info(Options, "JPEG 2000 pictures");
747 if ( KM_SUCCESS(result) )
749 wrapper.get_PictureEssenceCoding();
750 wrapper.calc_Bitrate(stdout);
752 if ( Options.showcoding_flag )
754 wrapper.dump_PictureEssenceCoding(stdout);
757 if ( Options.showrate_flag )
759 wrapper.dump_Bitrate(stdout);
762 result = wrapper.test_rates(Options, stdout);
766 else if ( EssenceType == ESS_AS02_PCM_24b_48k || EssenceType == ESS_AS02_PCM_24b_96k )
768 FileInfoWrapper<AS_02::PCM::MXFReader, MyAudioDescriptor> wrapper;
769 result = wrapper.file_info(Options, "PCM audio");
771 if ( ASDCP_SUCCESS(result) && Options.showcoding_flag )
772 wrapper.dump_WaveAudioDescriptor(stdout);
776 fprintf(stderr, "Unknown/unsupported essence type: %s\n", Options.filenames.front().c_str());
777 Kumu::FileReader Reader;
778 const Dictionary* Dict = &DefaultCompositeDict();
779 MXF::OP1aHeader TestHeader(Dict);
781 result = Reader.OpenRead(Options.filenames.front().c_str());
783 if ( ASDCP_SUCCESS(result) )
784 result = TestHeader.InitFromFile(Reader); // test UL and OP
786 if ( ASDCP_SUCCESS(result) )
788 TestHeader.Partition::Dump(stdout);
790 if ( MXF::Identification* ID = TestHeader.GetIdentification() )
793 fputs("File contains no Identification object.\n", stdout);
795 if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() )
798 fputs("File contains no SourcePackage object.\n", stdout);
802 fputs("File is not MXF.\n", stdout);
811 main(int argc, const char** argv)
813 Result_t result = RESULT_OK;
814 CommandOptions Options(argc, argv);
816 if ( Options.version_flag )
819 if ( Options.help_flag )
822 if ( Options.version_flag || Options.help_flag )
825 if ( Options.error_flag )
827 fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
833 while ( ! Options.filenames.empty() && ASDCP_SUCCESS(result) )
835 result = show_file_info(Options);
836 Options.filenames.pop_front();
839 if ( ASDCP_FAILURE(result) )
841 fputs("Program stopped on error.\n", stderr);
843 if ( result != RESULT_FAIL )
845 fputs(result, stderr);
857 // end as-02-info.cpp