Write moov box at the start of the file if possible
This is done by reserving some space for moov box at the start of the file and writing it there if it fits. If it doesn't fit, then it is written at the end of the file. PiperOrigin-RevId: 643944698
This commit is contained in:
parent
4109e2edd9
commit
aeb8fd134b
@ -70,7 +70,7 @@ public class Mp4MuxerEndToEndNonParameterizedAndroidTest {
|
||||
// Muxer not closed.
|
||||
|
||||
// Audio sample written = 192 out of 195.
|
||||
// Video sample written = 94 out of 127.
|
||||
// Video sample written = 125 out of 127.
|
||||
// Output is still a valid MP4 file.
|
||||
FakeExtractorOutput fakeExtractorOutput =
|
||||
TestUtil.extractAllSamplesFromFilePath(new Mp4Extractor(), checkNotNull(outputPath));
|
||||
|
@ -95,6 +95,7 @@ public final class Mp4Muxer implements Muxer {
|
||||
private @LastFrameDurationBehavior int lastFrameDurationBehavior;
|
||||
@Nullable private AnnexBToAvccConverter annexBToAvccConverter;
|
||||
private boolean sampleCopyEnabled;
|
||||
private boolean attemptStreamableOutputEnabled;
|
||||
|
||||
/**
|
||||
* Creates a {@link Builder} instance with default values.
|
||||
@ -105,6 +106,7 @@ public final class Mp4Muxer implements Muxer {
|
||||
this.fileOutputStream = checkNotNull(fileOutputStream);
|
||||
lastFrameDurationBehavior = LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME;
|
||||
sampleCopyEnabled = true;
|
||||
attemptStreamableOutputEnabled = true;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -148,6 +150,21 @@ public final class Mp4Muxer implements Muxer {
|
||||
return this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets whether to attempt to write a file where the metadata is stored at the start, which can
|
||||
* make the file more efficient to read sequentially.
|
||||
*
|
||||
* <p>Setting to {@code true} does not guarantee a streamable MP4 output.
|
||||
*
|
||||
* <p>The default value is {@code true}.
|
||||
*/
|
||||
@CanIgnoreReturnValue
|
||||
public Mp4Muxer.Builder setAttemptStreamableOutputEnabled(
|
||||
boolean attemptStreamableOutputEnabled) {
|
||||
this.attemptStreamableOutputEnabled = attemptStreamableOutputEnabled;
|
||||
return this;
|
||||
}
|
||||
|
||||
/** Builds an {@link Mp4Muxer} instance. */
|
||||
public Mp4Muxer build() {
|
||||
MetadataCollector metadataCollector = new MetadataCollector();
|
||||
@ -158,7 +175,8 @@ public final class Mp4Muxer implements Muxer {
|
||||
fileOutputStream,
|
||||
moovStructure,
|
||||
annexBToAvccConverter == null ? AnnexBToAvccConverter.DEFAULT : annexBToAvccConverter,
|
||||
sampleCopyEnabled);
|
||||
sampleCopyEnabled,
|
||||
attemptStreamableOutputEnabled);
|
||||
|
||||
return new Mp4Muxer(mp4Writer, metadataCollector);
|
||||
}
|
||||
|
@ -40,6 +40,8 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
/** Writes all media samples into a single mdat box. */
|
||||
/* package */ final class Mp4Writer {
|
||||
private static final long INTERLEAVE_DURATION_US = 1_000_000L;
|
||||
private static final int DEFAULT_MOOV_BOX_SIZE_BYTES = 400_000;
|
||||
private static final String FREE_BOX_TYPE = "free";
|
||||
|
||||
private final FileOutputStream outputStream;
|
||||
private final FileChannel output;
|
||||
@ -49,6 +51,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
private final AtomicBoolean hasWrittenSamples;
|
||||
private final boolean sampleCopyEnabled;
|
||||
|
||||
// Stores location of the space reserved for the moov box at the beginning of the file (after ftyp
|
||||
// box)
|
||||
private long reservedMoovSpaceStart;
|
||||
private long reservedMoovSpaceEnd;
|
||||
private boolean canWriteMoovAtStart;
|
||||
private long mdatStart;
|
||||
private long mdatEnd;
|
||||
private long mdatDataEnd; // Always <= mdatEnd
|
||||
@ -65,17 +72,20 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* H.265 NAL units from the Annex-B format (using start codes to delineate NAL units) to the
|
||||
* AVCC format (which uses length prefixes).
|
||||
* @param sampleCopyEnabled Whether sample copying is enabled.
|
||||
* @param attemptStreamableOutputEnabled Whether to attempt to write a streamable output.
|
||||
*/
|
||||
public Mp4Writer(
|
||||
FileOutputStream outputStream,
|
||||
Mp4MoovStructure moovGenerator,
|
||||
AnnexBToAvccConverter annexBToAvccConverter,
|
||||
boolean sampleCopyEnabled) {
|
||||
boolean sampleCopyEnabled,
|
||||
boolean attemptStreamableOutputEnabled) {
|
||||
this.outputStream = outputStream;
|
||||
this.output = outputStream.getChannel();
|
||||
this.moovGenerator = moovGenerator;
|
||||
this.annexBToAvccConverter = annexBToAvccConverter;
|
||||
this.sampleCopyEnabled = sampleCopyEnabled;
|
||||
canWriteMoovAtStart = attemptStreamableOutputEnabled;
|
||||
tracks = new ArrayList<>();
|
||||
hasWrittenSamples = new AtomicBoolean(false);
|
||||
lastMoovWritten = Range.closed(0L, 0L);
|
||||
@ -115,9 +125,16 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
output.position(0L);
|
||||
output.write(Boxes.ftyp());
|
||||
|
||||
if (canWriteMoovAtStart) {
|
||||
// Reserve some space for moov box by adding a free box.
|
||||
reservedMoovSpaceStart = output.position();
|
||||
output.write(
|
||||
BoxUtils.wrapIntoBox(FREE_BOX_TYPE, ByteBuffer.allocate(DEFAULT_MOOV_BOX_SIZE_BYTES)));
|
||||
reservedMoovSpaceEnd = output.position();
|
||||
}
|
||||
|
||||
// Start with an empty mdat box.
|
||||
mdatStart = output.position();
|
||||
|
||||
ByteBuffer header = ByteBuffer.allocate(4 + 4 + 8);
|
||||
header.putInt(1); // 4 bytes, indicating a 64-bit length field
|
||||
header.put(Util.getUtf8Bytes("mdat")); // 4 bytes
|
||||
@ -127,7 +144,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
// The box includes only its type and length.
|
||||
mdatDataEnd = mdatStart + 16;
|
||||
mdatEnd = mdatDataEnd;
|
||||
mdatEnd = canWriteMoovAtStart ? Long.MAX_VALUE : mdatDataEnd;
|
||||
}
|
||||
|
||||
private ByteBuffer assembleCurrentMoovData() {
|
||||
@ -174,7 +191,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
// Write a free box to the end of the file, with the new moov box wrapped into it.
|
||||
output.position(newMoovBoxPosition);
|
||||
output.write(BoxUtils.wrapIntoBox("free", newMoovBoxData.duplicate()));
|
||||
output.write(BoxUtils.wrapIntoBox(FREE_BOX_TYPE, newMoovBoxData.duplicate()));
|
||||
|
||||
// The current state is:
|
||||
// | ftyp | mdat .. .. .. | previous moov | free (new moov)|
|
||||
@ -188,6 +205,35 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
Range.closed(newMoovBoxPosition, newMoovBoxPosition + newMoovBoxData.remaining());
|
||||
}
|
||||
|
||||
/**
|
||||
* Attempts to write moov box at the start (after the ftyp box). If this is not possible, the moov
|
||||
* box is written at the end of the file (after the mdat box).
|
||||
*/
|
||||
private void maybeWriteMoovAtStart() throws IOException {
|
||||
ByteBuffer moovBox = assembleCurrentMoovData();
|
||||
int moovBoxSize = moovBox.remaining();
|
||||
// Keep some space for free box to fill the remaining space.
|
||||
if (moovBox.remaining() + BOX_HEADER_SIZE <= reservedMoovSpaceEnd - reservedMoovSpaceStart) {
|
||||
output.position(reservedMoovSpaceStart);
|
||||
output.write(moovBox);
|
||||
// Write free box in the remaining space.
|
||||
int freeSpace = (int) (reservedMoovSpaceEnd - output.position() - BOX_HEADER_SIZE);
|
||||
output.write(BoxUtils.wrapIntoBox(FREE_BOX_TYPE, ByteBuffer.allocate(freeSpace)));
|
||||
} else {
|
||||
// Write moov at the end (after mdat).
|
||||
canWriteMoovAtStart = false;
|
||||
mdatEnd = mdatDataEnd;
|
||||
output.position(mdatEnd);
|
||||
output.write(moovBox);
|
||||
lastMoovWritten = Range.closed(mdatEnd, mdatEnd + moovBoxSize);
|
||||
// Replace previously written moov box (after ftyp box) with a free box.
|
||||
int freeSpace = (int) (reservedMoovSpaceEnd - reservedMoovSpaceStart - BOX_HEADER_SIZE);
|
||||
ByteBuffer freeBox = BoxUtils.wrapIntoBox(FREE_BOX_TYPE, ByteBuffer.allocate(freeSpace));
|
||||
output.write(freeBox, reservedMoovSpaceStart);
|
||||
}
|
||||
updateMdatSize(mdatDataEnd - mdatStart);
|
||||
}
|
||||
|
||||
/**
|
||||
* Writes the final moov box and trims extra space from the mdat box.
|
||||
*
|
||||
@ -196,6 +242,11 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
* @throws IOException If there is any error while writing data to the disk.
|
||||
*/
|
||||
private void writeMoovAndTrim() throws IOException {
|
||||
if (canWriteMoovAtStart) {
|
||||
maybeWriteMoovAtStart();
|
||||
return;
|
||||
}
|
||||
|
||||
// The current state is:
|
||||
// | ftyp | mdat .. .. .. (00 00 00) | moov |
|
||||
|
||||
@ -229,10 +280,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
ByteBuffer freeHeader = ByteBuffer.allocate(4 + 4);
|
||||
freeHeader.putInt((int) remainingLength);
|
||||
freeHeader.put((byte) 'f');
|
||||
freeHeader.put((byte) 'r');
|
||||
freeHeader.put((byte) 'e');
|
||||
freeHeader.put((byte) 'e');
|
||||
freeHeader.put(Util.getUtf8Bytes(FREE_BOX_TYPE));
|
||||
freeHeader.flip();
|
||||
output.write(freeHeader);
|
||||
|
||||
@ -307,11 +355,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
mdatDataEnd += output.write(currentSampleByteBuffer, mdatDataEnd);
|
||||
track.writtenSamples.add(currentSampleBufferInfo);
|
||||
} while (!track.pendingSamplesBufferInfo.isEmpty());
|
||||
|
||||
checkState(mdatDataEnd <= mdatEnd);
|
||||
}
|
||||
|
||||
private void maybeExtendMdatAndRewriteMoov(long additionalBytesNeeded) throws IOException {
|
||||
// The mdat box can be written till the end of the file.
|
||||
if (canWriteMoovAtStart) {
|
||||
return;
|
||||
}
|
||||
// If the required number of bytes doesn't fit in the gap between the actual data and the moov
|
||||
// box, extend the file and write out the moov box to the end again.
|
||||
if (mdatDataEnd + additionalBytesNeeded >= mdatEnd) {
|
||||
@ -332,6 +383,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
}
|
||||
|
||||
private void doInterleave() throws IOException {
|
||||
boolean newSamplesWritten = false;
|
||||
for (int i = 0; i < tracks.size(); i++) {
|
||||
Track track = tracks.get(i);
|
||||
// TODO: b/270583563 - Check if we need to consider the global timestamp instead.
|
||||
@ -341,10 +393,14 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
|
||||
if (lastSampleInfo.presentationTimeUs - firstSampleInfo.presentationTimeUs
|
||||
> INTERLEAVE_DURATION_US) {
|
||||
newSamplesWritten = true;
|
||||
flushPending(track);
|
||||
}
|
||||
}
|
||||
}
|
||||
if (newSamplesWritten && canWriteMoovAtStart) {
|
||||
maybeWriteMoovAtStart();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -300,4 +300,64 @@ public class Mp4MuxerEndToEndTest {
|
||||
DumpFileAsserts.assertOutput(
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("mp4_without_empty_track.mp4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeMp4File_withLargeNumberOfSamples_writesMoovBoxAtTheEndAndFreeBoxAtStart()
|
||||
throws Exception {
|
||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||
Mp4Muxer muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
|
||||
try {
|
||||
muxer.addMetadataEntry(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 1_000_000L,
|
||||
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||
TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT);
|
||||
for (int i = 0; i < 50_000; i++) {
|
||||
Pair<ByteBuffer, BufferInfo> sampleAndSampleInfo =
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ i);
|
||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||
}
|
||||
} finally {
|
||||
muxer.close();
|
||||
}
|
||||
|
||||
DumpableMp4Box dumpableBox =
|
||||
new DumpableMp4Box(ByteBuffer.wrap(TestUtil.getByteArrayFromFilePath(outputFilePath)));
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
dumpableBox,
|
||||
MuxerTestUtil.getExpectedDumpFilePath(
|
||||
"mp4_with_moov_at_the_end_and_free_box_at_start.mp4"));
|
||||
}
|
||||
|
||||
@Test
|
||||
public void writeMp4File_withAttemptStreamableMp4SetToFalse_writesMoovBoxAtTheEndAndNoFreeBox()
|
||||
throws Exception {
|
||||
String outputFilePath = temporaryFolder.newFile().getPath();
|
||||
Mp4Muxer muxer =
|
||||
new Mp4Muxer.Builder(new FileOutputStream(outputFilePath))
|
||||
.setAttemptStreamableOutputEnabled(false)
|
||||
.build();
|
||||
try {
|
||||
muxer.addMetadataEntry(
|
||||
new Mp4TimestampData(
|
||||
/* creationTimestampSeconds= */ 1_000_000L,
|
||||
/* modificationTimestampSeconds= */ 5_000_000L));
|
||||
TrackToken token = muxer.addTrack(FAKE_VIDEO_FORMAT);
|
||||
for (int i = 0; i < 1_000; i++) {
|
||||
Pair<ByteBuffer, BufferInfo> sampleAndSampleInfo =
|
||||
getFakeSampleAndSampleInfo(/* presentationTimeUs= */ i);
|
||||
muxer.writeSampleData(token, sampleAndSampleInfo.first, sampleAndSampleInfo.second);
|
||||
}
|
||||
} finally {
|
||||
muxer.close();
|
||||
}
|
||||
|
||||
DumpableMp4Box dumpableBox =
|
||||
new DumpableMp4Box(ByteBuffer.wrap(TestUtil.getByteArrayFromFilePath(outputFilePath)));
|
||||
DumpFileAsserts.assertOutput(
|
||||
context,
|
||||
dumpableBox,
|
||||
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_moov_at_the_end_and_no_free_box.mp4"));
|
||||
}
|
||||
}
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 3966600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=1000000, position=152546]]
|
||||
getPosition(1983300) = [[timeUs=1000000, position=152546], [timeUs=2000000, position=238309]]
|
||||
getPosition(3966600) = [[timeUs=3000000, position=353603]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=1000000, position=552554]]
|
||||
getPosition(1983300) = [[timeUs=1000000, position=552554], [timeUs=2000000, position=638317]]
|
||||
getPosition(3966600) = [[timeUs=3000000, position=753611]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 416333
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 3966600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=1000000, position=147439]]
|
||||
getPosition(1983300) = [[timeUs=1000000, position=147439], [timeUs=2000000, position=231666]]
|
||||
getPosition(3966600) = [[timeUs=3000000, position=343992]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=1000000, position=547447]]
|
||||
getPosition(1983300) = [[timeUs=1000000, position=547447], [timeUs=2000000, position=631674]]
|
||||
getPosition(3966600) = [[timeUs=3000000, position=744000]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 406132
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 66700
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(33350) = [[timeUs=0, position=44]]
|
||||
getPosition(66700) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(33350) = [[timeUs=0, position=400052]]
|
||||
getPosition(66700) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 3
|
||||
track 0:
|
||||
total output bytes = 387
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 4203200
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=1002944, position=1883462]]
|
||||
getPosition(2101600) = [[timeUs=2003555, position=3784641], [timeUs=3003433, position=4026908]]
|
||||
getPosition(4203200) = [[timeUs=4003266, position=6038533]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=1002944, position=2283470]]
|
||||
getPosition(2101600) = [[timeUs=2003555, position=4184649], [timeUs=3003433, position=4426916]]
|
||||
getPosition(4203200) = [[timeUs=4003266, position=6438541]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 7944083
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 3000
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=3000, position=100]]
|
||||
getPosition(1500) = [[timeUs=0, position=44], [timeUs=3000, position=100]]
|
||||
getPosition(3000) = [[timeUs=3000, position=100]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=3000, position=400108]]
|
||||
getPosition(1500) = [[timeUs=0, position=400052], [timeUs=3000, position=400108]]
|
||||
getPosition(3000) = [[timeUs=3000, position=400108]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 224
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 273900
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=273900, position=100]]
|
||||
getPosition(136950) = [[timeUs=0, position=44], [timeUs=273900, position=100]]
|
||||
getPosition(273900) = [[timeUs=273900, position=100]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=273900, position=400108]]
|
||||
getPosition(136950) = [[timeUs=0, position=400052], [timeUs=273900, position=400108]]
|
||||
getPosition(273900) = [[timeUs=273900, position=400108]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 224
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 200
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=100, position=100]]
|
||||
getPosition(100) = [[timeUs=100, position=100]]
|
||||
getPosition(200) = [[timeUs=100, position=100]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=100, position=400108]]
|
||||
getPosition(100) = [[timeUs=100, position=400108]]
|
||||
getPosition(200) = [[timeUs=100, position=400108]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 112
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -0,0 +1,35 @@
|
||||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
free (400008 bytes):
|
||||
Data = length 400000, hash BBC7B001
|
||||
mdat (2800016 bytes):
|
||||
Data = length 2800000, hash 7A1CC21
|
||||
moov (472634 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash CAE9466E
|
||||
trak (472518 bytes):
|
||||
tkhd (92 bytes):
|
||||
Data = length 84, hash 59BEBEA1
|
||||
mdia (472418 bytes):
|
||||
mdhd (32 bytes):
|
||||
Data = length 24, hash 58568E23
|
||||
hdlr (44 bytes):
|
||||
Data = length 36, hash A0852FF2
|
||||
minf (472334 bytes):
|
||||
vmhd (20 bytes):
|
||||
Data = length 12, hash EE830681
|
||||
dinf (36 bytes):
|
||||
Data = length 28, hash D535436B
|
||||
stbl (472270 bytes):
|
||||
stsd (166 bytes):
|
||||
Data = length 158, hash 11532063
|
||||
stts (72008 bytes):
|
||||
Data = length 72000, hash FA47C748
|
||||
stsz (200020 bytes):
|
||||
Data = length 200012, hash 719AE8EE
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 2BB02571
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE6662
|
||||
stss (200016 bytes):
|
||||
Data = length 200008, hash 8ABF61C3
|
@ -0,0 +1,33 @@
|
||||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
mdat (56016 bytes):
|
||||
Data = length 56000, hash F535891
|
||||
moov (10074 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash E6A54065
|
||||
trak (9958 bytes):
|
||||
tkhd (92 bytes):
|
||||
Data = length 84, hash CB9C1A18
|
||||
mdia (9858 bytes):
|
||||
mdhd (32 bytes):
|
||||
Data = length 24, hash 463A595A
|
||||
hdlr (44 bytes):
|
||||
Data = length 36, hash A0852FF2
|
||||
minf (9774 bytes):
|
||||
vmhd (20 bytes):
|
||||
Data = length 12, hash EE830681
|
||||
dinf (36 bytes):
|
||||
Data = length 28, hash D535436B
|
||||
stbl (9710 bytes):
|
||||
stsd (166 bytes):
|
||||
Data = length 158, hash 11532063
|
||||
stts (1448 bytes):
|
||||
Data = length 1440, hash 4C9792F5
|
||||
stsz (4020 bytes):
|
||||
Data = length 4012, hash 537BD986
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 932CC0C9
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE4D2E
|
||||
stss (4016 bytes):
|
||||
Data = length 4008, hash 729103FF
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 200
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=100, position=100]]
|
||||
getPosition(100) = [[timeUs=100, position=100]]
|
||||
getPosition(200) = [[timeUs=100, position=100]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=100, position=400108]]
|
||||
getPosition(100) = [[timeUs=100, position=400108]]
|
||||
getPosition(200) = [[timeUs=100, position=400108]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 112
|
||||
|
@ -1,7 +1,5 @@
|
||||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
mdat (72 bytes):
|
||||
Data = length 56, hash DB5662FB
|
||||
moov (873 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash 2613A5C
|
||||
@ -37,8 +35,12 @@ moov (873 bytes):
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 8F6E8285
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE4D2E
|
||||
Data = length 16, hash E4EE6662
|
||||
stss (20 bytes):
|
||||
Data = length 12, hash EE911E03
|
||||
uuid (2853 bytes):
|
||||
Data = length 2845, hash 52AF0F9D
|
||||
free (396282 bytes):
|
||||
Data = length 396274, hash 946025C1
|
||||
mdat (72 bytes):
|
||||
Data = length 56, hash DB5662FB
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 0
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 56
|
||||
|
@ -1,7 +1,5 @@
|
||||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
mdat (72 bytes):
|
||||
Data = length 56, hash DB5662FB
|
||||
moov (658 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash 2613A5C
|
||||
@ -28,8 +26,12 @@ moov (658 bytes):
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 8F6E8285
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE4D2E
|
||||
Data = length 16, hash E4EE6662
|
||||
stss (20 bytes):
|
||||
Data = length 12, hash EE911E03
|
||||
uuid (2853 bytes):
|
||||
Data = length 2845, hash 52AF0F9D
|
||||
free (396497 bytes):
|
||||
Data = length 396489, hash 429891F
|
||||
mdat (72 bytes):
|
||||
Data = length 56, hash DB5662FB
|
||||
|
@ -1,7 +1,5 @@
|
||||
ftyp (28 bytes):
|
||||
Data = length 20, hash EF896440
|
||||
mdat (128 bytes):
|
||||
Data = length 112, hash 1AAF8FF5
|
||||
moov (674 bytes):
|
||||
mvhd (108 bytes):
|
||||
Data = length 100, hash 105FA889
|
||||
@ -28,6 +26,10 @@ moov (674 bytes):
|
||||
stsc (28 bytes):
|
||||
Data = length 20, hash 8F7C9A06
|
||||
co64 (24 bytes):
|
||||
Data = length 16, hash E4EE4D2E
|
||||
Data = length 16, hash E4EE6662
|
||||
stss (24 bytes):
|
||||
Data = length 16, hash 7940D386
|
||||
free (399334 bytes):
|
||||
Data = length 399326, hash 3C185041
|
||||
mdat (128 bytes):
|
||||
Data = length 112, hash 1AAF8FF5
|
||||
|
@ -1,14 +1,14 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 4117500
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=1002944, position=1883462]]
|
||||
getPosition(2058750) = [[timeUs=2003555, position=3784641], [timeUs=3003433, position=4026908]]
|
||||
getPosition(4117500) = [[timeUs=3003433, position=4026908]]
|
||||
duration = 4137400
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=1002944, position=2283470]]
|
||||
getPosition(2068700) = [[timeUs=2003555, position=4184649], [timeUs=3003433, position=4426916]]
|
||||
getPosition(4137400) = [[timeUs=4003266, position=6438541]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 5911788
|
||||
sample count = 94
|
||||
total output bytes = 7822354
|
||||
sample count = 125
|
||||
format 0:
|
||||
id = 1
|
||||
sampleMimeType = video/hevc
|
||||
@ -17,7 +17,7 @@ track 0:
|
||||
maxNumReorderSamples = 0
|
||||
width = 1280
|
||||
height = 720
|
||||
frameRate = 30.28936
|
||||
frameRate = 30.21221
|
||||
colorInfo:
|
||||
colorSpace = 6
|
||||
colorRange = 2
|
||||
@ -401,8 +401,132 @@ track 0:
|
||||
data = length 54110, hash 7B27C656
|
||||
sample 93:
|
||||
time = 3103411
|
||||
flags = 536870912
|
||||
flags = 0
|
||||
data = length 68308, hash C7F4AE80
|
||||
sample 94:
|
||||
time = 3136744
|
||||
flags = 0
|
||||
data = length 67629, hash 48E625B6
|
||||
sample 95:
|
||||
time = 3170100
|
||||
flags = 0
|
||||
data = length 66968, hash D46F0E01
|
||||
sample 96:
|
||||
time = 3203400
|
||||
flags = 0
|
||||
data = length 53022, hash 91852F32
|
||||
sample 97:
|
||||
time = 3236722
|
||||
flags = 0
|
||||
data = length 66729, hash 12CA7617
|
||||
sample 98:
|
||||
time = 3270055
|
||||
flags = 0
|
||||
data = length 53556, hash 904B00CF
|
||||
sample 99:
|
||||
time = 3303377
|
||||
flags = 0
|
||||
data = length 63459, hash AB813676
|
||||
sample 100:
|
||||
time = 3336711
|
||||
flags = 0
|
||||
data = length 63637, hash 8B0750F6
|
||||
sample 101:
|
||||
time = 3370033
|
||||
flags = 0
|
||||
data = length 64700, hash 8922E5BE
|
||||
sample 102:
|
||||
time = 3403366
|
||||
flags = 0
|
||||
data = length 54680, hash 4F49EB3D
|
||||
sample 103:
|
||||
time = 3436700
|
||||
flags = 0
|
||||
data = length 62600, hash 9DF2F9F5
|
||||
sample 104:
|
||||
time = 3470022
|
||||
flags = 0
|
||||
data = length 69506, hash DB702311
|
||||
sample 105:
|
||||
time = 3503355
|
||||
flags = 0
|
||||
data = length 50277, hash 1034F0A6
|
||||
sample 106:
|
||||
time = 3536711
|
||||
flags = 0
|
||||
data = length 52100, hash 33745B51
|
||||
sample 107:
|
||||
time = 3570000
|
||||
flags = 0
|
||||
data = length 65067, hash F73FE2C7
|
||||
sample 108:
|
||||
time = 3603333
|
||||
flags = 0
|
||||
data = length 68940, hash 4331DA16
|
||||
sample 109:
|
||||
time = 3636666
|
||||
flags = 0
|
||||
data = length 55215, hash 68087A40
|
||||
sample 110:
|
||||
time = 3670000
|
||||
flags = 0
|
||||
data = length 56090, hash 2F483911
|
||||
sample 111:
|
||||
time = 3703322
|
||||
flags = 0
|
||||
data = length 58356, hash D7D190C6
|
||||
sample 112:
|
||||
time = 3736644
|
||||
flags = 0
|
||||
data = length 57368, hash 2F6B7918
|
||||
sample 113:
|
||||
time = 3769977
|
||||
flags = 0
|
||||
data = length 56591, hash 19B696D2
|
||||
sample 114:
|
||||
time = 3803300
|
||||
flags = 0
|
||||
data = length 54748, hash 7E0CE70E
|
||||
sample 115:
|
||||
time = 3836622
|
||||
flags = 0
|
||||
data = length 73133, hash CFA46EE4
|
||||
sample 116:
|
||||
time = 3869955
|
||||
flags = 0
|
||||
data = length 52577, hash 5E174B5
|
||||
sample 117:
|
||||
time = 3903300
|
||||
flags = 0
|
||||
data = length 74756, hash 5A571060
|
||||
sample 118:
|
||||
time = 3936611
|
||||
flags = 0
|
||||
data = length 67171, hash 6F13FB2C
|
||||
sample 119:
|
||||
time = 3969933
|
||||
flags = 0
|
||||
data = length 42130, hash DAE94DB2
|
||||
sample 120:
|
||||
time = 4003266
|
||||
flags = 1
|
||||
data = length 120199, hash 32DEA792
|
||||
sample 121:
|
||||
time = 4036600
|
||||
flags = 0
|
||||
data = length 51028, hash FC7AF64F
|
||||
sample 122:
|
||||
time = 4069911
|
||||
flags = 0
|
||||
data = length 51879, hash 74852E0E
|
||||
sample 123:
|
||||
time = 4103244
|
||||
flags = 0
|
||||
data = length 51443, hash B735512A
|
||||
sample 124:
|
||||
time = 4137444
|
||||
flags = 536870912
|
||||
data = length 65012, hash DB29A2CD
|
||||
track 1:
|
||||
total output bytes = 131233
|
||||
sample count = 192
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1064600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(532300) = [[timeUs=0, position=44]]
|
||||
getPosition(1064600) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(532300) = [[timeUs=0, position=400052]]
|
||||
getPosition(1064600) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 69084
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1065600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(532800) = [[timeUs=0, position=44]]
|
||||
getPosition(1065600) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(532800) = [[timeUs=0, position=400052]]
|
||||
getPosition(1065600) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 9529
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 1065600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44]]
|
||||
getPosition(532800) = [[timeUs=0, position=44]]
|
||||
getPosition(1065600) = [[timeUs=0, position=44]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052]]
|
||||
getPosition(532800) = [[timeUs=0, position=400052]]
|
||||
getPosition(1065600) = [[timeUs=0, position=400052]]
|
||||
numberOfTracks = 2
|
||||
track 0:
|
||||
total output bytes = 301222
|
||||
|
@ -1,10 +1,10 @@
|
||||
seekMap:
|
||||
isSeekable = true
|
||||
duration = 966600
|
||||
getPosition(0) = [[timeUs=0, position=44]]
|
||||
getPosition(1) = [[timeUs=0, position=44], [timeUs=333333, position=16035]]
|
||||
getPosition(483300) = [[timeUs=333333, position=16035], [timeUs=666666, position=28785]]
|
||||
getPosition(966600) = [[timeUs=666666, position=28785]]
|
||||
getPosition(0) = [[timeUs=0, position=400052]]
|
||||
getPosition(1) = [[timeUs=0, position=400052], [timeUs=333333, position=416043]]
|
||||
getPosition(483300) = [[timeUs=333333, position=416043], [timeUs=666666, position=428793]]
|
||||
getPosition(966600) = [[timeUs=666666, position=428793]]
|
||||
numberOfTracks = 1
|
||||
track 0:
|
||||
total output bytes = 41647
|
||||
|
Loading…
x
Reference in New Issue
Block a user