Skip to content

Commit

Permalink
Adding parsing for 'J2KExtendedCapabilities' stored in the MXF header…
Browse files Browse the repository at this point in the history
…'s 'JPEG2000SubDescriptor'. (#382)

* Adding parsing for 'J2KExtendedCapabilities' stored in the MXF header's 'JPEG2000SubDescriptor'.

* Adding j2k_extended_capabilities to 'toString'

* Updating comment

* Simplifying code. Moving away from the 'B0' convention which seems to be used for InterchangeObject inheritors. Passed in byteProvider directly.

* Using smaller test file

* Renaming 'cCapi' to 'cCap'
  • Loading branch information
danielhdz13-netflix authored Sep 30, 2024
1 parent 18965f2 commit 0ebf06a
Show file tree
Hide file tree
Showing 11 changed files with 473 additions and 13 deletions.
13 changes: 13 additions & 0 deletions src/main/java/com/netflix/imflibrary/MXFPropertyPopulator.java
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@
import com.netflix.imflibrary.exceptions.MXFException;
import com.netflix.imflibrary.st0377.CompoundDataTypes;
import com.netflix.imflibrary.st0377.header.InterchangeObject;
import com.netflix.imflibrary.st0377.header.J2KExtendedCapabilities;
import com.netflix.imflibrary.st0377.header.JPEG2000PictureComponent;
import com.netflix.imflibrary.st0377.header.UL;
import com.netflix.imflibrary.utils.ByteProvider;
Expand Down Expand Up @@ -111,6 +112,10 @@ else if (field.getType() == CompoundDataTypes.Timestamp.class)
CompoundDataTypes.Timestamp timestamp = new CompoundDataTypes.Timestamp(byteProvider);
field.set(object, timestamp);
}
else if (field.getType() == J2KExtendedCapabilities.class) {
J2KExtendedCapabilities j2KExtendedCapabilities = new J2KExtendedCapabilities(byteProvider);
field.set(object, j2KExtendedCapabilities);
}
else if (field.getType() == CompoundDataTypes.MXFCollections.MXFCollection.class)
{
CompoundDataTypes.MXFCollections.Header cHeader = new CompoundDataTypes.MXFCollections.Header(byteProvider);
Expand All @@ -130,6 +135,14 @@ else if (field.getType() == CompoundDataTypes.MXFCollections.MXFCollection.class
}
field.set(object, new CompoundDataTypes.MXFCollections.MXFCollection<>(cHeader, cList, fieldName));
}
else if (parameterizedType.getActualTypeArguments()[0] == Short.class) {
List<Short> cList = new ArrayList<>();
for (long i=0; i <cHeader.getNumberOfElements(); i++)
{
cList.add(getShort(byteProvider.getBytes(2), KLVPacket.BYTE_ORDER));
}
field.set(object, new CompoundDataTypes.MXFCollections.MXFCollection<>(cHeader, cList, fieldName));
}
else if (parameterizedType.getActualTypeArguments()[0] == Integer.class)
{
List<Integer> cList = new ArrayList<>();
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
package com.netflix.imflibrary.st0377.header;

import com.netflix.imflibrary.MXFPropertyPopulator;
import com.netflix.imflibrary.annotations.MXFProperty;
import com.netflix.imflibrary.st0377.CompoundDataTypes;
import com.netflix.imflibrary.utils.ByteArrayDataProvider;
import com.netflix.imflibrary.utils.ByteProvider;

import javax.annotation.concurrent.Immutable;
import java.io.IOException;
import java.util.List;

/**
* Object model corresponding to J2KExtendedCapabilities as defined in ISO/IEC 15444-1:2019 Annex A.5.2
*/

@Immutable
public final class J2KExtendedCapabilities {

@MXFProperty(size=4) protected final Integer pCap = null;
@MXFProperty(size=0, depends=true) protected final CompoundDataTypes.MXFCollections.MXFCollection<Short> cCap = null;

/**
* Instantiates a new parsed J2KExtendedCapabilities object
*
* @param byteProvider the bytes corresponding to the 2 fields
* @throws IOException - any I/O related error will be exposed through an IOException
*/

public J2KExtendedCapabilities(ByteProvider byteProvider) throws IOException {
MXFPropertyPopulator.populateField(byteProvider, this, "pCap");
MXFPropertyPopulator.populateField(byteProvider, this, "cCap");
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,6 +74,7 @@ public static final class JPEG2000PictureSubDescriptorBO extends SubDescriptorBO
@MXFProperty(size=0, depends=true) private final CompoundDataTypes.MXFCollections.MXFCollection<JPEG2000PictureComponent.JPEG2000PictureComponentBO> picture_component_sizing = null;
@MXFProperty(size=0, depends=false) private final byte[] coding_style_default = null;
@MXFProperty(size=0, depends=false) private final byte[] quantisation_default = null;
@MXFProperty(size=0, depends=false) private final J2KExtendedCapabilities j2k_extended_capabilities = null;

/**
* Instantiates a new JPEG2000 picture sub descriptor ByteObject.
Expand Down Expand Up @@ -135,6 +136,7 @@ public String toString()
quantisationDefaultString = quantisationDefaultString.concat(String.format("%02x", b));
}
sb.append(String.format("quantisation_default = %s", quantisationDefaultString));
sb.append(String.format("j2k_extended_capabilities = %s", j2k_extended_capabilities));
return sb.toString();
}
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -483,6 +483,11 @@ private StructuralMetadata()
MXFUID mxfUL = new MXFUID(byteArray);
map.put(mxfUL, "quantisation_default");
}
{
byte[] byteArray = {0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x0e, 0x04, 0x01, 0x06, 0x03, 0x0f, 0x00, 0x00, 0x00};
MXFUID mxfUL = new MXFUID(byteArray);
map.put(mxfUL, "j2k_extended_capabilities");
}
{
byte[] byteArray = {0x06, 0x0e, 0x2b, 0x34, 0x01, 0x01, 0x01, 0x09, 0x04, 0x01, 0x02, 0x01, 0x01, 0x06, 0x01, 0x00};
MXFUID mxfUL = new MXFUID(byteArray);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,19 +23,7 @@
import com.netflix.imflibrary.RESTfulInterfaces.IMPValidator;
import com.netflix.imflibrary.RESTfulInterfaces.PayloadRecord;
import com.netflix.imflibrary.exceptions.MXFException;
import com.netflix.imflibrary.st0377.header.AudioChannelLabelSubDescriptor;
import com.netflix.imflibrary.st0377.header.ContentStorage;
import com.netflix.imflibrary.st0377.header.EssenceContainerData;
import com.netflix.imflibrary.st0377.header.GenericTrack;
import com.netflix.imflibrary.st0377.header.InterchangeObject;
import com.netflix.imflibrary.st0377.header.MaterialPackage;
import com.netflix.imflibrary.st0377.header.Preface;
import com.netflix.imflibrary.st0377.header.Sequence;
import com.netflix.imflibrary.st0377.header.SoundFieldGroupLabelSubDescriptor;
import com.netflix.imflibrary.st0377.header.SourceClip;
import com.netflix.imflibrary.st0377.header.SourcePackage;
import com.netflix.imflibrary.st0377.header.TimelineTrack;
import com.netflix.imflibrary.st0377.header.WaveAudioEssenceDescriptor;
import com.netflix.imflibrary.st0377.header.*;
import com.netflix.imflibrary.st2067_2.AudioContentKind;
import com.netflix.imflibrary.utils.ByteArrayDataProvider;
import com.netflix.imflibrary.utils.ByteProvider;
Expand All @@ -47,6 +35,7 @@

import java.io.File;
import java.io.IOException;
import java.lang.reflect.Field;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
Expand Down Expand Up @@ -229,6 +218,27 @@ public void videoHeaderPartitionTest2() throws IOException
Assert.assertTrue(headerPartition.getEssenceTypes().get(0) == HeaderPartition.EssenceTypeEnum.MainImageEssence);
}

@Test
public void videoHeaderPartitionTest3() throws IOException
{
File inputFile = TestHelper.findResourceByPath("TestIMP/HT/IMP/VIDEO_6ed567b7-c030-46d6-9c1c-0f09bab4b962.mxf");
IMFErrorLogger imfErrorLogger = new IMFErrorLoggerImpl();
HeaderPartition headerPartition = HeaderPartition.fromFile(inputFile, imfErrorLogger);
Assert.assertTrue(headerPartition.toString().length() > 0);
Assert.assertTrue(headerPartition.hasRGBAPictureEssenceDescriptor());
GenericPictureEssenceDescriptor pictureEssenceDescriptor = ((GenericPictureEssenceDescriptor)((SourcePackage) headerPartition.getSourcePackages().get(0)).getGenericDescriptor());
GenericPictureEssenceDescriptor.GenericPictureEssenceDescriptorBO descriptorBO = (GenericPictureEssenceDescriptor.GenericPictureEssenceDescriptorBO) TestHelper.getValue(pictureEssenceDescriptor, "rgbaPictureEssenceDescriptorBO");
InterchangeObject.InterchangeObjectBO jpeg2000SubDescriptor = headerPartition.getSubDescriptors(descriptorBO).get(0);
JPEG2000PictureSubDescriptor.JPEG2000PictureSubDescriptorBO jpeg2000PictureSubDescriptorBO = (JPEG2000PictureSubDescriptor.JPEG2000PictureSubDescriptorBO) jpeg2000SubDescriptor;
J2KExtendedCapabilities j2KExtendedCapabilities = (J2KExtendedCapabilities) TestHelper.getValue(jpeg2000PictureSubDescriptorBO, "j2k_extended_capabilities");
Integer pCap = (Integer) TestHelper.getValue(j2KExtendedCapabilities, "pCap");
List<Short> cCap = ((CompoundDataTypes.MXFCollections.MXFCollection<Short>) TestHelper.getValue(j2KExtendedCapabilities, "cCap")).getEntries();

Assert.assertEquals(pCap, 131072);
Assert.assertEquals(cCap.size(), 1);
Assert.assertTrue(cCap.get(0) == 38);
}

@Test
public void audioHeaderPartitionTest2() throws IOException
{
Expand Down
37 changes: 37 additions & 0 deletions src/test/java/testUtils/TestHelper.java
Original file line number Diff line number Diff line change
Expand Up @@ -16,10 +16,13 @@

package testUtils;

import com.netflix.imflibrary.exceptions.MXFException;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.lang.reflect.Field;
import java.net.URL;

import static org.testng.Assert.assertNotNull;
Expand Down Expand Up @@ -58,4 +61,38 @@ public static byte[] toByteArray(InputStream inputStream) throws IOException

return baos.toByteArray();
}

public static Object getValue(Object obj, String fieldName)
{
try
{
Field field = getField(obj.getClass(), fieldName);
field.setAccessible(true);
return field.get(obj);
}
catch (IllegalAccessException | NoSuchFieldException e)
{
throw new MXFException(String.format("Parsing failure due to reflection error, reading property {}", fieldName), e);
}
}

public static Field getField(Class<?> aClass, String fieldName) throws NoSuchFieldException
{
try
{
return aClass.getDeclaredField(fieldName);
}
catch (NoSuchFieldException e)
{
Class<?> superClass = aClass.getSuperclass();
if (superClass == null)
{
throw e;
}
else
{
return getField(superClass, fieldName);
}
}
}
}
56 changes: 56 additions & 0 deletions src/test/resources/TestIMP/HT/IMP/ASSETMAP.xml
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
<?xml version="1.0" encoding="UTF-8"?>
<AssetMap xmlns="http://www.smpte-ra.org/schemas/429-9/2007/AM">
<Id>urn:uuid:49e02e84-fee5-430a-8f0d-0063ff9f0e46</Id>
<AnnotationText>Untitled Project</AnnotationText>
<Creator>Blackmagic Design DaVinci Resolve 19.0.0b.0050</Creator>
<VolumeCount>1</VolumeCount>
<IssueDate>2024-09-30T13:25:04</IssueDate>
<Issuer>Blackmagic Design</Issuer>
<AssetList>
<Asset>
<Id>urn:uuid:6ed567b7-c030-46d6-9c1c-0f09bab4b962</Id>
<ChunkList>
<Chunk>
<Path>VIDEO_6ed567b7-c030-46d6-9c1c-0f09bab4b962.mxf</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>3651582</Length>
</Chunk>
</ChunkList>
</Asset>
<Asset>
<Id>urn:uuid:b285d8f3-0294-4207-8ea8-4f0b72314213</Id>
<ChunkList>
<Chunk>
<Path>AUDIO_b285d8f3-0294-4207-8ea8-4f0b72314213.mxf</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>651208</Length>
</Chunk>
</ChunkList>
</Asset>
<Asset>
<Id>urn:uuid:67be5fc8-87f1-4172-8d52-819ca14c7a20</Id>
<ChunkList>
<Chunk>
<Path>CPL_67be5fc8-87f1-4172-8d52-819ca14c7a20.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>13275</Length>
</Chunk>
</ChunkList>
</Asset>
<Asset>
<Id>urn:uuid:52f61ec0-1517-49b7-a8e2-941c0200c69a</Id>
<PackingList>true</PackingList>
<ChunkList>
<Chunk>
<Path>PKL_52f61ec0-1517-49b7-a8e2-941c0200c69a.xml</Path>
<VolumeIndex>1</VolumeIndex>
<Offset>0</Offset>
<Length>1708</Length>
</Chunk>
</ChunkList>
</Asset>
</AssetList>
</AssetMap>
Binary file not shown.
Loading

0 comments on commit 0ebf06a

Please sign in to comment.