Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

MKV Dolby Vision Support #7667

Merged
merged 8 commits into from
Aug 26, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@
import com.google.android.exoplayer2.util.Util;
import com.google.android.exoplayer2.video.AvcConfig;
import com.google.android.exoplayer2.video.ColorInfo;
import com.google.android.exoplayer2.video.DolbyVisionConfig;
import com.google.android.exoplayer2.video.HevcConfig;
import java.io.IOException;
import java.lang.annotation.Documented;
Expand Down Expand Up @@ -155,8 +156,11 @@ public class MatroskaExtractor implements Extractor {
private static final int ID_BLOCK = 0xA1;
private static final int ID_BLOCK_DURATION = 0x9B;
private static final int ID_BLOCK_ADDITIONS = 0x75A1;
private static final int ID_BLOCK_ADDITION_MAPPING = 0x41E4;
private static final int ID_BLOCK_MORE = 0xA6;
private static final int ID_BLOCK_ADD_ID = 0xEE;
private static final int ID_BLOCK_ADD_ID_TYPE = 0x41E7;
private static final int ID_BLOCK_ADD_ID_EXTRA_DATA = 0x41ED;
private static final int ID_BLOCK_ADDITIONAL = 0xA5;
private static final int ID_REFERENCE_BLOCK = 0xFB;
private static final int ID_TRACKS = 0x1654AE6B;
Expand Down Expand Up @@ -231,6 +235,18 @@ public class MatroskaExtractor implements Extractor {
*/
private static final int BLOCK_ADDITIONAL_ID_VP9_ITU_T_35 = 4;

/**
* Dolby Vision configuration for profiles <= 7
* https://www.matroska.org/technical/codec_specs.html
*/
private static final int BLOCK_ADD_ID_TYPE_DVCC = 0x64766343;

/**
* Dolby Vision configuration for profiles > 7
* https://www.matroska.org/technical/codec_specs.html
*/
private static final int BLOCK_ADD_ID_TYPE_DVVC = 0x64767643;

private static final int LACING_NONE = 0;
private static final int LACING_XIPH = 1;
private static final int LACING_FIXED_SIZE = 2;
Expand Down Expand Up @@ -510,6 +526,7 @@ protected int getElementType(int id) {
case ID_CUE_TRACK_POSITIONS:
case ID_BLOCK_GROUP:
case ID_BLOCK_ADDITIONS:
case ID_BLOCK_ADDITION_MAPPING:
case ID_BLOCK_MORE:
case ID_PROJECTION:
case ID_COLOUR:
Expand Down Expand Up @@ -552,6 +569,7 @@ protected int getElementType(int id) {
case ID_MAX_FALL:
case ID_PROJECTION_TYPE:
case ID_BLOCK_ADD_ID:
case ID_BLOCK_ADD_ID_TYPE:
return EbmlProcessor.ELEMENT_TYPE_UNSIGNED_INT;
case ID_DOC_TYPE:
case ID_NAME:
Expand All @@ -566,6 +584,7 @@ protected int getElementType(int id) {
case ID_CODEC_PRIVATE:
case ID_PROJECTION_PRIVATE:
case ID_BLOCK_ADDITIONAL:
case ID_BLOCK_ADD_ID_EXTRA_DATA:
return EbmlProcessor.ELEMENT_TYPE_BINARY;
case ID_DURATION:
case ID_SAMPLING_FREQUENCY:
Expand Down Expand Up @@ -968,6 +987,9 @@ protected void integerElement(int id, long value) throws ParserException {
case ID_BLOCK_ADD_ID:
blockAdditionalId = (int) value;
break;
case ID_BLOCK_ADD_ID_TYPE:
currentTrack.blockAddIdType = (int) value;
break;
default:
break;
}
Expand Down Expand Up @@ -1092,6 +1114,9 @@ protected void binaryElement(int id, int contentSize, ExtractorInput input) thro
currentTrack.cryptoData = new TrackOutput.CryptoData(C.CRYPTO_MODE_AES_CTR, encryptionKey,
0, 0); // We assume patternless AES-CTR.
break;
case ID_BLOCK_ADD_ID_EXTRA_DATA:
handleBlockAddIDExtraData(currentTrack, input, contentSize);
break;
case ID_SIMPLE_BLOCK:
case ID_BLOCK:
// Please refer to http://www.matroska.org/technical/specs/index.html#simpleblock_structure
Expand Down Expand Up @@ -1243,6 +1268,7 @@ protected void binaryElement(int id, int contentSize, ExtractorInput input) thro
protected void handleBlockAdditionalData(
Track track, int blockAdditionalId, ExtractorInput input, int contentSize)
throws IOException {

if (blockAdditionalId == BLOCK_ADDITIONAL_ID_VP9_ITU_T_35
&& CODEC_ID_VP9.equals(track.codecId)) {
blockAdditionalData.reset(contentSize);
Expand All @@ -1253,6 +1279,19 @@ protected void handleBlockAdditionalData(
}
}

protected void handleBlockAddIDExtraData(
Track track, ExtractorInput input, int contentSize)
throws IOException {

if (track.blockAddIdType == BLOCK_ADD_ID_TYPE_DVVC || track.blockAddIdType == BLOCK_ADD_ID_TYPE_DVCC) {
track.doviDecoderConfigurationRecord = new byte[contentSize];
input.readFully(track.doviDecoderConfigurationRecord, 0, contentSize);
} else {
// Unhandled block additional data.
input.skipFully(contentSize);
}
}

private void commitSampleToOutput(
Track track, long timeUs, @C.BufferFlags int flags, int size, int offset) {
if (track.trueHdSampleRechunker != null) {
Expand Down Expand Up @@ -1915,6 +1954,8 @@ private static final class Track {
public float whitePointChromaticityY = Format.NO_VALUE;
public float maxMasteringLuminance = Format.NO_VALUE;
public float minMasteringLuminance = Format.NO_VALUE;
// DOVIDecoderConfigurationRecord structure as defined in [@!DolbyVisionWithinIso.2020-02]
@Nullable public byte[] doviDecoderConfigurationRecord = null;

// Audio elements. Initially set to their default values.
public int channelCount = 1;
Expand All @@ -1933,6 +1974,9 @@ private static final class Track {
public TrackOutput output;
public int nalUnitLengthFieldLength;

// Block additional state
private int blockAddIdType;

/** Initializes the track with an output. */
public void initializeOutput(ExtractorOutput output, int trackId) throws ParserException {
String mimeType;
Expand Down Expand Up @@ -2085,6 +2129,16 @@ public void initializeOutput(ExtractorOutput output, int trackId) throws ParserE
throw new ParserException("Unrecognized codec identifier.");
}


if(doviDecoderConfigurationRecord != null) {
@Nullable DolbyVisionConfig dolbyVisionConfig = DolbyVisionConfig
.parse(new ParsableByteArray(doviDecoderConfigurationRecord));
if (dolbyVisionConfig != null) {
codecs = dolbyVisionConfig.codecs;
mimeType = MimeTypes.VIDEO_DOLBY_VISION;
}
}

@C.SelectionFlags int selectionFlags = 0;
selectionFlags |= flagDefault ? C.SELECTION_FLAG_DEFAULT : 0;
selectionFlags |= flagForced ? C.SELECTION_FLAG_FORCED : 0;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,4 +68,16 @@ public void webmSubsampleEncryptionWithAltrefFrames() throws Exception {
ExtractorAsserts.assertBehavior(
MatroskaExtractor::new, "mkv/subsample_encrypted_altref.webm", simulationConfig);
}

@Test
public void mkvSampleWithProfile5DolbyVision() throws Exception {
ExtractorAsserts.assertBehavior(
MatroskaExtractor::new, "mkv/dvhe_05_05.mkv", simulationConfig);
}

@Test
public void mkvSampleWithProfile8DolbyVision() throws Exception {
ExtractorAsserts.assertBehavior(
MatroskaExtractor::new, "mkv/hev1_08_05.mkv", simulationConfig);
}g
}
Original file line number Diff line number Diff line change
Expand Up @@ -74,4 +74,14 @@ public void mp4SampleWithEac3Track() throws Exception {
public void mp4SampleWithEac3jocTrack() throws Exception {
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/sample_eac3joc.mp4", simulationConfig);
}

@Test
public void mp4SampleWithProfile5DolbyVision() throws Exception {
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/dvhe_05_05.mp4", simulationConfig);
}

@Test
public void mp4SampleWithProfile8DolbyVision() throws Exception {
ExtractorAsserts.assertBehavior(Mp4Extractor::new, "mp4/hev1_08_05.mp4", simulationConfig);
}
}
Binary file added testdata/src/test/assets/mkv/dvhe_05_05.mkv
Binary file not shown.
Loading