Add support for depth/editing file format in Mp4Extractor
PiperOrigin-RevId: 662956209
This commit is contained in:
parent
92635342fb
commit
68eaa061e0
@ -119,6 +119,21 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
|
||||
validateData(key, value, typeIndicator);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editable track types from the {@linkplain #KEY_EDITABLE_TRACKS_MAP editable tracks
|
||||
* map} metadata.
|
||||
*/
|
||||
public List<Integer> getEditableTrackTypesFromMap() {
|
||||
checkState(key.equals(KEY_EDITABLE_TRACKS_MAP), "Metadata is not an editable tracks map");
|
||||
// Value has 1 byte version, 1 byte track count, n bytes track types.
|
||||
int numberOfTracks = value[1];
|
||||
List<Integer> trackTypes = new ArrayList<>();
|
||||
for (int i = 0; i < numberOfTracks; i++) {
|
||||
trackTypes.add((int) value[i + 2]);
|
||||
}
|
||||
return trackTypes;
|
||||
}
|
||||
|
||||
@Override
|
||||
public boolean equals(@Nullable Object obj) {
|
||||
if (this == obj) {
|
||||
@ -235,19 +250,4 @@ public final class MdtaMetadataEntry implements Metadata.Entry {
|
||||
Joiner.on(',').appendTo(sb, trackTypes);
|
||||
return sb.toString();
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the editable track types from the {@linkplain #KEY_EDITABLE_TRACKS_MAP editable tracks
|
||||
* map} metadata.
|
||||
*/
|
||||
private List<Integer> getEditableTrackTypesFromMap() {
|
||||
checkState(key.equals(KEY_EDITABLE_TRACKS_MAP), "Metadata is not an editable tracks map");
|
||||
// Value has 1 byte version, 1 byte track count, n bytes track types.
|
||||
int numberOfTracks = value[1];
|
||||
List<Integer> trackTypes = new ArrayList<>();
|
||||
for (int i = 0; i < numberOfTracks; i++) {
|
||||
trackTypes.add((int) value[i + 2]);
|
||||
}
|
||||
return trackTypes;
|
||||
}
|
||||
}
|
||||
|
@ -446,6 +446,9 @@ import java.util.List;
|
||||
@SuppressWarnings("ConstantCaseForConstants")
|
||||
public static final int TYPE_iacb = 0x69616362;
|
||||
|
||||
@SuppressWarnings("ConstantCaseForConstants")
|
||||
public static final int TYPE_edvd = 0x65647664;
|
||||
|
||||
public final int type;
|
||||
|
||||
public Atom(int type) {
|
||||
|
@ -238,6 +238,27 @@ import com.google.common.collect.ImmutableList;
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns the {@link MdtaMetadataEntry} for a given key, or {@code null} if the key is not
|
||||
* present.
|
||||
*
|
||||
* @param metadata The {@link Metadata} to retrieve the {@link MdtaMetadataEntry} from.
|
||||
* @param key The metadata key to search.
|
||||
*/
|
||||
@Nullable
|
||||
public static MdtaMetadataEntry findMdtaMetadataEntryWithKey(Metadata metadata, String key) {
|
||||
for (int i = 0; i < metadata.length(); i++) {
|
||||
Metadata.Entry entry = metadata.get(i);
|
||||
if (entry instanceof MdtaMetadataEntry) {
|
||||
MdtaMetadataEntry mdtaMetadataEntry = (MdtaMetadataEntry) entry;
|
||||
if (mdtaMetadataEntry.key.equals(key)) {
|
||||
return mdtaMetadataEntry;
|
||||
}
|
||||
}
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private static TextInformationFrame parseTextAttribute(
|
||||
int type, String id, ParsableByteArray data) {
|
||||
|
@ -15,9 +15,21 @@
|
||||
*/
|
||||
package androidx.media3.extractor.mp4;
|
||||
|
||||
import static androidx.media3.common.C.AUXILIARY_TRACK_TYPE_DEPTH_INVERSE;
|
||||
import static androidx.media3.common.C.AUXILIARY_TRACK_TYPE_DEPTH_LINEAR;
|
||||
import static androidx.media3.common.C.AUXILIARY_TRACK_TYPE_ORIGINAL;
|
||||
import static androidx.media3.common.C.AUXILIARY_TRACK_TYPE_UNDEFINED;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Assertions.checkState;
|
||||
import static androidx.media3.common.util.Assertions.checkStateNotNull;
|
||||
import static androidx.media3.common.util.Util.castNonNull;
|
||||
import static androidx.media3.container.MdtaMetadataEntry.EDITABLE_TRACKS_SAMPLES_LOCATION_IN_EDIT_DATA_MP4;
|
||||
import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_INVERSE;
|
||||
import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_LINEAR;
|
||||
import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_DEPTH_METADATA;
|
||||
import static androidx.media3.container.Mp4Util.EDITABLE_TRACK_TYPE_SHARP;
|
||||
import static androidx.media3.extractor.mp4.AtomParsers.parseTraks;
|
||||
import static androidx.media3.extractor.mp4.MetadataUtil.findMdtaMetadataEntryWithKey;
|
||||
import static androidx.media3.extractor.mp4.Sniffer.BRAND_HEIC;
|
||||
import static androidx.media3.extractor.mp4.Sniffer.BRAND_QUICKTIME;
|
||||
import static java.lang.Math.max;
|
||||
@ -34,6 +46,7 @@ import androidx.media3.common.ParserException;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.ParsableByteArray;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.container.MdtaMetadataEntry;
|
||||
import androidx.media3.container.NalUnitUtil;
|
||||
import androidx.media3.extractor.Ac3Util;
|
||||
import androidx.media3.extractor.Ac4Util;
|
||||
@ -62,6 +75,7 @@ import java.lang.annotation.Target;
|
||||
import java.util.ArrayDeque;
|
||||
import java.util.ArrayList;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
import java.util.Objects;
|
||||
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
@ -93,7 +107,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
FLAG_READ_SEF_DATA,
|
||||
FLAG_MARK_FIRST_VIDEO_TRACK_WITH_MAIN_ROLE,
|
||||
FLAG_EMIT_RAW_SUBTITLE_DATA,
|
||||
FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES
|
||||
FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES,
|
||||
FLAG_READ_EDITABLE_VIDEO_TRACKS
|
||||
})
|
||||
public @interface Flags {}
|
||||
|
||||
@ -143,6 +158,18 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
*/
|
||||
public static final int FLAG_READ_WITHIN_GOP_SAMPLE_DEPENDENCIES = 1 << 5;
|
||||
|
||||
// TODO: b/345219017 - Add depth/editing file format spec link after its published.
|
||||
/**
|
||||
* Flag to extract the editable video tracks.
|
||||
*
|
||||
* <p>Either primary video tracks or editable video tracks (but not both) will be extracted based
|
||||
* on the flag.
|
||||
*
|
||||
* <p>If the flag is set but the editable video tracks are not present, then it fallbacks to
|
||||
* extract primary tracks instead.
|
||||
*/
|
||||
public static final int FLAG_READ_EDITABLE_VIDEO_TRACKS = 1 << 6;
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #newFactory(SubtitleParser.Factory)} instead.
|
||||
*/
|
||||
@ -219,6 +246,12 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
private int sampleCurrentNalBytesRemaining;
|
||||
private boolean isSampleDependedOn;
|
||||
private boolean seenFtypAtom;
|
||||
private boolean seekToEdvdAtom;
|
||||
private long edvdAtomOffset;
|
||||
private boolean readingEditableVideoTracks;
|
||||
|
||||
// Used when editable video samples are in the edit data MP4 (inside edvd atom).
|
||||
private long sampleOffsetForEditableVideoTracks;
|
||||
|
||||
// Extractor outputs.
|
||||
private ExtractorOutput extractorOutput;
|
||||
@ -527,9 +560,10 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
}
|
||||
|
||||
/**
|
||||
* Processes the atom payload. If {@link #atomData} is null and the size is at or above the
|
||||
* threshold {@link #RELOAD_MINIMUM_SEEK_DISTANCE}, {@code true} is returned and the caller should
|
||||
* restart loading at the position in {@code positionHolder}. Otherwise, the atom is read/skipped.
|
||||
* Processes the atom payload.
|
||||
*
|
||||
* <p>If seek is required, {@code true} is returned and the caller should restart loading at the
|
||||
* position in {@code positionHolder}. Otherwise the atom is read/skipped.
|
||||
*/
|
||||
private boolean readAtomPayload(ExtractorInput input, PositionHolder positionHolder)
|
||||
throws IOException {
|
||||
@ -560,6 +594,12 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
}
|
||||
}
|
||||
processAtomEnded(atomEndPosition);
|
||||
if (seekToEdvdAtom) {
|
||||
readingEditableVideoTracks = true;
|
||||
positionHolder.position = edvdAtomOffset;
|
||||
seekRequired = true;
|
||||
seekToEdvdAtom = false;
|
||||
}
|
||||
return seekRequired && parserState != STATE_READING_SAMPLE;
|
||||
}
|
||||
|
||||
@ -579,7 +619,9 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
// We've reached the end of the moov atom. Process it and prepare to read samples.
|
||||
processMoovAtom(containerAtom);
|
||||
containerAtoms.clear();
|
||||
parserState = STATE_READING_SAMPLE;
|
||||
if (!seekToEdvdAtom) {
|
||||
parserState = STATE_READING_SAMPLE;
|
||||
}
|
||||
} else if (!containerAtoms.isEmpty()) {
|
||||
containerAtoms.peek().add(containerAtom);
|
||||
}
|
||||
@ -589,13 +631,35 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
}
|
||||
}
|
||||
|
||||
/** Updates the stored track metadata to reflect the contents of the specified moov atom. */
|
||||
/**
|
||||
* Processes moov atom and updates the stored track metadata.
|
||||
*
|
||||
* <p>The processing is aborted if the edvd.moov atom needs to be processed instead.
|
||||
*/
|
||||
private void processMoovAtom(ContainerAtom moov) throws ParserException {
|
||||
// Process metadata first to determine whether to abort processing and seek to the edvd atom.
|
||||
@Nullable Metadata mdtaMetadata = null;
|
||||
@Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
|
||||
List<@C.AuxiliaryTrackType Integer> auxiliaryTrackTypesForEditableVideoTracks =
|
||||
new ArrayList<>();
|
||||
if (meta != null) {
|
||||
mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
|
||||
if (readingEditableVideoTracks) {
|
||||
checkStateNotNull(mdtaMetadata);
|
||||
maybeSetDefaultSampleOffsetForEditableVideoTracks(mdtaMetadata);
|
||||
auxiliaryTrackTypesForEditableVideoTracks =
|
||||
getAuxiliaryTrackTypesForEditableVideoTracks(mdtaMetadata);
|
||||
} else if (shouldSeekToEdvdAtom(mdtaMetadata)) {
|
||||
seekToEdvdAtom = true;
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
int firstVideoTrackIndex = C.INDEX_UNSET;
|
||||
long durationUs = C.TIME_UNSET;
|
||||
List<Mp4Track> tracks = new ArrayList<>();
|
||||
|
||||
// Process metadata.
|
||||
// Process remaining metadata.
|
||||
boolean isQuickTime = fileType == FILE_TYPE_QUICKTIME;
|
||||
GaplessInfoHolder gaplessInfoHolder = new GaplessInfoHolder();
|
||||
@Nullable Metadata udtaMetadata = null;
|
||||
@ -604,11 +668,6 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
udtaMetadata = AtomParsers.parseUdta(udta);
|
||||
gaplessInfoHolder.setFromMetadata(udtaMetadata);
|
||||
}
|
||||
@Nullable Metadata mdtaMetadata = null;
|
||||
@Nullable Atom.ContainerAtom meta = moov.getContainerAtomOfType(Atom.TYPE_meta);
|
||||
if (meta != null) {
|
||||
mdtaMetadata = AtomParsers.parseMdtaFromMeta(meta);
|
||||
}
|
||||
|
||||
Metadata mvhdMetadata =
|
||||
new Metadata(
|
||||
@ -625,6 +684,16 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
isQuickTime,
|
||||
/* modifyTrackFunction= */ track -> track);
|
||||
|
||||
if (readingEditableVideoTracks) {
|
||||
checkState(
|
||||
auxiliaryTrackTypesForEditableVideoTracks.size() == trackSampleTables.size(),
|
||||
String.format(
|
||||
Locale.US,
|
||||
"The number of auxiliary track types from metadata (%d) is not same as the number of"
|
||||
+ " editable video tracks (%d)",
|
||||
auxiliaryTrackTypesForEditableVideoTracks.size(),
|
||||
trackSampleTables.size()));
|
||||
}
|
||||
int trackIndex = 0;
|
||||
for (int i = 0; i < trackSampleTables.size(); i++) {
|
||||
TrackSampleTable trackSampleTable = trackSampleTables.get(i);
|
||||
@ -651,17 +720,20 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
Format.Builder formatBuilder = track.format.buildUpon();
|
||||
formatBuilder.setMaxInputSize(maxInputSize);
|
||||
if (track.type == C.TRACK_TYPE_VIDEO) {
|
||||
@C.RoleFlags int roleFlags = track.format.roleFlags;
|
||||
if ((flags & FLAG_MARK_FIRST_VIDEO_TRACK_WITH_MAIN_ROLE) != 0) {
|
||||
formatBuilder.setRoleFlags(
|
||||
track.format.roleFlags
|
||||
| (firstVideoTrackIndex == C.INDEX_UNSET
|
||||
? C.ROLE_FLAG_MAIN
|
||||
: C.ROLE_FLAG_ALTERNATE));
|
||||
roleFlags |=
|
||||
firstVideoTrackIndex == C.INDEX_UNSET ? C.ROLE_FLAG_MAIN : C.ROLE_FLAG_ALTERNATE;
|
||||
}
|
||||
if (trackDurationUs > 0 && trackSampleTable.sampleCount > 0) {
|
||||
float frameRate = trackSampleTable.sampleCount / (trackDurationUs / 1000000f);
|
||||
formatBuilder.setFrameRate(frameRate);
|
||||
}
|
||||
if (readingEditableVideoTracks) {
|
||||
roleFlags |= C.ROLE_FLAG_AUXILIARY;
|
||||
formatBuilder.setAuxiliaryTrackType(auxiliaryTrackTypesForEditableVideoTracks.get(i));
|
||||
}
|
||||
formatBuilder.setRoleFlags(roleFlags);
|
||||
}
|
||||
|
||||
MetadataUtil.setFormatGaplessInfo(track.type, gaplessInfoHolder, formatBuilder);
|
||||
@ -688,6 +760,72 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
extractorOutput.seekMap(this);
|
||||
}
|
||||
|
||||
private boolean shouldSeekToEdvdAtom(@Nullable Metadata mdtaMetadata) {
|
||||
if (mdtaMetadata == null) {
|
||||
return false;
|
||||
}
|
||||
if ((flags & FLAG_READ_EDITABLE_VIDEO_TRACKS) != 0) {
|
||||
@Nullable
|
||||
MdtaMetadataEntry edvdAtomOffsetMetadata =
|
||||
findMdtaMetadataEntryWithKey(mdtaMetadata, MdtaMetadataEntry.KEY_EDITABLE_TRACKS_OFFSET);
|
||||
if (edvdAtomOffsetMetadata != null) {
|
||||
long offset = new ParsableByteArray(edvdAtomOffsetMetadata.value).readUnsignedLongToLong();
|
||||
if (offset > 0) {
|
||||
edvdAtomOffset = offset;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the sample offset for the editable video tracks, if the samples are in the edit data MP4
|
||||
* (inside edvd atom).
|
||||
*/
|
||||
private void maybeSetDefaultSampleOffsetForEditableVideoTracks(Metadata metadata) {
|
||||
@Nullable
|
||||
MdtaMetadataEntry sampleLocationMetadata =
|
||||
findMdtaMetadataEntryWithKey(
|
||||
metadata, MdtaMetadataEntry.KEY_EDITABLE_TRACKS_SAMPLES_LOCATION);
|
||||
if (sampleLocationMetadata != null) {
|
||||
if (sampleLocationMetadata.value[0] == EDITABLE_TRACKS_SAMPLES_LOCATION_IN_EDIT_DATA_MP4) {
|
||||
sampleOffsetForEditableVideoTracks = edvdAtomOffset + 16; // 16 bits for edvd atom header
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private List<@C.AuxiliaryTrackType Integer> getAuxiliaryTrackTypesForEditableVideoTracks(
|
||||
Metadata metadata) {
|
||||
MdtaMetadataEntry trackTypesMetadata =
|
||||
checkStateNotNull(
|
||||
findMdtaMetadataEntryWithKey(metadata, MdtaMetadataEntry.KEY_EDITABLE_TRACKS_MAP));
|
||||
List<Integer> editableVideoTrackTypes = trackTypesMetadata.getEditableTrackTypesFromMap();
|
||||
List<@C.AuxiliaryTrackType Integer> auxiliaryTrackTypes =
|
||||
new ArrayList<>(editableVideoTrackTypes.size());
|
||||
for (int i = 0; i < editableVideoTrackTypes.size(); i++) {
|
||||
@C.AuxiliaryTrackType int auxiliaryTrackType;
|
||||
switch (editableVideoTrackTypes.get(i)) {
|
||||
case EDITABLE_TRACK_TYPE_SHARP:
|
||||
auxiliaryTrackType = AUXILIARY_TRACK_TYPE_ORIGINAL;
|
||||
break;
|
||||
case EDITABLE_TRACK_TYPE_DEPTH_LINEAR:
|
||||
auxiliaryTrackType = AUXILIARY_TRACK_TYPE_DEPTH_LINEAR;
|
||||
break;
|
||||
case EDITABLE_TRACK_TYPE_DEPTH_INVERSE:
|
||||
auxiliaryTrackType = AUXILIARY_TRACK_TYPE_DEPTH_INVERSE;
|
||||
break;
|
||||
case EDITABLE_TRACK_TYPE_DEPTH_METADATA:
|
||||
auxiliaryTrackType = C.AUXILIARY_TRACK_TYPE_DEPTH_METADATA;
|
||||
break;
|
||||
default:
|
||||
auxiliaryTrackType = AUXILIARY_TRACK_TYPE_UNDEFINED;
|
||||
}
|
||||
auxiliaryTrackTypes.add(auxiliaryTrackType);
|
||||
}
|
||||
return auxiliaryTrackTypes;
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to extract the next sample in the current mdat atom for the specified track.
|
||||
*
|
||||
@ -714,7 +852,7 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
Mp4Track track = tracks[sampleTrackIndex];
|
||||
TrackOutput trackOutput = track.trackOutput;
|
||||
int sampleIndex = track.sampleIndex;
|
||||
long position = track.sampleTable.offsets[sampleIndex];
|
||||
long position = track.sampleTable.offsets[sampleIndex] + sampleOffsetForEditableVideoTracks;
|
||||
int sampleSize = track.sampleTable.sizes[sampleIndex];
|
||||
@Nullable TrueHdSampleRechunker trueHdSampleRechunker = track.trueHdSampleRechunker;
|
||||
long skipAmount = position - inputPosition + sampleBytesRead;
|
||||
@ -1067,7 +1205,8 @@ public final class Mp4Extractor implements Extractor, SeekMap {
|
||||
|| atom == Atom.TYPE_minf
|
||||
|| atom == Atom.TYPE_stbl
|
||||
|| atom == Atom.TYPE_edts
|
||||
|| atom == Atom.TYPE_meta;
|
||||
|| atom == Atom.TYPE_meta
|
||||
|| atom == Atom.TYPE_edvd;
|
||||
}
|
||||
|
||||
private static final class Mp4Track {
|
||||
|
@ -17,10 +17,13 @@ package androidx.media3.extractor.mp4;
|
||||
|
||||
import static com.google.common.truth.Truth.assertThat;
|
||||
|
||||
import android.content.Context;
|
||||
import androidx.media3.extractor.Extractor;
|
||||
import androidx.media3.extractor.PositionHolder;
|
||||
import androidx.media3.extractor.SniffFailure;
|
||||
import androidx.media3.extractor.text.DefaultSubtitleParserFactory;
|
||||
import androidx.media3.extractor.text.SubtitleParser;
|
||||
import androidx.media3.test.utils.DumpFileAsserts;
|
||||
import androidx.media3.test.utils.FakeExtractorInput;
|
||||
import androidx.media3.test.utils.FakeExtractorOutput;
|
||||
import androidx.media3.test.utils.FakeTrackOutput;
|
||||
@ -102,6 +105,44 @@ public final class Mp4ExtractorNonParameterizedTest {
|
||||
assertThat(extractorSeekTimeUs).isIn(trackSeekTimesUs.build());
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
extract_fileHavingNoEditableVideoTracksWithReadEditableVideoTracksFlag_extractsPrimaryVideoTracks()
|
||||
throws Exception {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
String inputFilePath = "media/mp4/sample.mp4";
|
||||
Mp4Extractor mp4Extractor =
|
||||
new Mp4Extractor(
|
||||
new DefaultSubtitleParserFactory(), Mp4Extractor.FLAG_READ_EDITABLE_VIDEO_TRACKS);
|
||||
|
||||
FakeExtractorOutput primaryTracksOutput =
|
||||
TestUtil.extractAllSamplesFromFile(mp4Extractor, context, inputFilePath);
|
||||
|
||||
String dumpFilePath = getDumpFilePath(inputFilePath, "_with_flag_read_Editable_video_tracks");
|
||||
DumpFileAsserts.assertOutput(context, primaryTracksOutput, dumpFilePath);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void
|
||||
extract_fileHavingEditableVideoTracksWithReadEditableVideoTracksFlag_extractsEditableVideoTracks()
|
||||
throws Exception {
|
||||
Context context = ApplicationProvider.getApplicationContext();
|
||||
String inputFilePath = "media/mp4/sample_with_fake_editable_video_tracks.mp4";
|
||||
Mp4Extractor mp4Extractor =
|
||||
new Mp4Extractor(
|
||||
new DefaultSubtitleParserFactory(), Mp4Extractor.FLAG_READ_EDITABLE_VIDEO_TRACKS);
|
||||
|
||||
FakeExtractorOutput editableTracksOutput =
|
||||
TestUtil.extractAllSamplesFromFile(mp4Extractor, context, inputFilePath);
|
||||
|
||||
String dumpFilePath = getDumpFilePath(inputFilePath, "_with_flag_read_Editable_video_tracks");
|
||||
DumpFileAsserts.assertOutput(context, editableTracksOutput, dumpFilePath);
|
||||
}
|
||||
|
||||
private static String getDumpFilePath(String inputFilePath, String suffix) {
|
||||
return inputFilePath.replaceFirst("media", "extractordumps") + suffix;
|
||||
}
|
||||
|
||||
private static FakeExtractorInput createInputForSample(String sample) throws IOException {
|
||||
return new FakeExtractorInput.Builder()
|
||||
.setData(
|
||||
|
@ -218,6 +218,11 @@ public final class Mp4ExtractorParameterizedTest {
|
||||
assertExtractorBehavior("media/mp4/water_180_mvhevc_5frames.mov");
|
||||
}
|
||||
|
||||
@Test
|
||||
public void mp4WithEditableVideoTracks() throws Exception {
|
||||
assertExtractorBehavior("media/mp4/sample_with_fake_editable_video_tracks.mp4");
|
||||
}
|
||||
|
||||
private void assertExtractorBehavior(String file) throws IOException {
|
||||
ExtractorAsserts.AssertionConfig.Builder assertionConfigBuilder =
|
||||
new ExtractorAsserts.AssertionConfig.Builder();
|
||||
|
@ -25,8 +25,6 @@ import android.content.Context;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.util.Assertions;
|
||||
import androidx.media3.common.util.ParsableByteArray;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.container.MdtaMetadataEntry;
|
||||
import androidx.media3.container.Mp4LocationData;
|
||||
@ -43,7 +41,6 @@ import androidx.media3.test.utils.TestUtil;
|
||||
import androidx.test.core.app.ApplicationProvider;
|
||||
import androidx.test.ext.junit.runners.AndroidJUnit4;
|
||||
import java.io.FileOutputStream;
|
||||
import java.io.IOException;
|
||||
import java.nio.ByteBuffer;
|
||||
import org.junit.Rule;
|
||||
import org.junit.Test;
|
||||
@ -510,7 +507,7 @@ public class Mp4MuxerEndToEndTest {
|
||||
FakeExtractorOutput primaryTracksOutput =
|
||||
TestUtil.extractAllSamplesFromFilePath(
|
||||
new Mp4Extractor(new DefaultSubtitleParserFactory()), outputFilePath);
|
||||
// The Mp4Extractor can not read edvd box and can only parse primary tracks.
|
||||
// The Mp4Extractor extracts primary tracks by default.
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
primaryTracksOutput,
|
||||
@ -556,11 +553,11 @@ public class Mp4MuxerEndToEndTest {
|
||||
muxer.close();
|
||||
}
|
||||
|
||||
byte[] edvdBoxPayload = getEdvdBoxPayload(outputFilePath);
|
||||
FakeExtractorOutput editableTracksOutput =
|
||||
TestUtil.extractAllSamplesFromByteArray(
|
||||
new Mp4Extractor(new DefaultSubtitleParserFactory()), edvdBoxPayload);
|
||||
// The Mp4Extractor can parse the MP4 embedded in the edvd box.
|
||||
TestUtil.extractAllSamplesFromFilePath(
|
||||
new Mp4Extractor(
|
||||
new DefaultSubtitleParserFactory(), Mp4Extractor.FLAG_READ_EDITABLE_VIDEO_TRACKS),
|
||||
outputFilePath);
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
editableTracksOutput,
|
||||
@ -575,28 +572,4 @@ public class Mp4MuxerEndToEndTest {
|
||||
muxer.writeSampleData(trackToken, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||
}
|
||||
}
|
||||
|
||||
private static byte[] getEdvdBoxPayload(String filePath) throws IOException {
|
||||
ParsableByteArray data = new ParsableByteArray(TestUtil.getByteArrayFromFilePath(filePath));
|
||||
while (data.bytesLeft() > 0) {
|
||||
long size = data.readInt();
|
||||
String name = data.readString(/* length= */ 4);
|
||||
long payloadSize = size - 8;
|
||||
if (size == 1) {
|
||||
size = data.readUnsignedLongToLong();
|
||||
// Parsing is not supported for box having size > Integer.MAX_VALUE.
|
||||
Assertions.checkState(size <= Integer.MAX_VALUE);
|
||||
// Subtract 4 bytes (32-bit box size) + 4 bytes (box name) + 8 bytes (64-bit box size).
|
||||
payloadSize = size - 16;
|
||||
}
|
||||
if (name.equals("edvd")) {
|
||||
byte[] payloadData = new byte[(int) payloadSize];
|
||||
data.readBytes(payloadData, /* offset= */ 0, (int) payloadSize);
|
||||
return payloadData;
|
||||
} else {
|
||||
data.skipBytes((int) payloadSize);
|
||||
}
|
||||
}
|
||||
return new byte[0];
|
||||
}
|
||||
}
|
||||
|
@ -0,0 +1,343 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1024000
|
||||
getPosition(0) = [[timeUs=0, position=2269]]
|
||||
getPosition(1) = [[timeUs=0, position=2269]]
|
||||
getPosition(512000) = [[timeUs=0, position=2269]]
|
||||
getPosition(1024000) = [[timeUs=0, position=2269]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 89876
|
||||
sample count = 30
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.64001F
|
||||
maxInputSize = 36722
|
||||
maxNumReorderSamples = 2
|
||||
width = 1080
|
||||
height = 720
|
||||
frameRate = 29.970028
|
||||
colorInfo:
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[TSSE: description=null: values=[Lavf56.1.0], xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=1000]
|
||||
initializationData:
|
||||
data = length 29, hash 4746B5D9
|
||||
data = length 10, hash 7A0D0F2B
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 36692, hash D216076E
|
||||
sample 1:
|
||||
time = 66733
|
||||
flags = 0
|
||||
data = length 5312, hash D45D3CA0
|
||||
sample 2:
|
||||
time = 33366
|
||||
flags = 0
|
||||
data = length 599, hash 1BE7812D
|
||||
sample 3:
|
||||
time = 200200
|
||||
flags = 0
|
||||
data = length 7735, hash 4490F110
|
||||
sample 4:
|
||||
time = 133466
|
||||
flags = 0
|
||||
data = length 987, hash 560B5036
|
||||
sample 5:
|
||||
time = 100100
|
||||
flags = 0
|
||||
data = length 673, hash ED7CD8C7
|
||||
sample 6:
|
||||
time = 166833
|
||||
flags = 0
|
||||
data = length 523, hash 3020DF50
|
||||
sample 7:
|
||||
time = 333666
|
||||
flags = 0
|
||||
data = length 6061, hash 736C72B2
|
||||
sample 8:
|
||||
time = 266933
|
||||
flags = 0
|
||||
data = length 992, hash FE132F23
|
||||
sample 9:
|
||||
time = 233566
|
||||
flags = 0
|
||||
data = length 623, hash 5B2C1816
|
||||
sample 10:
|
||||
time = 300300
|
||||
flags = 0
|
||||
data = length 421, hash 742E69C1
|
||||
sample 11:
|
||||
time = 433766
|
||||
flags = 0
|
||||
data = length 4899, hash F72F86A1
|
||||
sample 12:
|
||||
time = 400400
|
||||
flags = 0
|
||||
data = length 568, hash 519A8E50
|
||||
sample 13:
|
||||
time = 367033
|
||||
flags = 0
|
||||
data = length 620, hash 3990AA39
|
||||
sample 14:
|
||||
time = 567233
|
||||
flags = 0
|
||||
data = length 5450, hash F06EC4AA
|
||||
sample 15:
|
||||
time = 500500
|
||||
flags = 0
|
||||
data = length 1051, hash 92DFA63A
|
||||
sample 16:
|
||||
time = 467133
|
||||
flags = 0
|
||||
data = length 874, hash 69587FB4
|
||||
sample 17:
|
||||
time = 533866
|
||||
flags = 0
|
||||
data = length 781, hash 36BE495B
|
||||
sample 18:
|
||||
time = 700700
|
||||
flags = 0
|
||||
data = length 4725, hash AC0C8CD3
|
||||
sample 19:
|
||||
time = 633966
|
||||
flags = 0
|
||||
data = length 1022, hash 5D8BFF34
|
||||
sample 20:
|
||||
time = 600600
|
||||
flags = 0
|
||||
data = length 790, hash 99413A99
|
||||
sample 21:
|
||||
time = 667333
|
||||
flags = 0
|
||||
data = length 610, hash 5E129290
|
||||
sample 22:
|
||||
time = 834166
|
||||
flags = 0
|
||||
data = length 2751, hash 769974CB
|
||||
sample 23:
|
||||
time = 767433
|
||||
flags = 0
|
||||
data = length 745, hash B78A477A
|
||||
sample 24:
|
||||
time = 734066
|
||||
flags = 0
|
||||
data = length 621, hash CF741E7A
|
||||
sample 25:
|
||||
time = 800800
|
||||
flags = 0
|
||||
data = length 505, hash 1DB4894E
|
||||
sample 26:
|
||||
time = 967633
|
||||
flags = 0
|
||||
data = length 1268, hash C15348DC
|
||||
sample 27:
|
||||
time = 900900
|
||||
flags = 0
|
||||
data = length 880, hash C2DE85D0
|
||||
sample 28:
|
||||
time = 867533
|
||||
flags = 0
|
||||
data = length 530, hash C98BC6A8
|
||||
sample 29:
|
||||
time = 934266
|
||||
flags = 536870912
|
||||
data = length 568, hash 4FE5C8EA
|
||||
track 1:
|
||||
total output bytes = 9529
|
||||
sample count = 45
|
||||
format 0:
|
||||
peakBitrate = 200000
|
||||
id = 2
|
||||
sampleMimeType = audio/mp4a-latm
|
||||
codecs = mp4a.40.2
|
||||
maxInputSize = 294
|
||||
channelCount = 1
|
||||
sampleRate = 44100
|
||||
language = und
|
||||
metadata = entries=[TSSE: description=null: values=[Lavf56.1.0], xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=1000]
|
||||
initializationData:
|
||||
data = length 2, hash 5F7
|
||||
sample 0:
|
||||
time = 44000
|
||||
flags = 1
|
||||
data = length 23, hash 47DE9131
|
||||
sample 1:
|
||||
time = 67219
|
||||
flags = 1
|
||||
data = length 6, hash 31EC5206
|
||||
sample 2:
|
||||
time = 90439
|
||||
flags = 1
|
||||
data = length 148, hash 894A176B
|
||||
sample 3:
|
||||
time = 113659
|
||||
flags = 1
|
||||
data = length 189, hash CEF235A1
|
||||
sample 4:
|
||||
time = 136879
|
||||
flags = 1
|
||||
data = length 205, hash BBF5F7B0
|
||||
sample 5:
|
||||
time = 160099
|
||||
flags = 1
|
||||
data = length 210, hash F278B193
|
||||
sample 6:
|
||||
time = 183319
|
||||
flags = 1
|
||||
data = length 210, hash 82DA1589
|
||||
sample 7:
|
||||
time = 206539
|
||||
flags = 1
|
||||
data = length 207, hash 5BE231DF
|
||||
sample 8:
|
||||
time = 229759
|
||||
flags = 1
|
||||
data = length 225, hash 18819EE1
|
||||
sample 9:
|
||||
time = 252979
|
||||
flags = 1
|
||||
data = length 215, hash CA7FA67B
|
||||
sample 10:
|
||||
time = 276199
|
||||
flags = 1
|
||||
data = length 211, hash 581A1C18
|
||||
sample 11:
|
||||
time = 299419
|
||||
flags = 1
|
||||
data = length 216, hash ADB88187
|
||||
sample 12:
|
||||
time = 322639
|
||||
flags = 1
|
||||
data = length 229, hash 2E8BA4DC
|
||||
sample 13:
|
||||
time = 345859
|
||||
flags = 1
|
||||
data = length 232, hash 22F0C510
|
||||
sample 14:
|
||||
time = 369079
|
||||
flags = 1
|
||||
data = length 235, hash 867AD0DC
|
||||
sample 15:
|
||||
time = 392299
|
||||
flags = 1
|
||||
data = length 231, hash 84E823A8
|
||||
sample 16:
|
||||
time = 415519
|
||||
flags = 1
|
||||
data = length 226, hash 1BEF3A95
|
||||
sample 17:
|
||||
time = 438739
|
||||
flags = 1
|
||||
data = length 216, hash EAA345AE
|
||||
sample 18:
|
||||
time = 461959
|
||||
flags = 1
|
||||
data = length 229, hash 6957411F
|
||||
sample 19:
|
||||
time = 485179
|
||||
flags = 1
|
||||
data = length 219, hash 41275022
|
||||
sample 20:
|
||||
time = 508399
|
||||
flags = 1
|
||||
data = length 241, hash 6495DF96
|
||||
sample 21:
|
||||
time = 531619
|
||||
flags = 1
|
||||
data = length 228, hash 63D95906
|
||||
sample 22:
|
||||
time = 554839
|
||||
flags = 1
|
||||
data = length 238, hash 34F676F9
|
||||
sample 23:
|
||||
time = 578058
|
||||
flags = 1
|
||||
data = length 234, hash E5CBC045
|
||||
sample 24:
|
||||
time = 601278
|
||||
flags = 1
|
||||
data = length 231, hash 5FC43661
|
||||
sample 25:
|
||||
time = 624498
|
||||
flags = 1
|
||||
data = length 217, hash 682708ED
|
||||
sample 26:
|
||||
time = 647718
|
||||
flags = 1
|
||||
data = length 239, hash D43780FC
|
||||
sample 27:
|
||||
time = 670938
|
||||
flags = 1
|
||||
data = length 243, hash C5E17980
|
||||
sample 28:
|
||||
time = 694158
|
||||
flags = 1
|
||||
data = length 231, hash AC5837BA
|
||||
sample 29:
|
||||
time = 717378
|
||||
flags = 1
|
||||
data = length 230, hash 169EE895
|
||||
sample 30:
|
||||
time = 740598
|
||||
flags = 1
|
||||
data = length 238, hash C48FF3F1
|
||||
sample 31:
|
||||
time = 763818
|
||||
flags = 1
|
||||
data = length 225, hash 531E4599
|
||||
sample 32:
|
||||
time = 787038
|
||||
flags = 1
|
||||
data = length 232, hash CB3C6B8D
|
||||
sample 33:
|
||||
time = 810258
|
||||
flags = 1
|
||||
data = length 243, hash F8C94C7
|
||||
sample 34:
|
||||
time = 833478
|
||||
flags = 1
|
||||
data = length 232, hash A646A7D0
|
||||
sample 35:
|
||||
time = 856698
|
||||
flags = 1
|
||||
data = length 237, hash E8B787A5
|
||||
sample 36:
|
||||
time = 879918
|
||||
flags = 1
|
||||
data = length 228, hash 3FA7A29F
|
||||
sample 37:
|
||||
time = 903138
|
||||
flags = 1
|
||||
data = length 235, hash B9B33B0A
|
||||
sample 38:
|
||||
time = 926358
|
||||
flags = 1
|
||||
data = length 264, hash 71A4869E
|
||||
sample 39:
|
||||
time = 949578
|
||||
flags = 1
|
||||
data = length 257, hash D049B54C
|
||||
sample 40:
|
||||
time = 972798
|
||||
flags = 1
|
||||
data = length 227, hash 66757231
|
||||
sample 41:
|
||||
time = 996018
|
||||
flags = 1
|
||||
data = length 227, hash BD374F1B
|
||||
sample 42:
|
||||
time = 1019238
|
||||
flags = 1
|
||||
data = length 235, hash 999477F6
|
||||
sample 43:
|
||||
time = 1042458
|
||||
flags = 1
|
||||
data = length 229, hash FFF98DF0
|
||||
sample 44:
|
||||
time = 1065678
|
||||
flags = 536870913
|
||||
data = length 6, hash 31B22286
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,48 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
metadata = entries=[mdta: key=editable.tracks.offset, value=400332, mdta: key=editable.tracks.length, value=400628, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
@ -0,0 +1,91 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400276]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
roleFlags = [auxiliary]
|
||||
auxiliaryTrackType = original
|
||||
metadata = entries=[mdta: key=editable.tracks.map, value=track types = 0,1, mdta: key=editable.tracks.samples.location, value=0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
track 1:
|
||||
total output bytes = 280
|
||||
sample count = 5
|
||||
format 0:
|
||||
id = 2
|
||||
sampleMimeType = video/avc
|
||||
codecs = avc1.F4000A
|
||||
maxInputSize = 86
|
||||
maxNumReorderSamples = 2
|
||||
width = 12
|
||||
height = 10
|
||||
colorInfo:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
roleFlags = [auxiliary]
|
||||
auxiliaryTrackType = depth-linear
|
||||
metadata = entries=[mdta: key=editable.tracks.map, value=track types = 0,1, mdta: key=editable.tracks.samples.location, value=0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
data = length 9, hash FBADD682
|
||||
sample 0:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 1:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 2:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 3:
|
||||
time = 0
|
||||
flags = 1
|
||||
data = length 56, hash C4551A2E
|
||||
sample 4:
|
||||
time = 0
|
||||
flags = 536870913
|
||||
data = length 56, hash C4551A2E
|
||||
tracksEnded = true
|
Binary file not shown.
@ -21,6 +21,8 @@ track 0:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
roleFlags = [auxiliary]
|
||||
auxiliaryTrackType = original
|
||||
metadata = entries=[mdta: key=editable.tracks.map, value=track types = 0,1, mdta: key=editable.tracks.samples.location, value=0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
@ -60,6 +62,8 @@ track 1:
|
||||
colorRange = 1
|
||||
lumaBitdepth = 8
|
||||
chromaBitdepth = 8
|
||||
roleFlags = [auxiliary]
|
||||
auxiliaryTrackType = depth-linear
|
||||
metadata = entries=[mdta: key=editable.tracks.map, value=track types = 0,1, mdta: key=editable.tracks.samples.location, value=0, Mp4Timestamp: creation time=1000000, modification time=5000000, timescale=10000]
|
||||
initializationData:
|
||||
data = length 28, hash 410B510
|
||||
|
Loading…
x
Reference in New Issue
Block a user