diff options
| author | Thomas Richter <thomas.richter@iis.fraunhofer.de> | 2021-05-31 17:03:12 +0200 |
|---|---|---|
| committer | Thomas Richter <thomas.richter@iis.fraunhofer.de> | 2021-05-31 17:03:12 +0200 |
| commit | 7e3380f5eb9c9441c26646415be3ffec4d01b2c0 (patch) | |
| tree | 9a7dae0bf415de10682968c48c3641e1d27880ae /src | |
| parent | a542b262538a782d379fb3943a226dd7b11f04a2 (diff) | |
Added JXS support for as-02-unwrap. Added additional parameter checking
for the picture coding UL in as-02-wrap. Added JXS support in as-02-info.
Added identification of JXS files in AS_DCP_MXF.cpp.
Diffstat (limited to 'src')
| -rwxr-xr-x | src/AS_DCP_MXF.cpp | 8 | ||||
| -rw-r--r-- | src/as-02-info.cpp | 174 | ||||
| -rwxr-xr-x | src/as-02-unwrap.cpp | 158 | ||||
| -rwxr-xr-x | src/as-02-wrap.cpp | 33 |
4 files changed, 364 insertions, 9 deletions
diff --git a/src/AS_DCP_MXF.cpp b/src/AS_DCP_MXF.cpp index 7231b5a..3ee13c9 100755 --- a/src/AS_DCP_MXF.cpp +++ b/src/AS_DCP_MXF.cpp @@ -196,6 +196,10 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) type = ESS_JPEG_2000; } } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEGXSPictureSubDescriptor))) ) + { + type = ESS_JPEG_XS; + } else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &md_object)) ) { assert(md_object); @@ -249,6 +253,10 @@ ASDCP::EssenceType(const std::string& filename, EssenceType_t& type) { type = ESS_AS02_JPEG_2000; } + else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(JPEGXSPictureSubDescriptor))) ) + { + type = ESS_AS02_JPEG_XS; + } else if ( ASDCP_SUCCESS(TestHeader.GetMDObjectByType(OBJ_TYPE_ARGS(WaveAudioDescriptor), &md_object)) ) { assert(md_object); diff --git a/src/as-02-info.cpp b/src/as-02-info.cpp index dd769a8..1878f6b 100644 --- a/src/as-02-info.cpp +++ b/src/as-02-info.cpp @@ -1,3 +1,4 @@ + /* Copyright (c) 2003-2016, John Hurst, Wolfgang Ruppel @@ -40,6 +41,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <AS_DCP.h> #include <AS_02.h> #include <JP2K.h> +#ifdef USE_ASDCP_JXS +#include <AS_02_JXS.h> +#include <JXS.h> +#endif #include <AS_02_ACES.h> #include <ACES.h> #include <MXF.h> @@ -366,6 +371,114 @@ class MyPictureDescriptor : public JP2K::PictureDescriptor } }; +#ifdef USE_ASDCP_JXS +class MyXSPictureDescriptor : public JXS::PictureDescriptor +{ + RGBAEssenceDescriptor *m_RGBADescriptor; + CDCIEssenceDescriptor *m_CDCIDescriptor; + JPEGXSPictureSubDescriptor *m_JXSSubDescriptor; + + public: + MyXSPictureDescriptor() : + m_RGBADescriptor(0), + m_CDCIDescriptor(0), + m_JXSSubDescriptor(0) {} + + void FillDescriptor(AS_02::JXS::MXFReader& Reader) + { + m_CDCIDescriptor = get_descriptor_by_type<AS_02::JXS::MXFReader, CDCIEssenceDescriptor> + (Reader, DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor)); + + m_RGBADescriptor = get_descriptor_by_type<AS_02::JXS::MXFReader, RGBAEssenceDescriptor> + (Reader, DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor)); + + if ( m_RGBADescriptor != 0 ) + { + SampleRate = m_RGBADescriptor->SampleRate; + if ( ! m_RGBADescriptor->ContainerDuration.empty() ) + { + ContainerDuration = m_RGBADescriptor->ContainerDuration; + } + } + else if ( m_CDCIDescriptor != 0 ) + { + SampleRate = m_CDCIDescriptor->SampleRate; + if ( ! m_CDCIDescriptor->ContainerDuration.empty() ) + { + ContainerDuration = m_CDCIDescriptor->ContainerDuration; + } + } + else + { + DefaultLogSink().Error("Picture descriptor not found.\n"); + } + + m_JXSSubDescriptor = get_descriptor_by_type<AS_02::JXS::MXFReader, JPEGXSPictureSubDescriptor> + (Reader, DefaultCompositeDict().ul(MDD_JPEGXSPictureSubDescriptor)); + + if ( m_JXSSubDescriptor == 0 ) + { + DefaultLogSink().Error("JPEGXSPictureSubDescriptor not found.\n"); + } + + std::list<InterchangeObject*> ObjectList; + Reader.OP1aHeader().GetMDObjectsByType(DefaultCompositeDict().ul(MDD_Track), ObjectList); + + if ( ObjectList.empty() ) + { + DefaultLogSink().Error("MXF Metadata contains no Track Sets.\n"); + } + + EditRate = ((Track*)ObjectList.front())->EditRate; + } + + void MyDump(FILE* stream) { + if ( stream == 0 ) + { + stream = stderr; + } + + if ( m_CDCIDescriptor != 0 ) + { + m_CDCIDescriptor->Dump(stream); + } + else if ( m_RGBADescriptor != 0 ) + { + m_RGBADescriptor->Dump(stream); + } + else + { + return; + } + + if ( m_JXSSubDescriptor != 0 ) + { + m_JXSSubDescriptor->Dump(stream); + + fprintf(stream, " ImageComponents: (max=%d)\n", JXS::MaxComponents); + + // + ui32_t component_sizing = m_JXSSubDescriptor->JPEGXSComponentTable.Length(); + + if ( component_sizing == m_JXSSubDescriptor->JPEGXSNc * 2 + 4) + { + fprintf(stream, " bits h-sep v-sep\n"); + const byte_t *src = m_JXSSubDescriptor->JPEGXSComponentTable.RoData() + 4; + for(int i = 0;i < m_JXSSubDescriptor->JPEGXSNc && i < JXS::MaxComponents; i++ ) { + fprintf(stream, " %4d %5d %5d\n", + src[0],src[1] >> 4,src[1] & 0x0f); + src += 2; + } + } + else + { + DefaultLogSink().Warn("Unexpected PictureComponentSizing size: %u, should be 17.\n", component_sizing); + } + } + } +}; +#endif + class MyACESPictureDescriptor : public AS_02::ACES::PictureDescriptor { RGBAEssenceDescriptor *m_RGBADescriptor; @@ -611,9 +724,36 @@ init_rate_info() rate_ul = DefaultCompositeDict().ul(MDD_ACESUncompressedMonoscopicWithAlpha); g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2065-5"))); -} +#ifdef USE_ASDCP_JXS + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSUnrestrictedCodestream); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Unrestricted Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSMain422_10Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Main 422 10 Profile"))); + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSMain444_12Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Main 444 12 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSMain4444_12Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Main 4444 12 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSLight422_10Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Light 422 10 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSLight444_12Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Light 444 12 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSLightSubline422_10Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS Light Subline 422 10 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSHigh444_12Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS High 444 12 Profile"))); + + rate_ul = DefaultCompositeDict().ul(MDD_JPEGXSHigh4444_12Profile); + g_rate_info.insert(rate_info_map::value_type(rate_ul, RateInfo(rate_ul, DBL_MAX, "ST 2124 JPEG XS High 4444 12 Profile"))); +#endif +} // // template<class ReaderT, class DescriptorT> @@ -818,10 +958,12 @@ public: static const double mega_const = 1.0 / ( 1000000 / 8.0 ); // we did not accumulate the last, so duration -= 1 - double avg_bytes_frame = (double)(total_frame_bytes / ( duration - 1 )); - + if (duration > 1) { + double avg_bytes_frame = (double)(total_frame_bytes / ( duration - 1 )); + m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient(); + } + m_MaxBitrate = largest_frame * mega_const * m_Desc.EditRate.Quotient(); - m_AvgBitrate = avg_bytes_frame * mega_const * m_Desc.EditRate.Quotient(); } } @@ -886,7 +1028,31 @@ show_file_info(CommandOptions& Options) result = wrapper.test_rates(Options, stdout); } } +#ifdef USE_ASDCP_JXS + else if ( EssenceType == ESS_AS02_JPEG_XS ) + { + FileInfoWrapper<AS_02::JXS::MXFReader, MyXSPictureDescriptor> wrapper; + result = wrapper.file_info(Options, "JPEG XS pictures"); + + if ( KM_SUCCESS(result) ) + { + wrapper.get_PictureEssenceCoding(); + wrapper.calc_Bitrate(stdout); + + if ( Options.showcoding_flag ) + { + wrapper.dump_PictureEssenceCoding(stdout); + } + + if ( Options.showrate_flag ) + { + wrapper.dump_Bitrate(stdout); + } + result = wrapper.test_rates(Options, stdout); + } + } +#endif else if ( EssenceType == ESS_AS02_ACES ) { FileInfoWrapper<AS_02::ACES::MXFReader, MyACESPictureDescriptor> wrapper; diff --git a/src/as-02-unwrap.cpp b/src/as-02-unwrap.cpp index 64a399a..a50b76e 100755 --- a/src/as-02-unwrap.cpp +++ b/src/as-02-unwrap.cpp @@ -38,6 +38,9 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. #include <KM_fileio.h> #include <AS_02.h> +#ifdef USE_ASDCP_JXS +#include "AS_02_JXS.h" +#endif #include "AS_02_ACES.h" #include <WavFileWriter.h> @@ -431,6 +434,156 @@ read_JP2K_file(CommandOptions& Options) //------------------------------------------------------------------------------------------ +// JPEG XS essence + +#ifdef USE_ASDCP_JXS +// Read one or more plaintext JPEG XS codestreams from a plaintext ASDCP file +// Read one or more plaintext JPEG XS codestreams from a ciphertext ASDCP file +// Read one or more ciphertext JPEG XS codestreams from a ciphertext ASDCP file +// +Result_t +read_JXS_file(CommandOptions& Options) +{ + AESDecContext* Context = 0; + HMACContext* HMAC = 0; + AS_02::JXS::MXFReader Reader; + JXS::FrameBuffer FrameBuffer(Options.fb_size); + ui32_t frame_count = 0; + + Result_t result = Reader.OpenRead(Options.input_filename); + + if (ASDCP_SUCCESS(result)) + { + if (Options.verbose_flag) + { + fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size); + } + + ASDCP::MXF::RGBAEssenceDescriptor *rgba_descriptor = 0; + ASDCP::MXF::CDCIEssenceDescriptor *cdci_descriptor = 0; + + result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_RGBAEssenceDescriptor), + reinterpret_cast<MXF::InterchangeObject**>(&rgba_descriptor)); + + if (KM_SUCCESS(result)) + { + assert(rgba_descriptor); + if (!rgba_descriptor->ContainerDuration.empty()) + { + frame_count = (ui32_t)rgba_descriptor->ContainerDuration; + } + if (Options.verbose_flag) + { + rgba_descriptor->Dump(); + } + } + else + { + result = Reader.OP1aHeader().GetMDObjectByType(DefaultCompositeDict().ul(MDD_CDCIEssenceDescriptor), + reinterpret_cast<MXF::InterchangeObject**>(&cdci_descriptor)); + + if (KM_SUCCESS(result)) + { + assert(cdci_descriptor); + if (!cdci_descriptor->ContainerDuration.empty()) + { + frame_count = (ui32_t)cdci_descriptor->ContainerDuration; + } + if (Options.verbose_flag) + { + cdci_descriptor->Dump(); + } + } + else + { + fprintf(stderr, "File does not contain an essence descriptor.\n"); + frame_count = Reader.AS02IndexReader().GetDuration(); + } + } + + if (frame_count == 0) + { + frame_count = Reader.AS02IndexReader().GetDuration(); + } + + if (frame_count == 0) + { + fprintf(stderr, "Unable to determine file duration.\n"); + return RESULT_FAIL; + } + } + +#ifdef HAVE_OPENSSL + 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); + } + } + } +#endif + + 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.jxc", Options.number_width); + + for (ui32_t i = Options.start_frame; ASDCP_SUCCESS(result) && i < last_frame; i++) + { + result = Reader.ReadFrame(i, FrameBuffer, Context, HMAC); + + char filename[1024]; + snprintf(filename, 1024, name_format, Options.file_prefix, i); + + if (ASDCP_SUCCESS(result) && Options.verbose_flag) + { + printf("Frame %d, %d bytes", i, FrameBuffer.Size()); + + if (!Options.no_write_flag) + { + printf(" -> %s", filename); + } + + printf("\n"); + } + + if (ASDCP_SUCCESS(result) && (!Options.no_write_flag)) + { + Kumu::FileWriter OutFile; + ui32_t write_count; + result = OutFile.OpenWrite(filename); + + if (ASDCP_SUCCESS(result)) + result = OutFile.Write(FrameBuffer.Data(), FrameBuffer.Size(), &write_count); + + if (ASDCP_SUCCESS(result) && Options.verbose_flag) + { + FrameBuffer.Dump(stderr, Options.fb_dump_size); + } + } + } + + return result; +} +#endif + +//------------------------------------------------------------------------------------------ // ACES essence // @@ -1019,6 +1172,11 @@ main(int argc, const char** argv) result = read_JP2K_file(Options); break; //PB +#ifdef USE_ASDCP_JXS + case ESS_AS02_JPEG_XS: + result = read_JXS_file(Options); + break; +#endif case ESS_AS02_ACES: result = read_ACES_file(Options); break; diff --git a/src/as-02-wrap.cpp b/src/as-02-wrap.cpp index 1703394..f3e31ee 100755 --- a/src/as-02-wrap.cpp +++ b/src/as-02-wrap.cpp @@ -956,11 +956,6 @@ public: out_file = filenames.back(); filenames.pop_back(); - if ( ! picture_coding.HasValue() ) - { - picture_coding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1)); - } - error_flag = false; } }; @@ -1001,6 +996,11 @@ write_JP2K_file(CommandOptions& Options) ASDCP::JP2K::PictureDescriptor PDesc; Parser.FillPictureDescriptor(PDesc); PDesc.EditRate = Options.edit_rate; + + if ( ! Options.picture_coding.HasValue() ) + { + Options.picture_coding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1)); + } if ( Options.verbose_flag ) { @@ -1211,6 +1211,28 @@ write_JXS_file(CommandOptions& Options) // set up essence parser Result_t result = Parser.OpenRead(Options.filenames.front().c_str()); + if ( ! Options.picture_coding.HasValue() ) + { + Options.picture_coding = UL(g_dict->ul(MDD_JPEGXSUnrestrictedCodestream)); + } + + if (ASDCP_SUCCESS(result) ) + { + // verify the picture essence coding. + if (!((UL(g_dict->ul(MDD_JPEGXSUnrestrictedCodestream)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSMain422_10Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSMain444_12Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSMain4444_12Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSLight422_10Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSLight444_12Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSLightSubline422_10Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSHigh444_12Profile)) == Options.picture_coding) || + (UL(g_dict->ul(MDD_JPEGXSHigh4444_12Profile)) == Options.picture_coding))) + { + result = RESULT_PARAM; + } + } + // set up MXF writer if ( ASDCP_SUCCESS(result) ) { @@ -1235,6 +1257,7 @@ write_JXS_file(CommandOptions& Options) *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr), *static_cast<ASDCP::MXF::JPEGXSPictureSubDescriptor*>(essence_sub_descriptors.back())); + if ( ASDCP_SUCCESS(result) ) { tmp_dscr->CodingEquations = Options.coding_equations; |
