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 ( 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;
377 DefaultLogSink().Error("Audio descriptor not found.\n");
380 std::list<InterchangeObject*> object_list;
381 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_AudioChannelLabelSubDescriptor), object_list);
382 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_SoundfieldGroupLabelSubDescriptor), object_list);
383 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_GroupOfSoundfieldGroupsLabelSubDescriptor), object_list);
385 std::list<InterchangeObject*>::iterator i = object_list.begin();
386 for ( ; i != object_list.end(); ++i )
388 MCALabelSubDescriptor *p = dynamic_cast<MCALabelSubDescriptor*>(*i);
392 m_ChannelDescriptorList.push_back(p);
397 DefaultLogSink().Error("Audio sub-descriptor type error.\n", (**i).InstanceUID.EncodeHex(buf, 64));
402 Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), object_list);
404 if ( object_list.empty() )
406 DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n");
409 EditRate = ((Track*)object_list.front())->EditRate;
412 void MyDump(FILE* stream) {
418 if ( m_WaveAudioDescriptor != 0 )
420 m_WaveAudioDescriptor->Dump(stream);
423 if ( ! m_ChannelDescriptorList.empty() )
425 fprintf(stream, "Audio Channel Subdescriptors:\n");
427 std::list<MCALabelSubDescriptor*>::const_iterator i = m_ChannelDescriptorList.begin();
428 for ( ; i != m_ChannelDescriptorList.end(); ++i )
436 class MyTextDescriptor : public TimedText::TimedTextDescriptor
439 void FillDescriptor(TimedText::MXFReader& Reader) {
440 Reader.FillTimedTextDescriptor(*this);
443 void Dump(FILE* stream) {
444 TimedText::DescriptorDump(*this, stream);
454 RateInfo(const UL& u, const double& b, const std::string& l) {
455 ul = u; bitrate = b; label = l;
460 static const double dci_max_bitrate = 250.0;
461 static const double p_hfr_max_bitrate = 400.0;
462 typedef std::map<const UL, const RateInfo> rate_info_map;
463 static rate_info_map g_rate_info;
469 UL rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_1);
470 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 1")));
472 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_2);
473 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 2")));
475 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_3);
476 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 200.0, "ISO/IEC 15444-1 Amendment 3 Level 3")));
478 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_4);
479 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 400.0, "ISO/IEC 15444-1 Amendment 3 Level 4")));
481 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_5);
482 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 800.0, "ISO/IEC 15444-1 Amendment 3 Level 5")));
484 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_6);
485 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, 1600.0, "ISO/IEC 15444-1 Amendment 3 Level 6")));
487 rate_ul = DefaultCompositeDict().ul(MDD_JP2KEssenceCompression_BroadcastProfile_7);
488 g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ISO/IEC 15444-1 Amendment 3 Level 7")));
494 template<class ReaderT, class DescriptorT>
495 class FileInfoWrapper
499 WriterInfo m_WriterInfo;
500 double m_MaxBitrate, m_AvgBitrate;
501 UL m_PictureEssenceCoding;
503 KM_NO_COPY_CONSTRUCT(FileInfoWrapper);
506 Result_t OpenRead(const T& m, const CommandOptions& Options)
508 return m.OpenRead(Options.filenames.front().c_str());
510 Result_t OpenRead(const AS_02::PCM::MXFReader& m, const CommandOptions& Options)
512 return m.OpenRead(Options.filenames.front().c_str(), EditRate_24);
513 //Result_t OpenRead(const std::string& filename, const ASDCP::Rational& EditRate);
517 FileInfoWrapper() : m_MaxBitrate(0.0), m_AvgBitrate(0.0) {}
518 virtual ~FileInfoWrapper() {}
521 file_info(CommandOptions& Options, const char* type_string, FILE* stream = 0)
529 Result_t result = RESULT_OK;
530 result = OpenRead(m_Reader, Options);
532 if ( ASDCP_SUCCESS(result) )
534 m_Desc.FillDescriptor(m_Reader);
535 m_Reader.FillWriterInfo(m_WriterInfo);
537 fprintf(stdout, "%s file essence type is %s, (%d edit unit%s).\n",
538 ( m_WriterInfo.LabelSetType == LS_MXF_SMPTE ? "SMPTE 2067-5" : "Unknown" ),
540 (m_Desc.ContainerDuration != 0 ? m_Desc.ContainerDuration : m_Reader.AS02IndexReader().GetDuration()),
541 (m_Desc.ContainerDuration == 1 ? "":"s"));
543 if ( Options.showheader_flag )
545 m_Reader.DumpHeaderMetadata(stream);
548 if ( Options.showid_flag )
550 WriterInfoDump(m_WriterInfo, stream);
553 if ( Options.showdescriptor_flag )
555 m_Desc.MyDump(stream);
558 if ( Options.showindex_flag )
560 m_Reader.DumpIndex(stream);
563 else if ( result == RESULT_FORMAT && Options.showheader_flag )
565 m_Reader.DumpHeaderMetadata(stream);
572 void get_PictureEssenceCoding(FILE* stream = 0)
574 const Dictionary& Dict = DefaultCompositeDict();
575 MXF::RGBAEssenceDescriptor *rgba_descriptor = 0;
576 MXF::CDCIEssenceDescriptor *cdci_descriptor = 0;
578 Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor),
579 reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor));
581 if ( KM_SUCCESS(result) && rgba_descriptor)
582 m_PictureEssenceCoding = rgba_descriptor->PictureEssenceCoding;
584 result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor),
585 reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor));
586 if ( KM_SUCCESS(result) && cdci_descriptor)
587 m_PictureEssenceCoding = cdci_descriptor->PictureEssenceCoding;
593 void dump_PictureEssenceCoding(FILE* stream = 0)
597 if ( m_PictureEssenceCoding.HasValue() )
599 std::string encoding_ul_type = "**UNKNOWN**";
601 rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
602 if ( rate_i == g_rate_info.end() )
604 fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
608 encoding_ul_type = rate_i->second.label;
611 fprintf(stream, "PictureEssenceCoding: %s (%s)\n",
612 m_PictureEssenceCoding.EncodeString(buf, 64),
613 encoding_ul_type.c_str());
619 test_rates(CommandOptions& Options, FILE* stream = 0)
621 double max_bitrate = 0; //Options.max_bitrate_flag ? Options.max_bitrate : dci_max_bitrate;
625 rate_info_map::const_iterator rate_i = g_rate_info.find(m_PictureEssenceCoding);
626 if ( rate_i == g_rate_info.end() )
628 fprintf(stderr, "Unknown PictureEssenceCoding UL: %s\n", m_PictureEssenceCoding.EncodeString(buf, 64));
632 max_bitrate = rate_i->second.bitrate;
635 max_bitrate = Options.max_bitrate_flag ? Options.max_bitrate : max_bitrate;
637 if ( m_MaxBitrate > max_bitrate )
639 fprintf(stream, "Bitrate %0.0f Mb/s exceeds maximum %0.0f Mb/s\n", m_MaxBitrate, max_bitrate);
643 return errors ? RESULT_FAIL : RESULT_OK;
648 calc_Bitrate(FILE* stream = 0)
650 //MXF::OP1aHeader& footer = m_Reader.OP1aHeader();
651 AS_02::MXF::AS02IndexReader& footer = m_Reader.AS02IndexReader();
652 ui64_t total_frame_bytes = 0, last_stream_offset = 0;
653 ui32_t largest_frame = 0;
654 Result_t result = RESULT_OK;
657 if ( m_Desc.EditRate.Numerator == 0 || m_Desc.EditRate.Denominator == 0 )
659 fprintf(stderr, "Broken edit rate, unable to calculate essence bitrate.\n");
663 duration = m_Desc.ContainerDuration;
666 fprintf(stderr, "ContainerDuration not set in file descriptor, attempting to use index duration.\n");
667 duration = m_Reader.AS02IndexReader().GetDuration();
670 for ( ui32_t i = 0; KM_SUCCESS(result) && i < duration; ++i )
672 MXF::IndexTableSegment::IndexEntry entry;
673 result = footer.Lookup(i, entry);
675 if ( KM_SUCCESS(result) )
677 if ( last_stream_offset != 0 )
679 ui64_t this_frame_size = entry.StreamOffset - last_stream_offset - 20; // do not count the bytes that represent the KLV wrapping
680 total_frame_bytes += this_frame_size;
682 if ( this_frame_size > largest_frame )
683 largest_frame = this_frame_size;
686 last_stream_offset = entry.StreamOffset;
690 if ( KM_SUCCESS(result) )
692 // scale bytes to megabits
693 static const double mega_const = 1.0 / ( 1000000 / 8.0 );
695 // we did not accumulate the last, so duration -= 1
696 double avg_bytes_frame = total_frame_bytes / ( duration - 1 );
698 m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient();
699 m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient();
705 dump_Bitrate(FILE* stream = 0)
707 fprintf(stream, "Max BitRate: %0.2f Mb/s\n", m_MaxBitrate);
708 fprintf(stream, "Average BitRate: %0.2f Mb/s\n", m_AvgBitrate);
712 void dump_WaveAudioDescriptor(FILE* stream = 0)
714 const Dictionary& Dict = DefaultCompositeDict();
715 MXF::WaveAudioDescriptor *descriptor = 0;
717 Result_t result = m_Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_WaveAudioDescriptor),
718 reinterpret_cast<MXF::InterchangeObject**>(&descriptor));
720 if ( KM_SUCCESS(result) )
723 fprintf(stream, "ChannelAssignment: %s\n", descriptor->ChannelAssignment.const_get().EncodeString(buf, 64));
730 // Read header metadata from an ASDCP file
733 show_file_info(CommandOptions& Options)
735 EssenceType_t EssenceType;
736 Result_t result = ASDCP::EssenceType(Options.filenames.front().c_str(), EssenceType);
738 if ( ASDCP_FAILURE(result) )
741 if ( EssenceType == ESS_AS02_JPEG_2000 )
743 FileInfoWrapper<AS_02::JP2K::MXFReader, MyPictureDescriptor> wrapper;
744 result = wrapper.file_info(Options, "JPEG 2000 pictures");
746 if ( KM_SUCCESS(result) )
748 wrapper.get_PictureEssenceCoding();
749 wrapper.calc_Bitrate(stdout);
751 if ( Options.showcoding_flag )
753 wrapper.dump_PictureEssenceCoding(stdout);
756 if ( Options.showrate_flag )
758 wrapper.dump_Bitrate(stdout);
761 result = wrapper.test_rates(Options, stdout);
765 else if ( EssenceType == ESS_AS02_PCM_24b_48k || EssenceType == ESS_AS02_PCM_24b_96k )
767 FileInfoWrapper<AS_02::PCM::MXFReader, MyAudioDescriptor> wrapper;
768 result = wrapper.file_info(Options, "PCM audio");
770 if ( ASDCP_SUCCESS(result) && Options.showcoding_flag )
771 wrapper.dump_WaveAudioDescriptor(stdout);
775 fprintf(stderr, "Unknown/unsupported essence type: %s\n", Options.filenames.front().c_str());
776 Kumu::FileReader Reader;
777 const Dictionary* Dict = &DefaultCompositeDict();
778 MXF::OP1aHeader TestHeader(Dict);
780 result = Reader.OpenRead(Options.filenames.front().c_str());
782 if ( ASDCP_SUCCESS(result) )
783 result = TestHeader.InitFromFile(Reader); // test UL and OP
785 if ( ASDCP_SUCCESS(result) )
787 TestHeader.Partition::Dump(stdout);
789 if ( MXF::Identification* ID = TestHeader.GetIdentification() )
792 fputs("File contains no Identification object.\n", stdout);
794 if ( MXF::SourcePackage* SP = TestHeader.GetSourcePackage() )
797 fputs("File contains no SourcePackage object.\n", stdout);
801 fputs("File is not MXF.\n", stdout);
810 main(int argc, const char** argv)
812 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