summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorThomas Richter <thomas.richter@iis.fraunhofer.de>2021-05-31 17:03:12 +0200
committerThomas Richter <thomas.richter@iis.fraunhofer.de>2021-05-31 17:03:12 +0200
commit7e3380f5eb9c9441c26646415be3ffec4d01b2c0 (patch)
tree9a7dae0bf415de10682968c48c3641e1d27880ae /src
parenta542b262538a782d379fb3943a226dd7b11f04a2 (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-xsrc/AS_DCP_MXF.cpp8
-rw-r--r--src/as-02-info.cpp174
-rwxr-xr-xsrc/as-02-unwrap.cpp158
-rwxr-xr-xsrc/as-02-wrap.cpp33
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;