summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorjhurst <jhurst@cinecert.com>2021-09-12 13:55:51 -0700
committerjhurst <jhurst@cinecert.com>2021-09-12 13:55:51 -0700
commit8db9009293e6ace2ed05a8ca7bd734236a035c06 (patch)
tree74a389e6cd8a034a30a5409cedc15cb4016a2eee /src
parent2cefda0dc78b4e8a1347dcd2ce281fcf6cfeef7a (diff)
parent24c1a213b74792f7ab4a9b3241c303403b558f55 (diff)
Merge remote-tracking branch 'upstream/master'
Diffstat (limited to 'src')
-rw-r--r--src/AS_02_JXS.cpp58
-rw-r--r--src/AS_02_JXS.h6
-rw-r--r--src/AS_DCP_JXS.cpp604
-rw-r--r--src/AS_DCP_JXS.h163
-rw-r--r--src/JXS.cpp177
-rw-r--r--src/JXS.h120
-rw-r--r--src/JXS_Codestream_Parser.cpp79
-rw-r--r--src/JXS_Sequence_Parser.cpp29
-rw-r--r--src/MDD.cpp4
-rwxr-xr-xsrc/MDD.h2
-rwxr-xr-xsrc/MXF.cpp2
-rwxr-xr-xsrc/MXFTypes.h4
-rw-r--r--src/Makefile.am8
-rw-r--r--src/as-02-wrap-jxs.cpp1007
-rwxr-xr-xsrc/as-02-wrap.cpp70
15 files changed, 1542 insertions, 791 deletions
diff --git a/src/AS_02_JXS.cpp b/src/AS_02_JXS.cpp
index b54bd49..f8af21f 100644
--- a/src/AS_02_JXS.cpp
+++ b/src/AS_02_JXS.cpp
@@ -33,7 +33,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include "AS_02_internal.h"
-#include "AS_DCP_JXS.h"
+#include "JXS.h"
#include <iostream>
#include <iomanip>
@@ -312,8 +312,9 @@ public:
virtual ~h__Writer(){}
- Result_t OpenWrite(const std::string&, ASDCP::MXF::FileDescriptor* essence_descriptor,
- ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
+ Result_t OpenWrite(const std::string&,
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
const AS_02::IndexStrategy_t& IndexStrategy,
const ui32_t& PartitionSpace, const ui32_t& HeaderSize);
Result_t SetSourceStream(const std::string& label, const ASDCP::Rational& edit_rate);
@@ -326,10 +327,10 @@ public:
// the operation cannot be completed.
Result_t
AS_02::JXS::MXFWriter::h__Writer::OpenWrite(const std::string& filename,
- ASDCP::MXF::FileDescriptor* essence_descriptor,
- ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
- const AS_02::IndexStrategy_t& IndexStrategy,
- const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize)
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const AS_02::IndexStrategy_t& IndexStrategy,
+ const ui32_t& PartitionSpace_sec, const ui32_t& HeaderSize)
{
if ( ! m_State.Test_BEGIN() )
{
@@ -351,30 +352,23 @@ AS_02::JXS::MXFWriter::h__Writer::OpenWrite(const std::string& filename,
m_PartitionSpace = PartitionSpace_sec; // later converted to edit units by SetSourceStream()
m_HeaderSize = HeaderSize;
- if ( essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor))
- && essence_descriptor->GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) )
+ if ( picture_descriptor.GetUL() != UL(m_Dict->ul(MDD_RGBAEssenceDescriptor))
+ && picture_descriptor.GetUL() != UL(m_Dict->ul(MDD_CDCIEssenceDescriptor)) )
{
DefaultLogSink().Error("Essence descriptor is not a RGBAEssenceDescriptor or CDCIEssenceDescriptor.\n");
- essence_descriptor->Dump();
+ picture_descriptor.Dump();
return RESULT_AS02_FORMAT;
}
- m_EssenceDescriptor = essence_descriptor;
+ m_EssenceDescriptor = new ASDCP::MXF::GenericPictureEssenceDescriptor(m_Dict);
+ m_EssenceDescriptor->Copy(picture_descriptor);
- ASDCP::MXF::InterchangeObject_list_t::iterator i;
- for ( i = essence_sub_descriptor_list.begin(); i != essence_sub_descriptor_list.end(); ++i )
- {
- if ( (*i)->GetUL() != UL(m_Dict->ul(MDD_JPEGXSPictureSubDescriptor)) )
- {
- DefaultLogSink().Error("Essence sub-descriptor is not a JPEGXSPictureSubDescriptor.\n");
- (*i)->Dump();
- }
+ ASDCP::MXF::JPEGXSPictureSubDescriptor *jxs_subdesc = new ASDCP::MXF::JPEGXSPictureSubDescriptor(m_Dict);
+ jxs_subdesc->Copy(jxs_sub_descriptor);
- m_EssenceSubDescriptorList.push_back(*i);
- GenRandomValue((*i)->InstanceUID);
- m_EssenceDescriptor->SubDescriptors.push_back((*i)->InstanceUID);
- *i = 0; // parent will only free the ones we don't keep
- }
+ m_EssenceSubDescriptorList.push_back(jxs_subdesc);
+ GenRandomValue(jxs_subdesc->InstanceUID);
+ m_EssenceDescriptor->SubDescriptors.push_back(jxs_subdesc->InstanceUID);
result = m_State.Goto_INIT();
}
@@ -523,21 +517,15 @@ AS_02::JXS::MXFWriter::RIP()
// the operation cannot be completed.
Result_t
AS_02::JXS::MXFWriter::OpenWrite(const std::string& filename, const ASDCP::WriterInfo& Info,
- ASDCP::MXF::FileDescriptor* essence_descriptor,
- ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
- const ASDCP::Rational& edit_rate, const ui32_t& header_size,
- const IndexStrategy_t& strategy, const ui32_t& partition_space)
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const ASDCP::Rational& edit_rate, const ui32_t& header_size,
+ const IndexStrategy_t& strategy, const ui32_t& partition_space)
{
- if ( essence_descriptor == 0 )
- {
- DefaultLogSink().Error("Essence descriptor object required.\n");
- return RESULT_PARAM;
- }
-
m_Writer = new AS_02::JXS::MXFWriter::h__Writer(&DefaultSMPTEDict());
m_Writer->m_Info = Info;
- Result_t result = m_Writer->OpenWrite(filename, essence_descriptor, essence_sub_descriptor_list,
+ Result_t result = m_Writer->OpenWrite(filename, picture_descriptor, jxs_sub_descriptor,
strategy, partition_space, header_size);
if ( KM_SUCCESS(result) )
diff --git a/src/AS_02_JXS.h b/src/AS_02_JXS.h
index 6ef6aea..864110a 100644
--- a/src/AS_02_JXS.h
+++ b/src/AS_02_JXS.h
@@ -49,7 +49,7 @@ NOTE: ciphertext support for clip-wrapped PCM is not yet complete.
#include "Metadata.h"
#include "AS_02.h"
-#include "AS_DCP_JXS.h"
+#include "JXS.h"
namespace AS_02
{
@@ -77,8 +77,8 @@ namespace AS_02
// the operation cannot be completed or if nonsensical data is discovered
// in the essence descriptor.
Result_t OpenWrite(const std::string& filename, const ASDCP::WriterInfo&,
- ASDCP::MXF::FileDescriptor* essence_descriptor,
- ASDCP::MXF::InterchangeObject_list_t& essence_sub_descriptor_list,
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
const ASDCP::Rational& edit_rate, const ui32_t& header_size = 16384,
const IndexStrategy_t& strategy = IS_FOLLOW, const ui32_t& partition_space = 10);
diff --git a/src/AS_DCP_JXS.cpp b/src/AS_DCP_JXS.cpp
index 3dbbedc..5fec863 100644
--- a/src/AS_DCP_JXS.cpp
+++ b/src/AS_DCP_JXS.cpp
@@ -1,5 +1,5 @@
/*
-Copyright (c) 2004-2016, John Hurst,
+Copyright (c) 2004-2021, John Hurst,
Copyright (c) 2020, Thomas Richter Fraunhofer IIS
All rights reserved.
@@ -39,447 +39,10 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
using namespace ASDCP::JXS;
using Kumu::GenRandomValue;
-//------------------------------------------------------------------------------------------
-
static std::string JXS_PACKAGE_LABEL = "File Package: SMPTE 2124 frame wrapping of JPEG XS codestreams";
//static std::string JP2K_S_PACKAGE_LABEL = "File Package: SMPTE 429-10 frame wrapping of stereoscopic JPEG XS codestreams";
static std::string PICT_DEF_LABEL = "Picture Track";
-static int s_exp_lookup[16] = { 0, 2, 4, 8, 16, 32, 64, 128, 256, 512, 1024,2048, 4096, 8192, 16384, 32768 };
-
-//
-std::ostream&
-ASDCP::JXS::operator << (std::ostream& strm, const PictureDescriptor& PDesc)
-{
- strm << " AspectRatio: " << PDesc.AspectRatio.Numerator << "/" << PDesc.AspectRatio.Denominator << std::endl;
- strm << " EditRate: " << PDesc.EditRate.Numerator << "/" << PDesc.EditRate.Denominator << std::endl;
- strm << " SampleRate: " << PDesc.SampleRate.Numerator << "/" << PDesc.SampleRate.Denominator << std::endl;
- strm << " StoredWidth: " << (unsigned) PDesc.StoredWidth << std::endl;
- strm << " StoredHeight: " << (unsigned) PDesc.StoredHeight << std::endl;
- strm << " Wf: " << (unsigned) PDesc.Wf << std::endl; // width of the frame
- strm << " Hf: " << (unsigned) PDesc.Hf << std::endl; // height of the frame
- strm << " ContainerDuration: " << (unsigned) PDesc.ContainerDuration << std::endl;
-
- strm << "-- JPEG XS Metadata --" << std::endl;
- strm << " ImageComponents:" << std::endl;
- strm << " bits h-sep v-sep" << std::endl;
-
- ui32_t i;
- for ( i = 0; i < PDesc.Nc && i < MaxComponents; ++i )
- {
- strm << " " << std::setw(4) << PDesc.ImageComponents[i].Bc
- << " " << std::setw(5) << PDesc.ImageComponents[i].Sx
- << " " << std::setw(5) << PDesc.ImageComponents[i].Sy
- << std::endl;
- }
-
- strm << " Slice height: " << (short) PDesc.Hsl << std::endl;
- strm << " Profile: " << (short) PDesc.Ppih << std::endl;
- strm << " Level: " << (short) (PDesc.Plev >> 8) << std::endl;
- strm << " Sublevel: " << (short) (PDesc.Plev & 0xff) << std::endl;
- strm << " Column Width: " << (short) (PDesc.Cw) << std::endl;
- strm << " Maximum Bit Rate: " << (PDesc.MaximumBitRate) << std::endl;
- strm << " Primaries: " << (short) (PDesc.Primaries) << std::endl;
- strm << " Transfer Curve: " << (short) (PDesc.TransferCurve) << std::endl;
- strm << " Matrix: " << (short) (PDesc.Matrix) << std::endl;
- strm << " full range: " << (PDesc.fullRange?("yes"):("no")) << std::endl;
- /*
- ** thor: at this point, do not print the CAP marker
- */
-
- return strm;
-}
-
-//
-void
-ASDCP::JXS::PictureDescriptorDump(const PictureDescriptor& PDesc, FILE* stream)
-{
- if ( stream == 0 )
- stream = stderr;
-
- fprintf(stream, "\
- AspectRatio: %d/%d\n\
- EditRate: %d/%d\n\
- SampleRate: %d/%d\n\
- StoredWidth: %u\n\
- StoredHeight: %u\n\
- Wf: %u\n\
- Hf: %u\n\
- Profile: %u\n\
- Level: %u\n\
- Sublevel: %u\n\
- Maximum BitRate: %u\n\
- ContainerDuration: %u\n\
- Primaries: %u\n\
- Transfer Curve: %u\n\
- Matrix: %u\n\
- full range: %s\n",
- PDesc.AspectRatio.Numerator, PDesc.AspectRatio.Denominator,
- PDesc.EditRate.Numerator, PDesc.EditRate.Denominator,
- PDesc.SampleRate.Numerator, PDesc.SampleRate.Denominator,
- PDesc.StoredWidth,
- PDesc.StoredHeight,
- PDesc.Wf,
- PDesc.Hf,
- PDesc.Ppih,
- PDesc.Plev >> 4,
- PDesc.Plev & 0x0f,
- PDesc.MaximumBitRate,
- PDesc.ContainerDuration,
- PDesc.Primaries,
- PDesc.TransferCurve,
- PDesc.Matrix,
- PDesc.fullRange?("yes"):("no")
- );
-
- fprintf(stream, "-- JPEG XS Metadata --\n");
- fprintf(stream, " ImageComponents:\n");
- fprintf(stream, " bits h-sep v-sep\n");
-
- ui32_t i;
- for ( i = 0; i < PDesc.Nc && i < MaxComponents; i++ )
- {
- fprintf(stream, " %4d %5d %5d\n",
- PDesc.ImageComponents[i].Bc,
- PDesc.ImageComponents[i].Sx,
- PDesc.ImageComponents[i].Sy
- );
- }
-}
-
-//
-ASDCP::Result_t
-ASDCP::JXS_PDesc_to_MD(const JXS::PictureDescriptor& PDesc,
- const ASDCP::Dictionary&dict,
- ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
- ASDCP::MXF::JPEGXSPictureSubDescriptor& EssenceSubDescriptor)
-{
- EssenceDescriptor.ContainerDuration = PDesc.ContainerDuration;
- EssenceDescriptor.SampleRate = PDesc.EditRate;
- EssenceDescriptor.FrameLayout = 0;
- EssenceDescriptor.StoredWidth = PDesc.StoredWidth;
- EssenceDescriptor.StoredHeight = PDesc.StoredHeight;
- EssenceDescriptor.AspectRatio = PDesc.AspectRatio;
-
- EssenceSubDescriptor.JPEGXSPpih = PDesc.Ppih;
- EssenceSubDescriptor.JPEGXSPlev = PDesc.Plev;
- EssenceSubDescriptor.JPEGXSWf = PDesc.Wf;
- EssenceSubDescriptor.JPEGXSHf = PDesc.Hf;
- EssenceSubDescriptor.JPEGXSNc = PDesc.Nc;
-
- // Copy the value of the columns, but only if there are some
- if (PDesc.Cw) {
- EssenceSubDescriptor.JPEGXSCw = optional_property<ui16_t>(PDesc.Cw);
- } else {
- EssenceSubDescriptor.JPEGXSCw.set_has_value(false);
- }
-
- // Copy the slice height. Actually, this is optional
- // and does not necessarily require copying all the time,
- // but let's copy it nevertheless.
- EssenceSubDescriptor.JPEGXSHsl = optional_property<ui16_t>(PDesc.Hsl);
-
- if (PDesc.MaximumBitRate) {
- EssenceSubDescriptor.JPEGXSMaximumBitRate = PDesc.MaximumBitRate;
- } else {
- EssenceSubDescriptor.JPEGXSMaximumBitRate.set_has_value(false);
- }
-
- const ui32_t cdt_buffer_len = 8 * 2; // at most 8 components.
- byte_t tmp_buffer[cdt_buffer_len];
- int i,comps = (PDesc.Nc > 8)?8:PDesc.Nc;
- EssenceSubDescriptor.JPEGXSComponentTable.Length(4 + (comps << 1));
- // thor: unclear whether the marker size is part of this data.
- tmp_buffer[0] = 0xff;
- tmp_buffer[1] = 0x13; // the marker
- tmp_buffer[2] = 0x00;
- tmp_buffer[3] = comps * 2 + 2; // The size.
- for(i = 0;i < comps;i++) {
- tmp_buffer[4 + (i << 1)] = PDesc.ImageComponents[i].Bc;
- tmp_buffer[5 + (i << 1)] = (PDesc.ImageComponents[i].Sx << 4) | (PDesc.ImageComponents[i].Sy);
- }
-
- memcpy(EssenceSubDescriptor.JPEGXSComponentTable.Data(), tmp_buffer, 4 + (comps << 1));
-
- //
- switch(PDesc.Primaries) {
- case 1:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_ITU709);
- break;
- case 5:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_ITU470_PAL);
- break;
- case 6:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_SMPTE170M);
- break;
- case 9:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_ITU2020);
- break;
- case 10:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_SMPTE_DCDM);
- break;
- case 11:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_TheatricalViewingEnvironment);
- break;
- case 12:
- EssenceDescriptor.ColorPrimaries = dict.ul(ASDCP::MDD_ColorPrimaries_P3D65);
- break;
- default:
- return RESULT_PARAM;
- break;
- }
-
- switch(PDesc.TransferCurve) {
- case 1:
- case 6:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_ITU709);
- break;
- case 5: // Display Gamma 2.8, BT.470-6 This does not seem to be supported
- case 9: // Log(100:1) range This does not seem to be supported
- case 10:// Log(100*Sqrt(10):1 range)
- return Kumu::RESULT_NOTIMPL;
- break;
- case 8:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_linear);
- break;
- case 11:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_IEC6196624_xvYCC);
- break;
- case 13:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_sRGB);
- break;
- case 14:
- case 15:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_ITU2020);
- break;
- case 16:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_SMPTEST2084);
- break;
- case 17:
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_ST428);
- break;
- case 18: // HLG
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_HLG);
- break;
- case 12: // Rec. BT.1361
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_BT1361);
- break;
- case 4: // Rec. BT.470
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_BT470);
- break;
- case 7: // SMPTE 240M
- EssenceDescriptor.TransferCharacteristic = dict.ul(ASDCP::MDD_TransferCharacteristic_ST240M);
- break;
- case 2: // Unspecified. This leaves the data intentionally undefined.
- EssenceDescriptor.TransferCharacteristic.set_has_value(false);
- break;
- default:
- return RESULT_PARAM;
- break;
- }
- //
- switch(PDesc.Matrix) {
- case 0: // Identity matrix. Use the BGR coding equations.
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_BGR);
- break;
- case 4: // Title 47.
- case 10: // ITU 2020 constant luminance? Does not seem to be supported
- case 11: // SMPTE ST-2085
- return Kumu::RESULT_NOTIMPL;
- case 1:
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_709);
- break;
- // Note: Matrix=2 does not set the optional parameter. This is intentional.
- case 5:
- case 6:
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_601);
- break;
- case 9: // ITU 2020 non-constant luminance?
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_Rec2020);
- break;
- case 2: // This is unspecified. The metadata item remains undefined on purpose.
- EssenceDescriptor.CodingEquations.set_has_value(false);
- break;
- case 7: // ST 240M
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_ST240M);
- break;
- case 8: // YCgCo
- EssenceDescriptor.CodingEquations = dict.ul(ASDCP::MDD_CodingEquations_YCGCO);
- break;
- default:
- return RESULT_PARAM;
- break;
- }
- //
-#if 0
- if (rgba) {
- byte_t layout[ASDCP::MXF::RGBAValueLength];
- if (m_bFullRange) {
- rgba->ComponentMaxRef = (1UL << m_ucPrecision) - 1;
- rgba->ComponentMinRef = 0;
- } else {
- rgba->ComponentMaxRef = 235 * (1UL << (m_ucPrecision - 8));
- rgba->ComponentMinRef = 16 * (1UL << (m_ucPrecision - 8));
- }
- layout[0] = 'R';
- layout[1] = m_ucPrecision;
- layout[2] = 'G';
- layout[3] = m_ucPrecision;
- layout[4] = 'B';
- layout[5] = m_ucPrecision;
- layout[6] = 0;
-#endif
- return RESULT_OK;
-}
-
-//
-ASDCP::Result_t
-ASDCP::MD_to_JXS_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
- const ASDCP::MXF::JPEGXSPictureSubDescriptor& EssenceSubDescriptor,
- const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
- ASDCP::JXS::PictureDescriptor& PDesc)
-{
- const Dictionary *dict = &ASDCP::DefaultSMPTEDict();
- const ASDCP::MXF::RGBAEssenceDescriptor *rgba = dynamic_cast<const ASDCP::MXF::RGBAEssenceDescriptor *>(&EssenceDescriptor);
- const ASDCP::MXF::CDCIEssenceDescriptor *cdci = dynamic_cast<const ASDCP::MXF::CDCIEssenceDescriptor *>(&EssenceDescriptor);
- memset(&PDesc, 0, sizeof(PDesc));
-
- PDesc.EditRate = EditRate;
- PDesc.SampleRate = SampleRate;
- assert(EssenceDescriptor.ContainerDuration.const_get() <= 0xFFFFFFFFL);
- PDesc.ContainerDuration = static_cast<ui32_t>(EssenceDescriptor.ContainerDuration.const_get());
- PDesc.StoredWidth = EssenceDescriptor.StoredWidth;
- PDesc.StoredHeight = EssenceDescriptor.StoredHeight;
- PDesc.AspectRatio = EssenceDescriptor.AspectRatio;
-
- PDesc.Ppih = EssenceSubDescriptor.JPEGXSPpih;
- PDesc.Plev = EssenceSubDescriptor.JPEGXSPlev;
- PDesc.Wf = EssenceSubDescriptor.JPEGXSWf;
- PDesc.Hf = EssenceSubDescriptor.JPEGXSHf;
- PDesc.Nc = EssenceSubDescriptor.JPEGXSNc;
-
- if (EssenceDescriptor.ColorPrimaries.empty()) {
- PDesc.Primaries = 1; // If not set, let us assume 709 primaries. Yuck!
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_ITU709)) {
- PDesc.Primaries = 1;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_ITU470_PAL)) {
- PDesc.Primaries = 5;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_SMPTE170M)) {
- PDesc.Primaries = 6;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_ITU2020)) {
- PDesc.Primaries = 9;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_SMPTE_DCDM)) {
- PDesc.Primaries = 10;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_TheatricalViewingEnvironment)) {
- PDesc.Primaries = 11;
- } else if (EssenceDescriptor.ColorPrimaries == dict->ul(ASDCP::MDD_ColorPrimaries_P3D65)) {
- PDesc.Primaries = 12;
- } else {
- PDesc.Primaries = 0;
- }
-
- if (EssenceDescriptor.TransferCharacteristic.empty()) {
- PDesc.TransferCurve = 2; // Unspecified
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_ITU709)) {
- PDesc.TransferCurve = 1;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_linear)) {
- PDesc.TransferCurve = 8;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_IEC6196624_xvYCC)) {
- PDesc.TransferCurve = 11;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_sRGB)) {
- PDesc.TransferCurve = 13;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_SMPTEST2084)) {
- PDesc.TransferCurve = 16;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_ST428)) {
- PDesc.TransferCurve = 17;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_HLG)) {
- PDesc.TransferCurve = 18;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_BT1361)) {
- PDesc.TransferCurve = 12;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_BT470)) {
- PDesc.TransferCurve = 4;
- } else if (EssenceDescriptor.TransferCharacteristic == dict->ul(ASDCP::MDD_TransferCharacteristic_ST240M)) {
- PDesc.TransferCurve = 7;
- } else {
- PDesc.TransferCurve = 0;
- }
-
- if (EssenceDescriptor.CodingEquations.empty()) {
- PDesc.Matrix = 2;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_BGR)) {
- PDesc.Matrix = 0;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_709)) {
- PDesc.Matrix = 1;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_601)) {
- PDesc.Matrix = 5;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_Rec2020)) {
- PDesc.Matrix = 9;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_ST240M)) {
- PDesc.Matrix = 7;
- } else if (EssenceDescriptor.CodingEquations == dict->ul(ASDCP::MDD_CodingEquations_YCGCO)) {
- PDesc.Matrix = 8;
- } else {
- PDesc.Matrix = 0;
- }
-
- if (EssenceSubDescriptor.JPEGXSCw.const_get()==0 || EssenceSubDescriptor.JPEGXSCw.const_get() == 0)
- PDesc.Cw = 0;
- else
- PDesc.Cw = static_cast<ui16_t>(EssenceSubDescriptor.JPEGXSCw.const_get());
-
- PDesc.Hsl = static_cast<ui16_t>(EssenceSubDescriptor.JPEGXSHsl.const_get());
-
- PDesc.MaximumBitRate = static_cast<ui32_t>(EssenceSubDescriptor.JPEGXSMaximumBitRate.const_get());
-
- // JPEGXSComponentTable
- ui32_t tmp_size = EssenceSubDescriptor.JPEGXSComponentTable.Length();
-
- if (tmp_size > 4 && (tmp_size & 1) == 0 && (PDesc.Nc << 1) + 4 == tmp_size) {
- const byte_t *data = EssenceSubDescriptor.JPEGXSComponentTable.RoData() + 4;
- for(int i = 0;i < PDesc.Nc;i++) {
- PDesc.ImageComponents[i].Bc = data[0];
- PDesc.ImageComponents[i].Sy = data[1] >> 4;
- PDesc.ImageComponents[i].Sx = data[1] & 0x0f;
- data += 2;
- }
- } else {
- return RESULT_FAIL;
- }
-
- if (rgba) {
- if (rgba->ComponentMinRef.empty()) {
- if (rgba->ComponentMaxRef.empty()) {
- PDesc.fullRange = false;
- } else if (rgba->ComponentMaxRef == (1UL << PDesc.ImageComponents[0].Bc) - 1) {
- PDesc.fullRange = true;
- } else {
- PDesc.fullRange = false;
- }
- } else if (rgba->ComponentMinRef == 0) {
- PDesc.fullRange = true;
- } else {
- PDesc.fullRange = false;
- }
- } else if (cdci) {
- if (cdci->BlackRefLevel.empty()) {
- if (cdci->WhiteReflevel.empty()) {
- PDesc.fullRange = false;
- } else if (cdci->WhiteReflevel == (1UL << PDesc.ImageComponents[0].Bc) - 1) {
- PDesc.fullRange = true;
- } else {
- PDesc.fullRange = false;
- }
- } else if (cdci->BlackRefLevel == 0) {
- PDesc.fullRange = true;
- } else {
- PDesc.fullRange = false;
- }
- } else {
- PDesc.fullRange = false;
- }
-
- return RESULT_OK;
-}
//------------------------------------------------------------------------------------------
@@ -498,7 +61,6 @@ class ih__Reader : public ASDCP::h__ASDCPReader
ASDCP_NO_COPY_CONSTRUCT(ih__Reader);
public:
- PictureDescriptor m_PDesc; // codestream parameter list
ih__Reader(const Dictionary *d) :
ASDCP::h__ASDCPReader(d), m_EssenceDescriptor(0), m_EssenceSubDescriptor(0), m_Format(ESS_UNKNOWN) {}
@@ -670,8 +232,6 @@ ih__Reader::OpenRead(const std::string& filename, EssenceType_t type)
DefaultLogSink().Error("'type' argument unexpected: %x\n", type);
return RESULT_STATE;
}
-
- result = MD_to_JXS_PDesc(*m_EssenceDescriptor, *m_EssenceSubDescriptor, m_EditRate, m_SampleRate, m_PDesc);
}
return result;
@@ -711,26 +271,6 @@ public:
};
-
-//------------------------------------------------------------------------------------------
-
-
-//
-void
-ASDCP::JXS::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
-{
- if ( stream == 0 )
- stream = stderr;
-
- fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
-
- fputc('\n', stream);
-
- if ( dump_len > 0 )
- Kumu::hexdump(m_Data, dump_len, stream);
-}
-
-
//------------------------------------------------------------------------------------------
ASDCP::JXS::MXFReader::MXFReader()
@@ -829,21 +369,6 @@ ASDCP::JXS::MXFReader::LocateFrame(ui32_t FrameNum, Kumu::fpos_t& streamOffset,
// Fill the struct with the values from the file's header.
// Returns RESULT_INIT if the file is not open.
ASDCP::Result_t
-ASDCP::JXS::MXFReader::FillPictureDescriptor(PictureDescriptor& PDesc) const
-{
- if ( m_Reader && m_Reader->m_File.IsOpen() )
- {
- PDesc = m_Reader->m_PDesc;
- return RESULT_OK;
- }
-
- return RESULT_INIT;
-}
-
-
-// Fill the struct with the values from the file's header.
-// Returns RESULT_INIT if the file is not open.
-ASDCP::Result_t
ASDCP::JXS::MXFReader::FillWriterInfo(WriterInfo& Info) const
{
if ( m_Reader && m_Reader->m_File.IsOpen() )
@@ -897,7 +422,6 @@ class ih__Writer : public ASDCP::h__ASDCPWriter
JPEGXSPictureSubDescriptor* m_EssenceSubDescriptor;
public:
- PictureDescriptor m_PDesc;
byte_t m_EssenceUL[SMPTE_UL_LENGTH];
ih__Writer(const Dictionary *d) : ASDCP::h__ASDCPWriter(d), m_EssenceSubDescriptor(0) {
@@ -907,8 +431,10 @@ public:
virtual ~ih__Writer(){}
Result_t OpenWrite(const std::string&, EssenceType_t type, ui32_t HeaderSize);
- Result_t SetSourceStream(const PictureDescriptor&, const std::string& label,
- ASDCP::Rational LocalEditRate = ASDCP::Rational(0,0));
+ Result_t SetSourceStream(ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const std::string& label,
+ const ASDCP::Rational& edit_rate);
Result_t WriteFrame(const JXS::FrameBuffer&, bool add_index, AESEncContext*, HMACContext*);
Result_t Finalize();
};
@@ -957,72 +483,87 @@ ih__Writer::OpenWrite(const std::string& filename, EssenceType_t type, ui32_t He
// Automatically sets the MXF file's metadata from the first jpeg codestream stream.
ASDCP::Result_t
-ih__Writer::SetSourceStream(const PictureDescriptor& PDesc, const std::string& label, ASDCP::Rational LocalEditRate)
+ih__Writer::SetSourceStream(
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const std::string& label,
+ const ASDCP::Rational& edit_rate)
{
assert(m_Dict);
if ( ! m_State.Test_INIT() )
return RESULT_STATE;
- if ( LocalEditRate == ASDCP::Rational(0,0) )
- LocalEditRate = PDesc.EditRate;
+ if ( edit_rate == ASDCP::Rational(0,0) )
+ {
+ DefaultLogSink().Error("Edit rate not set before call to ih__Writer::SetSourceStream.\n");
+ return RESULT_PARAM;
+ }
- m_PDesc = PDesc;
- assert(m_Dict);
assert(m_EssenceDescriptor);
+ m_EssenceDescriptor->Copy(picture_descriptor);
+
assert(m_EssenceSubDescriptor);
- Result_t result = JXS_PDesc_to_MD(m_PDesc, *m_Dict,
- *static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(m_EssenceDescriptor),
- *m_EssenceSubDescriptor);
+ m_EssenceSubDescriptor->Copy(jxs_sub_descriptor);
- if ( ASDCP_SUCCESS(result) )
- {
- ASDCP::MXF::GenericPictureEssenceDescriptor *gpe = static_cast<ASDCP::MXF::RGBAEssenceDescriptor*>(m_EssenceDescriptor);
- switch(PDesc.Ppih) {
- case 0: // Profile_Unrestricted
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSUnrestrictedCodestream));
- break;
- case 0x1500: // Profile_Light422
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSLight422_10Profile));
- break;
- case 0x1a00: // Profile_Light444
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSLight444_12Profile));
- break;
- case 0x2500: // Profile_LightSubline
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSLightSubline422_10Profile));
- break;
- case 0x3540: // Profile_Main422
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSMain422_10Profile));
- break;
- case 0x3a40: // Profile_Main444
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSMain444_12Profile));
- break;
- case 0x3e40: // Profile_Main4444
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSMain4444_12Profile));
- break;
- case 0x4a40: // Profile_High444
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSHigh444_12Profile));
- break;
- case 0x4e40: // Profile_High4444
- gpe->PictureEssenceCoding.Set(m_Dict->ul(MDD_JPEGXSHigh4444_12Profile));
- break;
- default:
- return RESULT_PARAM;
- }
- memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEGXSEssence), SMPTE_UL_LENGTH);
- m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
- result = m_State.Goto_READY();
- }
+ memcpy(m_EssenceUL, m_Dict->ul(MDD_JPEGXSEssence), SMPTE_UL_LENGTH);
+ m_EssenceUL[SMPTE_UL_LENGTH-1] = 1; // first (and only) essence container
+
+ Result_t result = m_State.Goto_READY();
if ( ASDCP_SUCCESS(result) )
{
result = WriteASDCPHeader(label, UL(m_Dict->ul(MDD_MXFGCFUFrameWrappedPictureElement)),
PICT_DEF_LABEL, UL(m_EssenceUL), UL(m_Dict->ul(MDD_PictureDataDef)),
- LocalEditRate, derive_timecode_rate_from_edit_rate(m_PDesc.EditRate));
+ edit_rate, derive_timecode_rate_from_edit_rate(edit_rate));
}
return result;
}
+//
+bool
+ASDCP::JXS::lookup_PictureEssenceCoding(int value, ASDCP::UL& ul)
+{
+ const ASDCP::Dictionary& dict = DefaultSMPTEDict();
+ switch ( value )
+ {
+ case 0: // Profile_Unrestricted
+ ul = dict.ul(MDD_JPEGXSUnrestrictedCodestream);
+ break;
+ case 0x1500: // Profile_Light422
+ ul = dict.ul(MDD_JPEGXSLight422_10Profile);
+ break;
+ case 0x1a00: // Profile_Light444
+ ul = dict.ul(MDD_JPEGXSLight444_12Profile);
+ break;
+ case 0x2500: // Profile_LightSubline
+ ul = dict.ul(MDD_JPEGXSLightSubline422_10Profile);
+ break;
+ case 0x3540: // Profile_Main422
+ ul = dict.ul(MDD_JPEGXSMain422_10Profile);
+ break;
+ case 0x3a40: // Profile_Main444
+ ul = dict.ul(MDD_JPEGXSMain444_12Profile);
+ break;
+ case 0x3e40: // Profile_Main4444
+ ul = dict.ul(MDD_JPEGXSMain4444_12Profile);
+ break;
+ case 0x4a40: // Profile_High444
+ ul = dict.ul(MDD_JPEGXSHigh444_12Profile);
+ break;
+ case 0x4e40: // Profile_High4444
+ ul = dict.ul(MDD_JPEGXSHigh4444_12Profile);
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+
// Writes a frame of essence to the MXF file. If the optional AESEncContext
// argument is present, the essence is encrypted prior to writing.
// Fails if the file is not open, is finalized, or an operating system
@@ -1139,8 +680,11 @@ ASDCP::JXS::MXFWriter::RIP()
// Open the file for writing. The file must not exist. Returns error if
// the operation cannot be completed.
ASDCP::Result_t
-ASDCP::JXS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo& Info,
- const PictureDescriptor& PDesc, ui32_t HeaderSize)
+ASDCP::JXS::MXFWriter::OpenWrite(
+ const std::string& filename, const WriterInfo& Info,
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const ASDCP::Rational& edit_rate, ui32_t HeaderSize)
{
if ( Info.LabelSetType == LS_MXF_SMPTE )
m_Writer = new h__Writer(&DefaultSMPTEDict());
@@ -1150,9 +694,9 @@ ASDCP::JXS::MXFWriter::OpenWrite(const std::string& filename, const WriterInfo&
m_Writer->m_Info = Info;
Result_t result = m_Writer->OpenWrite(filename, ASDCP::ESS_JPEG_XS, HeaderSize);
-
+
if ( ASDCP_SUCCESS(result) )
- result = m_Writer->SetSourceStream(PDesc, JXS_PACKAGE_LABEL);
+ result = m_Writer->SetSourceStream(picture_descriptor, jxs_sub_descriptor, JXS_PACKAGE_LABEL, edit_rate);
if ( ASDCP_FAILURE(result) )
m_Writer.release();
diff --git a/src/AS_DCP_JXS.h b/src/AS_DCP_JXS.h
index dcd98e0..fd334df 100644
--- a/src/AS_DCP_JXS.h
+++ b/src/AS_DCP_JXS.h
@@ -79,16 +79,8 @@ This project depends upon the following libraries:
#ifndef _AS_DCP_JXS_H_
#define _AS_DCP_JXS_H_
-#include <KM_error.h>
-#include <KM_fileio.h>
-#include <stdio.h>
-#include <stdarg.h>
-#include <math.h>
-#include <iosfwd>
-#include <string>
-#include <cstring>
-#include <list>
#include "AS_DCP.h"
+#include "JXS.h"
#include "Metadata.h"
//--------------------------------------------------------------------------------
@@ -100,134 +92,7 @@ namespace ASDCP {
//
namespace JXS
{
- const ui32_t MaxComponents = 4; // ISO 21122-1 Annex A.2 up to 8 components
- const ui32_t MaxHorizontalLevels = 15;
- const ui32_t MaxVerticalLevels = 2;
-
-#pragma pack(1)
- struct ImageComponent_t // Essentially, a lookalike of the CDT marker, just with less bit-packing
- {
- ui8_t Bc; // Bitdepth (literal, not -1)
- ui8_t Sx;
- ui8_t Sy; // Subsampling factors, horizontal and vertically. Bit-packed in the marker.
- };
-#pragma pack()
-
- struct PictureDescriptor
- {
- Rational EditRate;
- ui32_t ContainerDuration;
- Rational SampleRate;
- ui32_t StoredWidth;
- ui32_t StoredHeight;
- Rational AspectRatio;
- ui16_t Ppih; // Profile, copy from the PIH marker
- ui16_t Plev; // Level and sublevel, copy from the PIH marker
- ui16_t Wf; // Frame width, copy from the PIH marker
- ui16_t Hf; // Frame height, copy from the PIH marker
- ui16_t Hsl; // slice height, copy from the PIH marker
- ui16_t Cw; // column width, or 0 for no columns, copy from the PIH marker
- ui8_t Nc; // number of components, copy from the PIH marker
- ui32_t MaximumBitRate; // bit rate in MB/sec, or 0 if not known
- ui8_t Primaries; // Color primaries as defined by CICP
- ui8_t TransferCurve; // Transfer curve as defined by CICP
- ui8_t Matrix; // Transform matrix, as defined by CICP
- bool fullRange; // If true, no head and toe region
- ImageComponent_t ImageComponents[MaxComponents]; // These are copies from the CDT (component table)
- };
- // Print debugging information to std::ostream
- std::ostream& operator << (std::ostream& strm, const PictureDescriptor& pdesc);
- // Print debugging information to stream (stderr default)
- void PictureDescriptorDump(const PictureDescriptor&, FILE* = 0);
-
- //
- class FrameBuffer : public ASDCP::FrameBuffer
- {
- public:
- FrameBuffer() {}
- FrameBuffer(ui32_t size) { Capacity(size); }
- virtual ~FrameBuffer() {}
-
- // Print debugging information to stream (stderr default)
- void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
- };
-
-
- // An object which opens and reads a JPEG XS codestream file. The file is expected
- // to contain exactly one complete frame of picture essence as an unwrapped (raw)
- // ISO/IEC 21122 codestream.
- class CodestreamParser
- {
- class h__CodestreamParser;
- mem_ptr<h__CodestreamParser> m_Parser;
- ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
-
- public:
- CodestreamParser();
- virtual ~CodestreamParser();
-
- // Opens a file for reading, parses enough data to provide a complete
- // set of stream metadata for the MXFWriter below.
- // The frame buffer's PlaintextOffset parameter will be set to the first
- // byte of the data segment. Set this value to zero if you want
- // encrypted headers.
- Result_t OpenReadFrame(const std::string& filename, FrameBuffer&) const;
-
- // Fill a PictureDescriptor struct with the values from the file's codestream.
- // Returns RESULT_INIT if the file is not open.
- Result_t FillPictureDescriptor(PictureDescriptor&) const;
- };
-
- // Parses the data in the frame buffer to fill in the picture descriptor. Copies
- // the offset of the image data into start_of_data. Returns error if the parser fails.
- Result_t ParseMetadataIntoDesc(const FrameBuffer&, PictureDescriptor&, byte_t* start_of_data = 0);
-
- // An object which reads a sequence of files containing JPEG XS pictures.
- class SequenceParser
- {
- class h__SequenceParser;
- mem_ptr<h__SequenceParser> m_Parser;
- ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
-
- public:
- SequenceParser();
- virtual ~SequenceParser();
-
- // Opens a directory for reading. The directory is expected to contain one or
- // more files, each containing the codestream for exactly one picture. The
- // files must be named such that the frames are in temporal order when sorted
- // alphabetically by filename. The parser will automatically parse enough data
- // from the first file to provide a complete set of stream metadata for the
- // MXFWriter below. If the "pedantic" parameter is given and is true, the
- // parser will check the metadata for each codestream and fail if a
- // mismatch is detected.
- Result_t OpenRead(const std::string& filename) const;
-
- // Opens a file sequence for reading. The sequence is expected to contain one or
- // more filenames, each naming a file containing the codestream for exactly one
- // picture. The parser will automatically parse enough data
- // from the first file to provide a complete set of stream metadata for the
- // MXFWriter below. If the "pedantic" parameter is given and is true, the
- // parser will check the metadata for each codestream and fail if a
- // mismatch is detected.
- Result_t OpenRead(const std::list<std::string>& file_list) const;
-
- // Fill a PictureDescriptor struct with the values from the first file's codestream.
- // Returns RESULT_INIT if the directory is not open.
- Result_t FillPictureDescriptor(PictureDescriptor&) const;
-
- // Rewind the directory to the beginning.
- Result_t Reset() const;
-
- // Reads the next sequential frame in the directory and places it in the
- // frame buffer. Fails if the buffer is too small or the direcdtory
- // contains no more files.
- // The frame buffer's PlaintextOffset parameter will be set to the first
- // byte of the data segment. Set this value to zero if you want
- // encrypted headers.
- Result_t ReadFrame(FrameBuffer&) const;
- };
-
+ bool lookup_PictureEssenceCoding(int value, ASDCP::UL& ul);
//
class MXFWriter
@@ -250,7 +115,9 @@ namespace ASDCP {
// the operation cannot be completed or if nonsensical data is discovered
// in the essence descriptor.
Result_t OpenWrite(const std::string& filename, const WriterInfo&,
- const PictureDescriptor&, ui32_t HeaderSize = 16384);
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_sub_descriptor,
+ const ASDCP::Rational& edit_rate, ui32_t header_size = 16384);
// Writes a frame of essence to the MXF file. If the optional AESEncContext
// argument is present, the essence is encrypted prior to writing.
@@ -286,10 +153,6 @@ namespace ASDCP {
// Returns RESULT_INIT if the file is not open.
Result_t Close() const;
- // Fill an AudioDescriptor struct with the values from the file's header.
- // Returns RESULT_INIT if the file is not open.
- Result_t FillPictureDescriptor(PictureDescriptor&) const;
-
// Fill a WriterInfo struct with the values from the file's header.
// Returns RESULT_INIT if the file is not open.
Result_t FillWriterInfo(WriterInfo&) const;
@@ -318,16 +181,12 @@ namespace ASDCP {
void DumpIndex(FILE* = 0) const;
};
}
- Result_t MD_to_JXS_PDesc(const ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
- const ASDCP::MXF::JPEGXSPictureSubDescriptor& EssenceSubDescriptor,
- const ASDCP::Rational& EditRate, const ASDCP::Rational& SampleRate,
- ASDCP::JXS::PictureDescriptor& PDesc);
-
- Result_t JXS_PDesc_to_MD(const JXS::PictureDescriptor& PDesc,
- const ASDCP::Dictionary& dict,
- ASDCP::MXF::GenericPictureEssenceDescriptor& EssenceDescriptor,
- ASDCP::MXF::JPEGXSPictureSubDescriptor& EssenceSubDescriptor);
};
///
-#endif
+#endif // _AS_DCP_JXS_H_
+
+
+//
+// end AS_DCP_JXS.h
+//
diff --git a/src/JXS.cpp b/src/JXS.cpp
index 0cb6eed..7be7ce9 100644
--- a/src/JXS.cpp
+++ b/src/JXS.cpp
@@ -120,19 +120,19 @@ ASDCP::JXS::Accessor::PIH::Dump(FILE* stream) const
fprintf(stream, "PIH: \n");
fprintf(stream, " LpihSize: %hu\n", LpihSize());
- fprintf(stream, " LcodSize: %hu\n", LcodSize());
+ fprintf(stream, " LcodSize: %u\n", LcodSize());
fprintf(stream, " Ppih: %hu\n", Ppih());
fprintf(stream, " Plev: %hu\n", Plev());
fprintf(stream, " Wf: %hu\n", Wf());
fprintf(stream, " Hf: %hu\n", Hf());
fprintf(stream, " Cw: %hu\n", Cw());
fprintf(stream, " Hsl: %hu\n", Hsl());
- fprintf(stream, " Nc: %hu\n", Nc());
- fprintf(stream, " Ng: %hu\n", Ng());
- fprintf(stream, " Ss: %hu\n", Ss());
- fprintf(stream, " Cpih: %hu\n", Cpih());
- fprintf(stream, " Nlx: %hu\n", Nlx());
- fprintf(stream, " Nly: %hu\n", Nly());
+ fprintf(stream, " Nc: %hhu\n", Nc());
+ fprintf(stream, " Ng: %hhu\n", Ng());
+ fprintf(stream, " Ss: %hhu\n", Ss());
+ fprintf(stream, " Cpih: %hhu\n", Cpih());
+ fprintf(stream, " Nlx: %hhu\n", Nlx());
+ fprintf(stream, " Nly: %hhu\n", Nly());
Kumu::hexdump(m_MarkerData, m_DataSize, stream);
}
@@ -146,11 +146,168 @@ ASDCP::JXS::Accessor::CDT::Dump(FILE* stream) const
fprintf(stream, "CDT: \n");
for (ui32_t i = 0; i < 3; i++) {
- fprintf(stream, " Component %u Bc: %hu\n", i,Bc(i));
- fprintf(stream, " Component %u Sx: %hu\n", i,Sx(i));
- fprintf(stream, " Component %u Sy: %hu\n", i,Sy(i));
+ fprintf(stream, " Component %u Bc: %hhu\n", i,Bc(i));
+ fprintf(stream, " Component %u Sx: %hhu\n", i,Sx(i));
+ fprintf(stream, " Component %u Sy: %hhu\n", i,Sy(i));
}
}
+
+//
+bool
+ASDCP::JXS::lookup_ColorPrimaries(int cicp_value, ASDCP::UL& ul)
+{
+ const ASDCP::Dictionary& dict = DefaultSMPTEDict();
+ switch ( cicp_value )
+ {
+ case 1:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_ITU709);
+ break;
+ case 5:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_ITU470_PAL);
+ break;
+ case 6:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_SMPTE170M);
+ break;
+ case 9:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_ITU2020);
+ break;
+ case 10:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_SMPTE_DCDM);
+ break;
+ case 11:
+ ul = dict.ul(ASDCP::MDD_TheatricalViewingEnvironment);
+ break;
+ case 12:
+ ul = dict.ul(ASDCP::MDD_ColorPrimaries_P3D65);
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+//
+bool
+ASDCP::JXS::lookup_TransferCharacteristic(int cicp_value, ASDCP::UL& ul)
+{
+ const ASDCP::Dictionary& dict = DefaultSMPTEDict();
+ switch ( cicp_value )
+ {
+ case 1:
+ case 6:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_ITU709);
+ break;
+ case 5: // Display Gamma 2.8, BT.470-6 This does not seem to be supported
+ case 9: // Log(100:1) range This does not seem to be supported
+ case 10:// Log(100*Sqrt(10):1 range)
+ return Kumu::RESULT_NOTIMPL;
+ break;
+ case 8:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_linear);
+ break;
+ case 11:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_IEC6196624_xvYCC);
+ break;
+ case 13:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_sRGB);
+ break;
+ case 14:
+ case 15:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_ITU2020);
+ break;
+ case 16:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_SMPTEST2084);
+ break;
+ case 17:
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_ST428);
+ break;
+ case 18: // HLG
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_HLG);
+ break;
+ case 12: // Rec. BT.1361
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_BT1361);
+ break;
+ case 4: // Rec. BT.470
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_BT470);
+ break;
+ case 7: // SMPTE 240M
+ ul = dict.ul(ASDCP::MDD_TransferCharacteristic_ST240M);
+ break;
+ case 2: // Unspecified. This leaves the data intentionally undefined.
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+//
+bool
+ASDCP::JXS::lookup_CodingEquations(int value, ASDCP::UL& ul)
+{
+ const ASDCP::Dictionary& dict = DefaultSMPTEDict();
+ switch ( value )
+ {
+ case 0: // Identity matrix. Use the BGR coding equations.
+ ul = dict.ul(ASDCP::MDD_CodingEquations_BGR);
+ break;
+ case 4: // Title 47.
+ case 10: // ITU 2020 constant luminance? Does not seem to be supported
+ case 11: // SMPTE ST-2085
+ return Kumu::RESULT_NOTIMPL;
+ case 1:
+ ul = dict.ul(ASDCP::MDD_CodingEquations_709);
+ break;
+ // Note: Matrix=2 does not set the optional parameter. This is intentional.
+ case 5:
+ case 6:
+ ul = dict.ul(ASDCP::MDD_CodingEquations_601);
+ break;
+ case 9: // ITU 2020 non-constant luminance?
+ ul = dict.ul(ASDCP::MDD_CodingEquations_Rec2020);
+ break;
+ case 2: // This is unspecified. The metadata item remains undefined on purpose.
+ break;
+ case 7: // ST 240M
+ ul = dict.ul(ASDCP::MDD_CodingEquations_ST240M);
+ break;
+ case 8: // YCgCo
+ ul = dict.ul(ASDCP::MDD_CodingEquations_YCGCO);
+ break;
+
+ default:
+ return false;
+ break;
+ }
+
+ return true;
+}
+
+
+//------------------------------------------------------------------------------------------
+
+
+//
+void
+ASDCP::JXS::FrameBuffer::Dump(FILE* stream, ui32_t dump_len) const
+{
+ if ( stream == 0 )
+ stream = stderr;
+
+ fprintf(stream, "Frame: %06u, %7u bytes", m_FrameNumber, m_Size);
+
+ fputc('\n', stream);
+
+ if ( dump_len > 0 )
+ Kumu::hexdump(m_Data, dump_len, stream);
+}
+
//
// end JXS.cpp
//
diff --git a/src/JXS.h b/src/JXS.h
index bdfc57e..4155f94 100644
--- a/src/JXS.h
+++ b/src/JXS.h
@@ -40,14 +40,31 @@ support parsing picture metadata from a codestream header.
// AS_DCP.h is included only for it's base type definitions.
#include <KM_platform.h>
#include <KM_util.h>
-#include <AS_DCP.h>
+#include <Metadata.h>
#include <assert.h>
namespace ASDCP
{
namespace JXS
{
- const byte_t Magic[] = { 0xff, 0x10, 0xff };
+ const ui32_t MaxComponents = 4; // ISO 21122-1 Annex A.2 up to 8 components
+ const ui32_t MaxHorizontalLevels = 15;
+ const ui32_t MaxVerticalLevels = 2;
+
+#pragma pack(1)
+ struct ImageComponent_t // Essentially, a lookalike of the CDT marker, just with less bit-packing
+ {
+ ui8_t Bc; // Bitdepth (literal, not -1)
+ ui8_t Sx;
+ ui8_t Sy; // Subsampling factors, horizontal and vertically. Bit-packed in the marker.
+ };
+#pragma pack()
+
+ const byte_t Magic[] = { 0xff, 0x10, 0xff };
+
+ bool lookup_ColorPrimaries(int value, ASDCP::UL& ul);
+ bool lookup_TransferCharacteristic(int value, ASDCP::UL& ul);
+ bool lookup_CodingEquations(int value, ASDCP::UL& ul);
enum Marker_t
{
@@ -229,11 +246,106 @@ namespace ASDCP
void Dump(FILE* stream = 0) const;
};
}
+
+ //
+ class FrameBuffer : public ASDCP::FrameBuffer
+ {
+ public:
+ FrameBuffer() {}
+ FrameBuffer(ui32_t size) { Capacity(size); }
+ virtual ~FrameBuffer() {}
+
+ // Print debugging information to stream (stderr default)
+ void Dump(FILE* = 0, ui32_t dump_bytes = 0) const;
+ };
+
+ // An object which opens and reads a JPEG XS codestream file. The file is expected
+ // to contain exactly one complete frame of picture essence as an unwrapped (raw)
+ // ISO/IEC 21122 codestream.
+ class CodestreamParser
+ {
+ class h__CodestreamParser;
+ mem_ptr<h__CodestreamParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(CodestreamParser);
+
+ public:
+ CodestreamParser();
+ virtual ~CodestreamParser();
+
+ // Opens a file for reading, parses enough data to provide a complete
+ // set of stream metadata for the MXFWriter below.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t OpenReadFrame(const std::string& filename, FrameBuffer&) const;
+
+ // Fill the MXF descriptor objects with the values from the file's codestream.
+ // Returns RESULT_INIT if the file is not open.
+ Result_t FillPictureDescriptor(
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor) const;
+ };
+
+ // Parses the data in the frame buffer to fill in the picture descriptor. Copies
+ // the offset of the image data into start_of_data. Returns error if the parser fails.
+ Result_t ParseMetadataIntoDesc(const FrameBuffer&,
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor,
+ byte_t* start_of_data = 0);
+
+ // An object which reads a sequence of files containing JPEG XS pictures.
+ class SequenceParser
+ {
+ class h__SequenceParser;
+ mem_ptr<h__SequenceParser> m_Parser;
+ ASDCP_NO_COPY_CONSTRUCT(SequenceParser);
+
+ public:
+ SequenceParser();
+ virtual ~SequenceParser();
+
+ // Opens a directory for reading. The directory is expected to contain one or
+ // more files, each containing the codestream for exactly one picture. The
+ // files must be named such that the frames are in temporal order when sorted
+ // alphabetically by filename. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const std::string& filename) const;
+
+ // Opens a file sequence for reading. The sequence is expected to contain one or
+ // more filenames, each naming a file containing the codestream for exactly one
+ // picture. The parser will automatically parse enough data
+ // from the first file to provide a complete set of stream metadata for the
+ // MXFWriter below. If the "pedantic" parameter is given and is true, the
+ // parser will check the metadata for each codestream and fail if a
+ // mismatch is detected.
+ Result_t OpenRead(const std::list<std::string>& file_list) const;
+
+ // Fill a PictureDescriptor struct with the values from the first file's codestream.
+ // Returns RESULT_INIT if the directory is not open.
+ Result_t FillPictureDescriptor(
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor) const;
+
+ // Rewind the directory to the beginning.
+ Result_t Reset() const;
+
+ // Reads the next sequential frame in the directory and places it in the
+ // frame buffer. Fails if the buffer is too small or the direcdtory
+ // contains no more files.
+ // The frame buffer's PlaintextOffset parameter will be set to the first
+ // byte of the data segment. Set this value to zero if you want
+ // encrypted headers.
+ Result_t ReadFrame(FrameBuffer&) const;
+ };
+
} //namespace JXS
} // namespace ASDCP
#endif // _JXS_H_
//
-// end JP2K.h
-// \ No newline at end of file
+// end JXS.h
+//
diff --git a/src/JXS_Codestream_Parser.cpp b/src/JXS_Codestream_Parser.cpp
index bb7b729..4d08c80 100644
--- a/src/JXS_Codestream_Parser.cpp
+++ b/src/JXS_Codestream_Parser.cpp
@@ -32,8 +32,6 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#include <KM_fileio.h>
-#include <AS_DCP.h>
-#include <AS_DCP_JXS.h>
#include <JXS.h>
#include <assert.h>
#include <KM_log.h>
@@ -46,15 +44,12 @@ class ASDCP::JXS::CodestreamParser::h__CodestreamParser
ASDCP_NO_COPY_CONSTRUCT(h__CodestreamParser);
public:
- PictureDescriptor m_PDesc;
+ ASDCP::MXF::GenericPictureEssenceDescriptor m_PDesc;
+ ASDCP::MXF::JPEGXSPictureSubDescriptor m_JxsSubdesc;
Kumu::FileReader m_File;
- h__CodestreamParser()
- {
- memset(&m_PDesc, 0, sizeof(m_PDesc));
- m_PDesc.EditRate = Rational(24, 1);
- m_PDesc.SampleRate = m_PDesc.EditRate;
- }
+ h__CodestreamParser()
+ : m_PDesc(&DefaultSMPTEDict()), m_JxsSubdesc(&DefaultSMPTEDict()) {}
~h__CodestreamParser() {}
@@ -85,7 +80,7 @@ public:
if (ASDCP_SUCCESS(result))
{
byte_t start_of_data = 0; // out param
- result = ParseMetadataIntoDesc(FB, m_PDesc, &start_of_data);
+ result = ParseMetadataIntoDesc(FB, m_PDesc, m_JxsSubdesc, &start_of_data);
if (ASDCP_SUCCESS(result))
FB.PlaintextOffset(start_of_data);
@@ -96,7 +91,8 @@ public:
};
ASDCP::Result_t
-ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDesc, byte_t* start_of_data)
+ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor, byte_t* start_of_data)
{
Result_t result = RESULT_OK;
Marker NextMarker;
@@ -108,6 +104,8 @@ ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDes
bool pih = false;
bool havesoc = false;
+ ImageComponent_t image_components[MaxComponents];
+
while (p < end_p && ASDCP_SUCCESS(result))
{
result = GetNextMarker(&p, NextMarker);
@@ -158,23 +156,23 @@ ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDes
// size of the bitstream: ignore, just store away.
size = PIH_.LcodSize();
// Profile and level
- PDesc.Ppih = PIH_.Ppih();
- PDesc.Plev = PIH_.Plev();
+ jxs_subdescriptor.JPEGXSPpih = PIH_.Ppih();
+ jxs_subdescriptor.JPEGXSPlev = PIH_.Plev();
// Width and Height
- PDesc.AspectRatio = Rational(PIH_.Wf(), PIH_.Hf());
- PDesc.StoredWidth = PIH_.Wf();
- PDesc.StoredHeight = PIH_.Hf();
- PDesc.Wf = PIH_.Wf();
- PDesc.Hf = PIH_.Hf();
- PDesc.Cw = PIH_.Cw();
- PDesc.Hsl = PIH_.Hsl();
+ picture_descriptor.AspectRatio = Rational(PIH_.Wf(), PIH_.Hf());
+ picture_descriptor.StoredWidth = PIH_.Wf();
+ picture_descriptor.StoredHeight = PIH_.Hf();
+ jxs_subdescriptor.JPEGXSWf = PIH_.Wf();
+ jxs_subdescriptor.JPEGXSHf = PIH_.Hf();
+ jxs_subdescriptor.JPEGXSCw = PIH_.Cw();
+ jxs_subdescriptor.JPEGXSHsl = PIH_.Hsl();
if (PIH_.Hsl() < 1 || PIH_.Hsl() > 0xffff) // This includes the EOF check
DefaultLogSink().Error("JXS::ParseMetadataIntoDesc: unsupported slice height specified, must be > 0 and < 65536");
// Number of compoennts.
- PDesc.Nc = PIH_.Nc();
- if (PDesc.Nc != 3)
+ jxs_subdescriptor.JPEGXSNc = PIH_.Nc();
+ if (jxs_subdescriptor.JPEGXSNc != 3)
{
- DefaultLogSink().Error("Unexpected number of components: %u\n", PDesc.Nc);
+ DefaultLogSink().Error("Unexpected number of components: %u\n", jxs_subdescriptor.JPEGXSNc);
return RESULT_RAW_FORMAT;
}
// A lot of settings that must be fixed right now.
@@ -196,10 +194,10 @@ ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDes
Accessor::CDT CDT_(NextMarker);
int i, count = NextMarker.m_DataSize >> 1;
- for (i = 0; i < count && i < PDesc.Nc; i++) {
- PDesc.ImageComponents[i].Bc = CDT_.Bc(i);
- PDesc.ImageComponents[i].Sx = CDT_.Sx(i);
- PDesc.ImageComponents[i].Sy = CDT_.Sy(i);
+ for (i = 0; i < count && i < jxs_subdescriptor.JPEGXSNc; i++) {
+ image_components[i].Bc = CDT_.Bc(i);
+ image_components[i].Sx = CDT_.Sx(i);
+ image_components[i].Sy = CDT_.Sy(i);
}
}
else {
@@ -213,10 +211,28 @@ ASDCP::JXS::ParseMetadataIntoDesc(const FrameBuffer& FB, PictureDescriptor& PDes
p = end_p;
break;
+ }
}
-}
+
+ const ui32_t cdt_buffer_len = 8 * 2; // at most 8 components.
+ byte_t tmp_buffer[cdt_buffer_len];
+ int comps = (jxs_subdescriptor.JPEGXSNc > 8)?8:jxs_subdescriptor.JPEGXSNc;
+ jxs_subdescriptor.JPEGXSComponentTable.Length(4 + (comps << 1));
+
+ // thor: unclear whether the marker size is part of this data.
+ tmp_buffer[0] = 0xff;
+ tmp_buffer[1] = 0x13; // the marker
+ tmp_buffer[2] = 0x00;
+ tmp_buffer[3] = comps * 2 + 2; // The size.
+ for(int j = 0;j < comps;j++) {
+ tmp_buffer[4 + (j << 1)] = image_components[j].Bc;
+ tmp_buffer[5 + (j << 1)] = (image_components[j].Sx << 4) | (image_components[j].Sy);
+ }
+
+ memcpy(jxs_subdescriptor.JPEGXSComponentTable.Data(), tmp_buffer, 4 + (comps << 1));
return result;
}
+
//------------------------------------------------------------------------------------------
ASDCP::JXS::CodestreamParser::CodestreamParser()
@@ -238,12 +254,15 @@ ASDCP::JXS::CodestreamParser::OpenReadFrame(const std::string& filename, FrameBu
//
ASDCP::Result_t
-ASDCP::JXS::CodestreamParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+ASDCP::JXS::CodestreamParser::FillPictureDescriptor(
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor) const
{
if (m_Parser.empty())
return RESULT_INIT;
- PDesc = m_Parser->m_PDesc;
+ picture_descriptor = m_Parser->m_PDesc;
+ jxs_subdescriptor = m_Parser->m_JxsSubdesc;
return RESULT_OK;
}
diff --git a/src/JXS_Sequence_Parser.cpp b/src/JXS_Sequence_Parser.cpp
index 38b8de4..331f0e3 100644
--- a/src/JXS_Sequence_Parser.cpp
+++ b/src/JXS_Sequence_Parser.cpp
@@ -31,16 +31,7 @@ THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\brief AS-DCP library, JPEG XS sequence codestream essence reader implementation
*/
-#include <AS_DCP.h>
-#include <AS_DCP_JXS.h>
-#include <KM_fileio.h>
-#include <KM_log.h>
-#include <list>
-#include <string>
-#include <algorithm>
-#include <string.h>
-#include <assert.h>
-
+#include <JXS.h>
using namespace ASDCP;
//------------------------------------------------------------------------------------------
@@ -107,13 +98,10 @@ class ASDCP::JXS::SequenceParser::h__SequenceParser
ASDCP_NO_COPY_CONSTRUCT(h__SequenceParser);
public:
- PictureDescriptor m_PDesc;
+ ASDCP::MXF::GenericPictureEssenceDescriptor m_PDesc;
+ ASDCP::MXF::JPEGXSPictureSubDescriptor m_JxsSubdesc;
- h__SequenceParser() : m_FramesRead(0)
- {
- memset(&m_PDesc, 0, sizeof(m_PDesc));
- m_PDesc.EditRate = Rational(24, 1);
- }
+ h__SequenceParser() : m_FramesRead(0), m_PDesc(&DefaultSMPTEDict()), m_JxsSubdesc(&DefaultSMPTEDict()) {}
~h__SequenceParser()
{
@@ -157,7 +145,7 @@ ASDCP::JXS::SequenceParser::h__SequenceParser::OpenRead()
result = Parser.OpenReadFrame((*m_CurrentFile).c_str(), TmpBuffer);
if (ASDCP_SUCCESS(result))
- result = Parser.FillPictureDescriptor(m_PDesc);
+ result = Parser.FillPictureDescriptor(m_PDesc, m_JxsSubdesc);
// how big is it?
if (ASDCP_SUCCESS(result))
@@ -268,12 +256,15 @@ ASDCP::JXS::SequenceParser::ReadFrame(FrameBuffer& FB) const
//
ASDCP::Result_t
-ASDCP::JXS::SequenceParser::FillPictureDescriptor(PictureDescriptor& PDesc) const
+ASDCP::JXS::SequenceParser::FillPictureDescriptor(
+ ASDCP::MXF::GenericPictureEssenceDescriptor& picture_descriptor,
+ ASDCP::MXF::JPEGXSPictureSubDescriptor& jxs_subdescriptor) const
{
if (m_Parser.empty())
return RESULT_INIT;
- PDesc = m_Parser->m_PDesc;
+ picture_descriptor = m_Parser->m_PDesc;
+ jxs_subdescriptor = m_Parser->m_JxsSubdesc;
return RESULT_OK;
}
diff --git a/src/MDD.cpp b/src/MDD.cpp
index 4b3b928..c513f3b 100644
--- a/src/MDD.cpp
+++ b/src/MDD.cpp
@@ -1069,7 +1069,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{0, 0}, false, "IMFAudioSoundfield_LtRt" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 344
0x03, 0x02, 0x02, 0x20, 0x0a, 0x00, 0x00, 0x00 },
- {0, 0}, false, "IMFAudioSoundfield_51Ex" },
+ {0, 0}, false, "IMFAudioSoundfield_51EX" },
{ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d, // 345
0x03, 0x02, 0x02, 0x20, 0x0b, 0x00, 0x00, 0x00 },
{0, 0}, false, "IMFAudioSoundfield_HI" },
@@ -1702,7 +1702,7 @@ static const ASDCP::MDDEntry s_MDD_Table[] = {
{ { 0x06, 0x0e, 0x2b, 0x34, 0x04, 0x01, 0x01, 0x0d,
0x04, 0x01, 0x02, 0x02, 0x03, 0x08, 0x09, 0x00 },
{0}, false, "JPEGXSHigh4444_12Profile" }, // 549
- { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x7f, 0x01, 0x01,
+ { { 0x06, 0x0e, 0x2b, 0x34, 0x02, 0x53, 0x01, 0x01,
0x0d, 0x01, 0x01, 0x01, 0x01, 0x01, 0x81, 0x02 },
{0}, false, "JPEGXSSubDescriptor" }, // 550
{ { 0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e,
diff --git a/src/MDD.h b/src/MDD.h
index 730d74b..2250f0c 100755
--- a/src/MDD.h
+++ b/src/MDD.h
@@ -379,7 +379,7 @@ namespace ASDCP {
MDD_IMFAudioSoundfield_60, // 341
MDD_IMFAudioSoundfield_70, // 342
MDD_IMFAudioSoundfield_LtRt, // 343
- MDD_IMFAudioSoundfield_51Ex, // 344
+ MDD_IMFAudioSoundfield_51EX, // 344
MDD_IMFAudioSoundfield_HI, // 345
MDD_IMFAudioSoundfield_VIN, // 346
MDD_IMFAudioGroup_MPg, // 347
diff --git a/src/MXF.cpp b/src/MXF.cpp
index 641fdcb..c961727 100755
--- a/src/MXF.cpp
+++ b/src/MXF.cpp
@@ -1927,7 +1927,7 @@ ASDCP::MXF::AS02_MCAConfigParser::AS02_MCAConfigParser(const Dictionary* d) : AS
m_LabelMap.insert(pair("60", label_traits("6.0", true, m_Dict->ul(MDD_IMFAudioSoundfield_60))));
m_LabelMap.insert(pair("70", label_traits("7.0DS", true, m_Dict->ul(MDD_IMFAudioSoundfield_70))));
m_LabelMap.insert(pair("LtRt", label_traits("Lt-Rt",true, m_Dict->ul(MDD_IMFAudioSoundfield_LtRt))));
- m_LabelMap.insert(pair("51Ex", label_traits("5.1EX",true, m_Dict->ul(MDD_IMFAudioSoundfield_51Ex))));
+ m_LabelMap.insert(pair("51EX", label_traits("5.1EX",true, m_Dict->ul(MDD_IMFAudioSoundfield_51EX))));
m_LabelMap.insert(pair("HA", label_traits("Hearing Accessibility", true, m_Dict->ul(MDD_IMFAudioSoundfield_HI))));
m_LabelMap.insert(pair("VA", label_traits("Visual Accessibility", true, m_Dict->ul(MDD_IMFAudioSoundfield_VIN))));
diff --git a/src/MXFTypes.h b/src/MXFTypes.h
index 0f38e9d..50cc286 100755
--- a/src/MXFTypes.h
+++ b/src/MXFTypes.h
@@ -624,8 +624,12 @@ namespace ASDCP
size_t const RGBAValueLength = 16;
+ byte_t const RGBAValue_RGB_16[RGBAValueLength] = { 'R', 16, 'G', 16, 'B', 16, 0, 0 };
+ byte_t const RGBAValue_RGB_12[RGBAValueLength] = { 'R', 12, 'G', 12, 'B', 12, 0, 0 };
byte_t const RGBAValue_RGB_10[RGBAValueLength] = { 'R', 10, 'G', 10, 'B', 10, 0, 0 };
byte_t const RGBAValue_RGB_8[RGBAValueLength] = { 'R', 8, 'G', 8, 'B', 8, 0, 0 };
+ byte_t const RGBAValue_YUV_16[RGBAValueLength] = { 'Y', 16, 'U', 16, 'V', 16, 0, 0 };
+ byte_t const RGBAValue_YUV_12[RGBAValueLength] = { 'Y', 12, 'U', 12, 'V', 12, 0, 0 };
byte_t const RGBAValue_YUV_10[RGBAValueLength] = { 'Y', 10, 'U', 10, 'V', 10, 0, 0 };
byte_t const RGBAValue_YUV_8[RGBAValueLength] = { 'Y', 8, 'U', 8, 'V', 8, 0, 0 };
byte_t const RGBAValue_DCDM[RGBAValueLength] = { 0xd8, 10, 0xd9, 10, 0xda, 10, 0, 0 };
diff --git a/src/Makefile.am b/src/Makefile.am
index 179bf05..5a7f9ed 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -152,6 +152,10 @@ libasdcp_la_LIBADD = libkumu.la
libasdcp_la_CPPFLAGS = -DASDCP_PLATFORM=\"@host@\"
if USE_AS_02
+if ! USE_ASDCP_JXS
+libasdcp_la_SOURCES += JXS_Codestream_Parser.cpp JXS_Sequence_Parser.cpp JXS.cpp
+endif
+
# sources for as-02 library
libas02_la_SOURCES = \
AS_02.h \
@@ -212,6 +216,7 @@ bin_PROGRAMS = \
if USE_AS_02
bin_PROGRAMS += \
as-02-wrap \
+ as-02-wrap-jxs \
as-02-unwrap \
as-02-info
endif
@@ -269,6 +274,9 @@ if USE_AS_02
as_02_wrap_SOURCES = as-02-wrap.cpp
as_02_wrap_LDADD = libas02.la libasdcp.la libkumu.la
+as_02_wrap_jxs_SOURCES = as-02-wrap-jxs.cpp
+as_02_wrap_jxs_LDADD = libas02.la libasdcp.la libkumu.la
+
as_02_unwrap_SOURCES = as-02-unwrap.cpp
as_02_unwrap_LDADD = libas02.la libasdcp.la libkumu.la
diff --git a/src/as-02-wrap-jxs.cpp b/src/as-02-wrap-jxs.cpp
new file mode 100644
index 0000000..fa57460
--- /dev/null
+++ b/src/as-02-wrap-jxs.cpp
@@ -0,0 +1,1007 @@
+/*
+Copyright (c) 2011-2020, Robert Scheler, Heiko Sparenberg Fraunhofer IIS,
+John Hurst, Wolfgang Ruppel, Thomas Richter
+
+All rights reserved.
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+ notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+ notice, this list of conditions and the following disclaimer in the
+ documentation and/or other materials provided with the distribution.
+3. The name of the author may not be used to endorse or promote products
+ derived from this software without specific prior written permission.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+*/
+/*! \file as-02-wrap-jxs.cpp
+ \version $Id$
+ \brief AS-02 file wrapping utility
+
+ This program wraps JPEG XS picture essence in an AS-02 MXF file.
+
+ For more information about AS-02, please refer to the header file AS_02.h
+ For more information about asdcplib, please refer to the header file AS_DCP.h
+*/
+
+#include <KM_prng.h>
+#include <Metadata.h>
+#include "JXS.h"
+#include "AS_02_JXS.h"
+
+using namespace ASDCP;
+
+const ui32_t FRAME_BUFFER_SIZE = 4 * Kumu::Megabyte;
+const ASDCP::Dictionary *g_dict = 0;
+
+const char*
+RationalToString(const ASDCP::Rational& r, char* buf, const ui32_t& len)
+{
+ snprintf(buf, len, "%d/%d", r.Numerator, r.Denominator);
+ return buf;
+}
+
+
+//------------------------------------------------------------------------------------------
+//
+// command line option parser class
+
+static const char* PROGRAM_NAME = "as-02-wrap"; // program name for messages
+
+// local program identification info written to file headers
+class MyInfo : public WriterInfo
+{
+public:
+ MyInfo()
+ {
+ static byte_t default_ProductUUID_Data[UUIDlen] =
+ { 0x40, 0xf5, 0x4c, 0x1d, 0x46, 0xf0, 0x41, 0xd3,
+ 0x8b, 0x68, 0x84, 0xb6, 0x29, 0xf8, 0xad, 0x74 };
+
+
+
+ memcpy(ProductUUID, default_ProductUUID_Data, UUIDlen);
+ CompanyName = "WidgetCo";
+ ProductName = "as-02-wrap-jxs";
+ ProductVersion = ASDCP::Version();
+ }
+} s_MyInfo;
+
+
+
+// Increment the iterator, test for an additional non-option command line argument.
+// Causes the caller to return if there are no remaining arguments or if the next
+// argument begins with '-'.
+#define TEST_EXTRA_ARG(i,c) \
+ if ( ++i >= argc || argv[(i)][0] == '-' ) { \
+ fprintf(stderr, "Argument not found for option -%c.\n", (c)); \
+ return; \
+ }
+
+#define TEST_EXTRA_ARG_STRING(i,s) \
+ if ( ++i >= argc || argv[(i)][0] == '-' ) { \
+ fprintf(stderr, "Argument not found for option -%s.\n", (s)); \
+ return; \
+ }
+
+
+//
+static void
+create_random_uuid(byte_t* uuidbuf)
+{
+ Kumu::UUID tmp_id;
+ GenRandomValue(tmp_id);
+ memcpy(uuidbuf, tmp_id.Value(), tmp_id.Size());
+}
+
+//
+void
+banner(FILE* stream = stdout)
+{
+ fprintf(stream, "\n\
+%s (asdcplib %s)\n\n\
+Copyright (c) 2011-2018, Robert Scheler, Heiko Sparenberg Fraunhofer IIS, John Hurst\n\n\
+asdcplib may be copied only under the terms of the license found at\n\
+the top of every file in the asdcplib distribution kit.\n\n\
+Specify the -h (help) option for further information about %s\n\n",
+ PROGRAM_NAME, ASDCP::Version(), PROGRAM_NAME);
+}
+
+//
+void
+usage(FILE* stream = stdout)
+{
+ fprintf(stream, "\
+USAGE: %s [-h|-help] [-V]\n\
+\n\
+ %s [options] <input-file>+ <output-file>\n\n",
+ PROGRAM_NAME, PROGRAM_NAME);
+
+ fprintf(stream, "\
+Options:\n\
+ -h | -help - Show help\n\
+ -V - Show version information\n\
+ -a <uuid> - Specify the Asset ID of the file\n\
+ -A <w>/<h> - Set aspect ratio for image (default 4/3)\n\
+ -b <buffer-size> - Specify size in bytes of picture frame buffer\n\
+ Defaults to 4,194,304 (4MB)\n\
+ -c <num> - Select the IMF color system to be signaled:\n\
+ Application 2 (2067-20): 1, 2, or 3\n\
+ Application 2e (2067-21): 4, 5, or 7\n\
+ All color system values assume YCbCr; also use -R for RGB\n\
+ -d <duration> - Number of frames to process, default all\n\
+ -D <depth> - Component depth for YCbCr images (default: 10)\n\
+ -e - Encrypt JP2K headers (default)\n\
+ -E - Do not encrypt JP2K headers\n\
+ -F (0|1) - Set field dominance for interlaced image (default: 0)\n\
+ -i - Indicates input essence is interlaced fields (forces -Y)\n\
+ -j <key-id-str> - Write key ID instead of creating a random value\n\
+ -k <key-string> - Use key for ciphertext operations\n\
+ -l <first>,<second>\n\
+ - Integer values that set the VideoLineMap\n\
+ -M - Do not create HMAC values when writing\n\
+ -n <UL> - Set the TransferCharacteristic UL\n\
+ -o <min>,<max> - Mastering Display luminance, cd*m*m, e.g., \".05,100\"\n\
+ -O <rx>,<ry>,<gx>,<gy>,<bx>,<by>,<wx>,<wy>\n\
+ - Mastering Display Color Primaries and white point\n\
+ e.g., \".64,.33,.3,.6,.15,.06,.3457,.3585\"\n\
+ -p <ul> - Set broadcast profile\n\
+ -q <UL> - Set the CodingEquations UL\n\
+ -r <n>/<d> - Edit Rate of the output file. 24/1 is the default\n\
+ -R - Indicates RGB image essence (default except with -c)\n\
+ -s <seconds> - Duration of a frame-wrapped partition (default 60)\n\
+ -t <min> - Set RGB component minimum code value (default: 0)\n\
+ -T <max> - Set RGB component maximum code value (default: 1023)\n\
+ -u - Print UL catalog to stdout\n\
+ -v - Verbose, prints informative messages to stderr\n\
+ -W - Read input file only, do not write source file\n\
+ -x <int> - Horizontal subsampling degree (default: 2)\n\
+ -X <int> - Vertical subsampling degree (default: 2)\n\
+ -y <white-ref>[,<black-ref>[,<color-range>]]\n\
+ - Same as -Y but White Ref, Black Ref and Color Range are\n\
+ set from the given argument\n\
+ -Y - Indicates YCbCr image essence (default with -c), uses\n\
+ default values for White Ref, Black Ref and Color Range,\n\
+ 940,64,897, indicating 10 bit standard Video Range\n\
+ -z - Fail if j2c inputs have unequal parameters (default)\n\
+ -Z - Ignore unequal parameters in j2c inputs\n\
+\n\
+ NOTES: o There is no option grouping, all options must be distinct arguments.\n\
+ o All option arguments must be separated from the option by whitespace.\n\n");
+}
+
+const float chromaticity_scale = 50000.0;
+//
+ui32_t
+set_primary_from_token(const std::string& token, ui16_t& primary)
+{
+ float raw_value = strtod(token.c_str(),0);
+
+ if ( raw_value == 0.0 || raw_value > 1.0 )
+ {
+ fprintf(stderr, "Invalid coordinate value \"%s\".\n", token.c_str());
+ return false;
+ }
+
+ primary = floor(0.5 + ( raw_value * chromaticity_scale ));
+ return true;
+}
+
+const float luminance_scale = 10000.0;
+//
+ui32_t
+set_luminance_from_token(const std::string& token, ui32_t& luminance)
+{
+ float raw_value = strtod(token.c_str(),0);
+
+ if ( raw_value == 0.0 || raw_value > 400000.0 )
+ {
+ fprintf(stderr, "Invalid luminance value \"%s\".\n", token.c_str());
+ return false;
+ }
+
+ luminance = floor(0.5 + ( raw_value * luminance_scale ));
+ return true;
+}
+
+#define SET_LUMINANCE(p,t) \
+ if ( ! set_luminance_from_token(t, p) ) { \
+ return false; \
+ }
+
+//
+class CommandOptions
+{
+ CommandOptions();
+
+public:
+ bool error_flag; // true if the given options are in error or not complete
+ bool key_flag; // true if an encryption key was given
+ bool asset_id_flag; // true if an asset ID was given
+ bool encrypt_header_flag; // true if j2c headers are to be encrypted
+ bool write_hmac; // true if HMAC values are to be generated and written
+ bool verbose_flag; // true if the verbose option was selected
+ ui32_t fb_dump_size; // number of bytes of frame buffer to dump
+ bool no_write_flag; // true if no output files are to be written
+ bool version_flag; // true if the version display option was selected
+ bool help_flag; // true if the help display option was selected
+ ui32_t duration; // number of frames to be processed
+ bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
+ bool use_cdci_descriptor; //
+ Rational edit_rate; // edit rate of JP2K sequence
+ ui32_t fb_size; // size of picture frame buffer
+ byte_t key_value[KeyLen]; // value of given encryption key (when key_flag is true)
+ bool key_id_flag; // true if a key ID was given
+ byte_t key_id_value[UUIDlen];// value of given key ID (when key_id_flag is true)
+ byte_t asset_id_value[UUIDlen];// value of asset ID (when asset_id_flag is true)
+ bool show_ul_values_flag; // if true, dump the UL table before going tp work.
+ Kumu::PathList_t filenames; // list of filenames to be processed
+
+ UL picture_coding, transfer_characteristic, color_primaries, coding_equations;
+
+ ui32_t rgba_MaxRef;
+ ui32_t rgba_MinRef;
+
+ ui32_t horizontal_subsampling;
+ ui32_t vertical_subsampling;
+ ui32_t component_depth;
+ ui8_t frame_layout;
+ ASDCP::Rational aspect_ratio;
+ bool aspect_ratio_flag;
+ ui8_t field_dominance;
+ ui32_t mxf_header_size;
+ ui32_t cdci_BlackRefLevel;
+ ui32_t cdci_WhiteRefLevel;
+ ui32_t cdci_ColorRange;
+
+ ui32_t md_min_luminance, md_max_luminance;
+ ASDCP::MXF::ThreeColorPrimaries md_primaries;
+ ASDCP::MXF::ColorPrimary md_white_point;
+
+ //new attributes for AS-02 support
+ AS_02::IndexStrategy_t index_strategy; //Shim parameter index_strategy_frame/clip
+ ui32_t partition_space; //Shim parameter partition_spacing
+
+ //
+ MXF::LineMapPair line_map;
+ bool line_map_flag;
+ std::string out_file, profile_name; //
+ std::string mca_audio_element_kind, mca_audio_content_kind;
+
+ //
+ bool set_video_line_map(const std::string& arg)
+ {
+ const char* sep_str = strrchr(arg.c_str(), ',');
+
+ if ( sep_str == 0 )
+ {
+ fprintf(stderr, "Expecting <first>,<second>\n");
+ return false;
+ }
+
+ line_map.First = Kumu::xabs(strtol(arg.c_str(), 0, 10));
+ line_map.Second = Kumu::xabs(strtol(sep_str+1, 0, 10));
+ return true;
+ }
+
+ //
+ bool set_video_ref(const std::string& arg)
+ {
+ std::list<std::string> ref_tokens = Kumu::km_token_split(arg, ",");
+
+ switch ( ref_tokens.size() )
+ {
+ case 3:
+ cdci_ColorRange = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
+ ref_tokens.pop_back();
+ case 2:
+ cdci_BlackRefLevel = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
+ ref_tokens.pop_back();
+ case 1:
+ cdci_WhiteRefLevel = Kumu::xabs(strtol(ref_tokens.back().c_str(), 0, 10));
+ break;
+
+ default:
+ fprintf(stderr, "Expecting <white-ref>[,<black-ref>[,<color-range>]]\n");
+ return false;
+ }
+
+ if ( cdci_WhiteRefLevel > 65535 || cdci_BlackRefLevel > 65535 || cdci_ColorRange > 65535 )
+ {
+ fprintf(stderr, "Unexpected CDCI video referece levels.\n");
+ return false;
+ }
+
+ return true;
+ }
+
+ //
+ bool set_display_primaries(const std::string& arg)
+ {
+ std::list<std::string> coordinate_tokens = Kumu::km_token_split(arg, ",");
+ if ( coordinate_tokens.size() != 8 )
+ {
+ fprintf(stderr, "Expecting four coordinate pairs.\n");
+ return false;
+ }
+
+ std::list<std::string>::const_iterator i = coordinate_tokens.begin();
+ if ( ! set_primary_from_token(*(i++), md_primaries.First.X) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_primaries.First.Y) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_primaries.Second.X) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_primaries.Second.Y) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_primaries.Third.X) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_primaries.Third.Y) ) return false;
+ if ( ! set_primary_from_token(*(i++), md_white_point.X) ) return false;
+ if ( ! set_primary_from_token(*i, md_white_point.Y) ) return false;
+
+ return true;
+ }
+
+ //
+ bool set_display_luminance(const std::string& arg)
+ {
+ std::list<std::string> luminance_tokens = Kumu::km_token_split(arg, ",");
+ if ( luminance_tokens.size() != 2 )
+ {
+ fprintf(stderr, "Expecting a luminance pair.\n");
+ return false;
+ }
+
+ if ( ! set_luminance_from_token(luminance_tokens.front(), md_min_luminance) ) return false;
+ if ( ! set_luminance_from_token(luminance_tokens.back(), md_max_luminance) ) return false;
+
+ return true;
+ }
+
+ //
+ bool set_color_system_from_arg(const char* arg)
+ {
+ assert(arg);
+
+ switch ( *arg )
+ {
+ // Application 2 (ST 2067-20)
+ case '1':
+ coding_equations = g_dict->ul(MDD_CodingEquations_601);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_ITU709);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU470_PAL);
+ use_cdci_descriptor = true;
+ break;
+
+ case '2':
+ coding_equations = g_dict->ul(MDD_CodingEquations_601);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_ITU709);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_SMPTE170M);
+ use_cdci_descriptor = true;
+ break;
+
+ case '3':
+ coding_equations = g_dict->ul(MDD_CodingEquations_709);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_ITU709);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU709);
+ use_cdci_descriptor = true;
+ break;
+
+ // Application 2e (ST 2067-21)
+ case '4':
+ coding_equations = g_dict->ul(MDD_CodingEquations_709);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_IEC6196624_xvYCC);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU709);
+ use_cdci_descriptor = true;
+ break;
+
+ case '5':
+ coding_equations = g_dict->ul(MDD_CodingEquations_709);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_ITU2020);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU2020);
+ use_cdci_descriptor = true;
+ break;
+
+ case '7':
+ coding_equations = g_dict->ul(MDD_CodingEquations_Rec2020);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_SMPTEST2084);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU2020);
+ use_cdci_descriptor = true;
+ break;
+
+ default:
+ fprintf(stderr, "Unrecognized color system number, expecting one of 1-5 or 7.\n");
+ return false;
+ }
+
+ return true;
+ }
+
+
+ CommandOptions(int argc, const char** argv) :
+ error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
+ encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0),
+ no_write_flag(false), version_flag(false), help_flag(false),
+ duration(0xffffffff), j2c_pedantic(true), use_cdci_descriptor(false),
+ edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE),
+ show_ul_values_flag(false), index_strategy(AS_02::IS_FOLLOW), partition_space(60),
+ rgba_MaxRef(1023), rgba_MinRef(0),
+ horizontal_subsampling(2), vertical_subsampling(2), component_depth(10),
+ frame_layout(0), aspect_ratio(ASDCP::Rational(4,3)), aspect_ratio_flag(false), field_dominance(0),
+ mxf_header_size(16384), cdci_WhiteRefLevel(940), cdci_BlackRefLevel(64), cdci_ColorRange(897),
+ md_min_luminance(0), md_max_luminance(0), line_map(0,0), line_map_flag(false)
+ {
+ memset(key_value, 0, KeyLen);
+ memset(key_id_value, 0, UUIDlen);
+
+ coding_equations = g_dict->ul(MDD_CodingEquations_709);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU709);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_ITU709);
+ std::string mca_config_str;
+
+ for ( int i = 1; i < argc; i++ )
+ {
+
+ if ( (strcmp( argv[i], "-help") == 0) )
+ {
+ help_flag = true;
+ continue;
+ }
+
+ if ( argv[i][0] == '-'
+ && ( isalpha(argv[i][1]) || isdigit(argv[i][1]) )
+ && argv[i][2] == 0 )
+ {
+ switch ( argv[i][1] )
+ {
+ case 'A':
+ TEST_EXTRA_ARG(i, 'A');
+ if ( ! DecodeRational(argv[i], aspect_ratio) )
+ {
+ fprintf(stderr, "Error decoding aspect ratio value: %s\n", argv[i]);
+ return;
+ }
+ else
+ {
+ aspect_ratio_flag = true;
+ }
+ break;
+
+ case 'a':
+ asset_id_flag = true;
+ TEST_EXTRA_ARG(i, 'a');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], asset_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected asset ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'b':
+ TEST_EXTRA_ARG(i, 'b');
+ fb_size = Kumu::xabs(strtol(argv[i], 0, 10));
+
+ if ( verbose_flag )
+ fprintf(stderr, "Frame Buffer size: %u bytes.\n", fb_size);
+
+ break;
+
+ case 'c':
+ TEST_EXTRA_ARG(i, 'c');
+ if ( ! set_color_system_from_arg(argv[i]) )
+ {
+ return;
+ }
+ break;
+
+ case 'D':
+ TEST_EXTRA_ARG(i, 'D');
+ component_depth = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'd':
+ TEST_EXTRA_ARG(i, 'd');
+ duration = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'E': encrypt_header_flag = false; break;
+ case 'e': encrypt_header_flag = true; break;
+
+ case 'F':
+ TEST_EXTRA_ARG(i, 'F');
+ field_dominance = Kumu::xabs(strtol(argv[i], 0, 10));
+ if ( field_dominance > 1 )
+ {
+ fprintf(stderr, "Field dominance value must be \"0\" or \"1\"\n");
+ return;
+ }
+ break;
+
+ case 'h': help_flag = true; break;
+
+ case 'i':
+ frame_layout = 1;
+ use_cdci_descriptor = true;
+ break;
+
+ case 'j':
+ key_id_flag = true;
+ TEST_EXTRA_ARG(i, 'j');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_id_value, UUIDlen, &length);
+
+ if ( length != UUIDlen )
+ {
+ fprintf(stderr, "Unexpected key ID length: %u, expecting %u characters.\n", length, UUIDlen);
+ return;
+ }
+ }
+ break;
+
+ case 'k': key_flag = true;
+ TEST_EXTRA_ARG(i, 'k');
+ {
+ ui32_t length;
+ Kumu::hex2bin(argv[i], key_value, KeyLen, &length);
+
+ if ( length != KeyLen )
+ {
+ fprintf(stderr, "Unexpected key length: %u, expecting %u characters.\n", length, KeyLen);
+ return;
+ }
+ }
+ break;
+
+ case 'l':
+ TEST_EXTRA_ARG(i, 'y');
+ if ( ! set_video_line_map(argv[i]) )
+ {
+ return;
+ } else {
+ line_map_flag = true;
+ }
+ break;
+
+ case 'M': write_hmac = false; break;
+
+ case 'm':
+ TEST_EXTRA_ARG(i, 'm');
+ mca_config_str = argv[i];
+ break;
+
+ case 'n':
+ TEST_EXTRA_ARG(i, 'n');
+ if ( ! transfer_characteristic.DecodeHex(argv[i]) )
+ {
+ fprintf(stderr, "Error decoding TransferCharacteristic UL value: %s\n", argv[i]);
+ return;
+ }
+ break;
+
+ case 'O':
+ TEST_EXTRA_ARG(i, 'O');
+ if ( ! set_display_primaries(argv[i]) )
+ {
+ return;
+ }
+ break;
+
+ case 'o':
+ TEST_EXTRA_ARG(i, 'o');
+ if ( ! set_display_luminance(argv[i]) )
+ {
+ return;
+ }
+ break;
+
+ case 'P':
+ TEST_EXTRA_ARG(i, 'P');
+ profile_name = argv[i];
+ break;
+
+ case 'p':
+ TEST_EXTRA_ARG(i, 'p');
+ if ( ! picture_coding.DecodeHex(argv[i]) )
+ {
+ fprintf(stderr, "Error decoding PictureEssenceCoding UL value: %s\n", argv[i]);
+ return;
+ }
+ break;
+
+ case 'q':
+ TEST_EXTRA_ARG(i, 'q');
+ if ( ! coding_equations.DecodeHex(argv[i]) )
+ {
+ fprintf(stderr, "Error decoding CodingEquations UL value: %s\n", argv[i]);
+ return;
+ }
+ break;
+
+ case 'r':
+ TEST_EXTRA_ARG(i, 'r');
+ if ( ! DecodeRational(argv[i], edit_rate) )
+ {
+ fprintf(stderr, "Error decoding edit rate value: %s\n", argv[i]);
+ return;
+ }
+
+ break;
+
+ case 'R':
+ use_cdci_descriptor = false;
+ break;
+
+ case 's':
+ TEST_EXTRA_ARG(i, 's');
+ partition_space = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 't':
+ TEST_EXTRA_ARG(i, 't');
+ rgba_MinRef = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'T':
+ TEST_EXTRA_ARG(i, 'T');
+ rgba_MaxRef = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'u': show_ul_values_flag = true; break;
+
+ case 'V': version_flag = true; break;
+ case 'v': verbose_flag = true; break;
+ case 'W': no_write_flag = true; break;
+
+ case 'x':
+ TEST_EXTRA_ARG(i, 'x');
+ horizontal_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'X':
+ TEST_EXTRA_ARG(i, 'X');
+ vertical_subsampling = Kumu::xabs(strtol(argv[i], 0, 10));
+ break;
+
+ case 'Y':
+ use_cdci_descriptor = true;
+ // default 10 bit video range YUV, ref levels already set
+ break;
+
+ case 'y':
+ // Use values provided as argument, sharp tool, be careful
+ use_cdci_descriptor = true;
+ TEST_EXTRA_ARG(i, 'y');
+ if ( ! set_video_ref(argv[i]) )
+ {
+ return;
+ }
+ break;
+
+ case 'Z': j2c_pedantic = false; break;
+ case 'z': j2c_pedantic = true; break;
+
+ default:
+ fprintf(stderr, "Unrecognized option: %s\n", argv[i]);
+ return;
+ }
+ }
+ else
+ {
+ if ( argv[i][0] != '-' )
+ {
+ filenames.push_back(argv[i]);
+ }
+ else
+ {
+ fprintf(stderr, "Unrecognized argument: %s\n", argv[i]);
+ return;
+ }
+ }
+ }
+
+ if ( help_flag || version_flag || show_ul_values_flag )
+ {
+ return;
+ }
+
+ if ( filenames.size() < 2 )
+ {
+ fputs("Option requires at least two filename arguments: <input-file> <output-file>\n", stderr);
+ return;
+ }
+
+ out_file = filenames.back();
+ filenames.pop_back();
+
+ if ( ! picture_coding.HasValue() )
+ {
+ picture_coding = UL(g_dict->ul(MDD_JP2KEssenceCompression_BroadcastProfile_1));
+ }
+
+ error_flag = false;
+ }
+};
+
+
+
+
+//------------------------------------------------------------------------------------------
+// JPEG XS essence
+
+// Write one or more plaintext JPEG XS codestreams to a plaintext AS-02 file
+// Write one or more plaintext JPEG XS codestreams to a ciphertext AS-02 file
+//
+Result_t
+write_JXS_file(CommandOptions& Options)
+{
+ AESEncContext* Context = 0;
+ HMACContext* HMAC = 0;
+ AS_02::JXS::MXFWriter Writer;
+ ASDCP::JXS::FrameBuffer FrameBuffer(Options.fb_size);
+ ASDCP::JXS::SequenceParser Parser;
+ ASDCP::MXF::GenericPictureEssenceDescriptor *picture_descriptor = 0;
+ ASDCP::MXF::JPEGXSPictureSubDescriptor jxs_sub_descriptor(g_dict);
+
+ // set up essence parser
+ Result_t result = Parser.OpenRead(Options.filenames.front().c_str());
+
+ // set up MXF writer
+ if ( ASDCP_SUCCESS(result) )
+ {
+ // PDesc.EditRate = Options.edit_rate;
+
+ if ( Options.verbose_flag )
+ {
+ fprintf(stderr, "JPEG XS pictures\n");
+ fputs("PictureDescriptor:\n", stderr);
+ fprintf(stderr, "Frame Buffer size: %u\n", Options.fb_size);
+ }
+
+ if ( Options.use_cdci_descriptor )
+ {
+ ASDCP::MXF::CDCIEssenceDescriptor* tmp_dscr = new ASDCP::MXF::CDCIEssenceDescriptor(g_dict);
+ Parser.FillPictureDescriptor(*tmp_dscr, jxs_sub_descriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ tmp_dscr->CodingEquations = Options.coding_equations;
+ tmp_dscr->TransferCharacteristic = Options.transfer_characteristic;
+ tmp_dscr->ColorPrimaries = Options.color_primaries;
+ tmp_dscr->PictureEssenceCoding = Options.picture_coding;
+ tmp_dscr->HorizontalSubsampling = Options.horizontal_subsampling;
+ tmp_dscr->VerticalSubsampling = Options.vertical_subsampling;
+ tmp_dscr->ComponentDepth = Options.component_depth;
+ tmp_dscr->FrameLayout = Options.frame_layout;
+ tmp_dscr->AspectRatio = Options.aspect_ratio;
+ tmp_dscr->FieldDominance = Options.field_dominance;
+ tmp_dscr->WhiteReflevel = Options.cdci_WhiteRefLevel;
+ tmp_dscr->BlackRefLevel = Options.cdci_BlackRefLevel;
+ tmp_dscr->ColorRange = Options.cdci_ColorRange;
+ if (Options.line_map_flag) tmp_dscr->VideoLineMap = Options.line_map;
+
+ if ( Options.md_min_luminance || Options.md_max_luminance )
+ {
+ tmp_dscr->MasteringDisplayMinimumLuminance = Options.md_min_luminance;
+ tmp_dscr->MasteringDisplayMaximumLuminance = Options.md_max_luminance;
+ }
+
+ if ( Options.md_primaries.HasValue() )
+ {
+ tmp_dscr->MasteringDisplayPrimaries = Options.md_primaries;
+ tmp_dscr->MasteringDisplayWhitePointChromaticity = Options.md_white_point;
+ }
+
+ picture_descriptor = static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr);
+ }
+ }
+ else
+ { // use RGB
+ ASDCP::MXF::RGBAEssenceDescriptor* tmp_dscr = new ASDCP::MXF::RGBAEssenceDescriptor(g_dict);
+ Parser.FillPictureDescriptor(*tmp_dscr, jxs_sub_descriptor);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ tmp_dscr->CodingEquations = Options.coding_equations;
+ tmp_dscr->TransferCharacteristic = Options.transfer_characteristic;
+ tmp_dscr->ColorPrimaries = Options.color_primaries;
+ tmp_dscr->ScanningDirection = 0;
+ tmp_dscr->PictureEssenceCoding = Options.picture_coding;
+ tmp_dscr->ComponentMaxRef = Options.rgba_MaxRef;
+ tmp_dscr->ComponentMinRef = Options.rgba_MinRef;
+ if (Options.line_map_flag) tmp_dscr->VideoLineMap = Options.line_map;
+
+ if ( Options.md_min_luminance || Options.md_max_luminance )
+ {
+ tmp_dscr->MasteringDisplayMinimumLuminance = Options.md_min_luminance;
+ tmp_dscr->MasteringDisplayMaximumLuminance = Options.md_max_luminance;
+ }
+
+ if ( Options.md_primaries.HasValue() )
+ {
+ tmp_dscr->MasteringDisplayPrimaries = Options.md_primaries;
+ tmp_dscr->MasteringDisplayWhitePointChromaticity = Options.md_white_point;
+ }
+
+ picture_descriptor = static_cast<ASDCP::MXF::GenericPictureEssenceDescriptor*>(tmp_dscr);
+ }
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) && Options.verbose_flag )
+ {
+ picture_descriptor->Dump();
+ jxs_sub_descriptor.Dump();
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ WriterInfo Info = s_MyInfo; // fill in your favorite identifiers here
+ Info.LabelSetType = LS_MXF_SMPTE;
+
+ if ( Options.asset_id_flag )
+ memcpy(Info.AssetUUID, Options.asset_id_value, UUIDlen);
+ else
+ Kumu::GenRandomUUID(Info.AssetUUID);
+
+#ifdef HAVE_OPENSSL
+ // configure encryption
+ if( Options.key_flag )
+ {
+ byte_t IV_buf[CBC_BLOCK_SIZE];
+ Kumu::FortunaRNG RNG;
+ Kumu::GenRandomUUID(Info.ContextID);
+ Info.EncryptedEssence = true;
+
+ if ( Options.key_id_flag )
+ {
+ memcpy(Info.CryptographicKeyID, Options.key_id_value, UUIDlen);
+ }
+ else
+ {
+ create_random_uuid(Info.CryptographicKeyID);
+ }
+
+ Context = new AESEncContext;
+ result = Context->InitKey(Options.key_value);
+
+ if ( ASDCP_SUCCESS(result) )
+ result = Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+
+ if ( ASDCP_SUCCESS(result) && Options.write_hmac )
+ {
+ Info.UsesHMAC = true;
+ HMAC = new HMACContext;
+ result = HMAC->InitKey(Options.key_value, Info.LabelSetType);
+ }
+ }
+#endif // HAVE_OPENSSL
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = Writer.OpenWrite(Options.out_file, Info, *picture_descriptor, jxs_sub_descriptor,
+ Options.edit_rate, Options.mxf_header_size, Options.index_strategy, Options.partition_space);
+ }
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ ui32_t duration = 0;
+ result = Parser.Reset();
+
+ while ( ASDCP_SUCCESS(result) && duration++ < Options.duration )
+ {
+ result = Parser.ReadFrame(FrameBuffer);
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ if ( Options.verbose_flag )
+ FrameBuffer.Dump(stderr, Options.fb_dump_size);
+
+ if ( Options.encrypt_header_flag )
+ FrameBuffer.PlaintextOffset(0);
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ {
+ result = Writer.WriteFrame(FrameBuffer, Context, HMAC);
+
+ // The Writer class will forward the last block of ciphertext
+ // to the encryption context for use as the IV for the next
+ // frame. If you want to use non-sequitur IV values, un-comment
+ // the following line of code.
+ // if ( ASDCP_SUCCESS(result) && Options.key_flag )
+ // Context->SetIVec(RNG.FillRandom(IV_buf, CBC_BLOCK_SIZE));
+ }
+ }
+
+ if ( result == RESULT_ENDOFFILE )
+ result = RESULT_OK;
+ }
+
+ if ( ASDCP_SUCCESS(result) && ! Options.no_write_flag )
+ result = Writer.Finalize();
+
+ return result;
+}
+
+
+//
+int
+main(int argc, const char** argv)
+{
+ Result_t result = RESULT_OK;
+ char str_buf[64];
+ g_dict = &ASDCP::DefaultSMPTEDict();
+ assert(g_dict);
+
+ CommandOptions Options(argc, argv);
+
+ if ( Options.version_flag )
+ banner();
+
+ if ( Options.help_flag )
+ usage();
+
+ if ( Options.show_ul_values_flag )
+ {
+ g_dict->Dump(stdout);
+ }
+
+ if ( Options.version_flag || Options.help_flag || Options.show_ul_values_flag )
+ return 0;
+
+ if ( Options.error_flag )
+ {
+ fprintf(stderr, "There was a problem. Type %s -h for help.\n", PROGRAM_NAME);
+ return 3;
+ }
+
+ EssenceType_t EssenceType;
+ result = ASDCP::RawEssenceType(Options.filenames.front().c_str(), EssenceType);
+
+ if ( ASDCP_SUCCESS(result) && EssenceType != ESS_JPEG_XS )
+ {
+ fprintf(stderr, "%s: Unknown file type, not AS-02-compatible essence.\n",
+ Options.filenames.front().c_str());
+ return 5;
+ }
+
+ if ( ASDCP_SUCCESS(result) )
+ {
+ result = write_JXS_file(Options);
+ }
+
+ if ( ASDCP_FAILURE(result) )
+ {
+ fputs("Program stopped on error.\n", stderr);
+
+ if ( result != RESULT_FAIL )
+ {
+ fputs(result, stderr);
+ fputc('\n', stderr);
+ }
+
+ return 1;
+ }
+
+ return 0;
+}
+
+
+//
+// end as-02-wrap.cpp
+//
diff --git a/src/as-02-wrap.cpp b/src/as-02-wrap.cpp
index 98126bf..8dba4ce 100755
--- a/src/as-02-wrap.cpp
+++ b/src/as-02-wrap.cpp
@@ -139,11 +139,11 @@ Options:\n\
Defaults to 4,194,304 (4MB)\n\
-c <num> - Select the IMF color system to be signaled:\n\
Application 2 (2067-20): 1, 2, or 3\n\
- Application 2e (2067-21): 4 or 5\n\
+ Application 2e (2067-21): 4, 5, or 7\n\
All color system values assume YCbCr; also use -R for RGB\n\
-C <ul> - Set ChannelAssignment UL value\n\
-d <duration> - Number of frames to process, default all\n\
- -D <depth> - Component depth for YCbCr images (default: 10)\n\
+ -D <depth> - Component depth for YCbCr or RGB images (default: 10)\n\
-e - Encrypt JP2K headers (default)\n\
-E - Do not encrypt JP2K headers\n\
-F (0|1) - Set field dominance for interlaced image (default: 0)\n\
@@ -155,6 +155,7 @@ Options:\n\
Stream. May be issued multiple times.\n\
-i - Indicates input essence is interlaced fields (forces -Y)\n\
-j <key-id-str> - Write key ID instead of creating a random value\n\
+ -J - Write J2CLayout\n\
-k <key-string> - Use key for ciphertext operations\n\
-l <first>,<second>\n\
- Integer values that set the VideoLineMap\n\
@@ -273,6 +274,7 @@ public:
bool help_flag; // true if the help display option was selected
ui32_t duration; // number of frames to be processed
bool j2c_pedantic; // passed to JP2K::SequenceParser::OpenRead
+ bool write_j2clayout; // true if a J2CLayout field should be written
bool use_cdci_descriptor; //
Rational edit_rate; // edit rate of JP2K sequence
ui32_t fb_size; // size of picture frame buffer
@@ -459,8 +461,15 @@ public:
use_cdci_descriptor = true;
break;
+ case '7':
+ coding_equations = g_dict->ul(MDD_CodingEquations_Rec2020);
+ transfer_characteristic = g_dict->ul(MDD_TransferCharacteristic_SMPTEST2084);
+ color_primaries = g_dict->ul(MDD_ColorPrimaries_ITU2020);
+ use_cdci_descriptor = true;
+ break;
+
default:
- fprintf(stderr, "Unrecognized color system number, expecting one of 1-5.\n");
+ fprintf(stderr, "Unrecognized color system number, expecting one of 1-5 or 7.\n");
return false;
}
@@ -505,7 +514,7 @@ public:
error_flag(true), key_flag(false), key_id_flag(false), asset_id_flag(false),
encrypt_header_flag(true), write_hmac(true), verbose_flag(false), fb_dump_size(0),
no_write_flag(false), version_flag(false), help_flag(false),
- duration(0xffffffff), j2c_pedantic(true), use_cdci_descriptor(false),
+ duration(0xffffffff), j2c_pedantic(true), write_j2clayout(false), use_cdci_descriptor(false),
edit_rate(24,1), fb_size(FRAME_BUFFER_SIZE),
show_ul_values_flag(false), index_strategy(AS_02::IS_FOLLOW), partition_space(60),
mca_config(g_dict), rgba_MaxRef(1023), rgba_MinRef(0),
@@ -727,6 +736,8 @@ public:
}
break;
+ case 'J': write_j2clayout = true; break;
+
case 'k': key_flag = true;
TEST_EXTRA_ARG(i, 'k');
{
@@ -988,6 +999,7 @@ write_JP2K_file(CommandOptions& Options)
JP2K::SequenceParser Parser;
ASDCP::MXF::FileDescriptor *essence_descriptor = 0;
ASDCP::MXF::InterchangeObject_list_t essence_sub_descriptors;
+ ASDCP::MXF::JPEG2000PictureSubDescriptor *jp2k_sub_descriptor = NULL;
// set up essence parser
Result_t result = Parser.OpenRead(Options.filenames.front().c_str(), Options.j2c_pedantic);
@@ -1046,6 +1058,31 @@ write_JP2K_file(CommandOptions& Options)
}
essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
+
+ if (Options.write_j2clayout)
+ {
+ jp2k_sub_descriptor = static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back());
+ if (Options.component_depth == 16)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_YUV_16);
+ }
+ else if (Options.component_depth == 12)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_YUV_12);
+ }
+ else if (Options.component_depth == 10)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_YUV_10);
+ }
+ else if (Options.component_depth == 8)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_YUV_8);
+ }
+ else
+ {
+ fprintf(stderr, "Warning: could not determine J2CLayout to write.\n");
+ }
+ }
}
}
else
@@ -1081,6 +1118,31 @@ write_JP2K_file(CommandOptions& Options)
}
essence_descriptor = static_cast<ASDCP::MXF::FileDescriptor*>(tmp_dscr);
+
+ if (Options.write_j2clayout)
+ {
+ jp2k_sub_descriptor = static_cast<ASDCP::MXF::JPEG2000PictureSubDescriptor*>(essence_sub_descriptors.back());
+ if (Options.component_depth == 16)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_RGB_16);
+ }
+ else if (Options.component_depth == 12)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_RGB_12);
+ }
+ else if (Options.component_depth == 10)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_RGB_10);
+ }
+ else if (Options.component_depth == 8)
+ {
+ jp2k_sub_descriptor->J2CLayout = ASDCP::MXF::RGBALayout(ASDCP::MXF::RGBAValue_RGB_8);
+ }
+ else
+ {
+ fprintf(stderr, "Warning: could not determine J2CLayout to write.\n");
+ }
+ }
}
}
}