Throw exception when B-frames are written to Mp4Muxer

Mp4Muxer does not support out of order B-frames. Currently it
silently writes out of order B-frames, producing an invalid file (with
negative sample durations).

Although `Mp4Extractor` is somehow able to process this invalid file and
`Exoplayer` is able to play it but that is unexpected.

The `sample.mp4` test file contains B frames. Other test files does not
contain `H264 video + AAC audio` format hence created a new test file by
running `sample.mp4` via `Transformer` after applying some effects.

PiperOrigin-RevId: 594016144
This commit is contained in:
sheenachhabra 2023-12-27 08:30:00 -08:00 committed by Copybara-Service
parent 0ab7bafa87
commit 1609928242
12 changed files with 490 additions and 454 deletions

View File

@ -46,7 +46,7 @@ import org.junit.runners.Parameterized.Parameters;
/** End to end instrumentation tests for {@link Mp4Muxer}. */
@RunWith(Parameterized.class)
public class Mp4MuxerEndToEndTest {
private static final String H264_MP4 = "sample.mp4";
private static final String H264_MP4 = "sample_no_bframes.mp4";
private static final String H265_HDR10_MP4 = "hdr10-720p.mp4";
private static final String H265_WITH_METADATA_TRACK_MP4 = "h265_with_metadata_track.mp4";
private static final String AV1_MP4 = "sample_av1.mp4";

View File

@ -242,6 +242,8 @@ public final class Mp4Muxer {
* <p>The samples are cached and are written in batches so the caller must not change/release the
* {@link ByteBuffer} and the {@link BufferInfo} after calling this method.
*
* <p>Note: Out of order B-frames are currently not supported.
*
* @param trackToken The {@link TrackToken} for which this sample is being written.
* @param byteBuffer The encoded sample.
* @param bufferInfo The {@link BufferInfo} related to this sample.

View File

@ -15,8 +15,11 @@
*/
package androidx.media3.muxer;
import static androidx.media3.common.util.Assertions.checkArgument;
import android.media.MediaCodec;
import android.media.MediaCodec.BufferInfo;
import androidx.media3.common.C;
import androidx.media3.common.Format;
import androidx.media3.common.MimeTypes;
import androidx.media3.muxer.Mp4Muxer.TrackToken;
@ -74,9 +77,10 @@ import java.util.List;
public final List<Integer> writtenChunkSampleCounts;
public final Deque<BufferInfo> pendingSamplesBufferInfo;
public final Deque<ByteBuffer> pendingSamplesByteBuffer;
public boolean hadKeyframe = false;
private long lastSamplePresentationTimeUs;
/** Creates an instance with {@code sortKey} set to 1. */
public Track(Format format) {
this(format, /* sortKey= */ 1);
@ -96,9 +100,13 @@ import java.util.List;
writtenChunkSampleCounts = new ArrayList<>();
pendingSamplesBufferInfo = new ArrayDeque<>();
pendingSamplesByteBuffer = new ArrayDeque<>();
lastSamplePresentationTimeUs = C.TIME_UNSET;
}
public void writeSampleData(ByteBuffer byteBuffer, BufferInfo bufferInfo) throws IOException {
checkArgument(
bufferInfo.presentationTimeUs > lastSamplePresentationTimeUs,
"Out of order B-frames are not supported");
// TODO: b/279931840 - Confirm whether muxer should throw when writing empty samples.
// Skip empty samples.
if (bufferInfo.size == 0 || byteBuffer.remaining() == 0) {
@ -109,12 +117,14 @@ import java.util.List;
hadKeyframe = true;
}
// The video track must start with a key frame.
if (!hadKeyframe && MimeTypes.isVideo(format.sampleMimeType)) {
return;
}
pendingSamplesBufferInfo.addLast(bufferInfo);
pendingSamplesByteBuffer.addLast(byteBuffer);
lastSamplePresentationTimeUs = bufferInfo.presentationTimeUs;
}
@Override

View File

@ -17,6 +17,7 @@ package androidx.media3.muxer;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
import static com.google.common.truth.Truth.assertThat;
import static org.junit.Assert.assertThrows;
import android.media.MediaCodec.BufferInfo;
import android.util.Pair;
@ -62,12 +63,10 @@ public class Mp4MuxerEndToEndTest {
String outputFilePath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L);
Pair<ByteBuffer, BufferInfo> track1Sample1 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
Pair<ByteBuffer, BufferInfo> track1Sample2 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 200L);
Pair<ByteBuffer, BufferInfo> track2Sample1 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
Pair<ByteBuffer, BufferInfo> track2Sample2 =
@ -104,12 +103,10 @@ public class Mp4MuxerEndToEndTest {
String outputFilePath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
mp4Muxer.setModificationTime(/* timestampMs= */ 500_000_000L);
Pair<ByteBuffer, BufferInfo> track1Sample1 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
Pair<ByteBuffer, BufferInfo> track1Sample2 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
Pair<ByteBuffer, BufferInfo> track2Sample1 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 100L);
Pair<ByteBuffer, BufferInfo> track2Sample2 =
@ -136,4 +133,27 @@ public class Mp4MuxerEndToEndTest {
fakeExtractorOutput,
MuxerTestUtil.getExpectedDumpFilePath("mp4_with_different_tracks_offset.mp4"));
}
@Test
public void writeSampleData_withOutOfOrderSampleTimestamps_throws() throws IOException {
String outputFilePath = temporaryFolder.newFile().getPath();
Mp4Muxer mp4Muxer = new Mp4Muxer.Builder(new FileOutputStream(outputFilePath)).build();
Pair<ByteBuffer, BufferInfo> track1Sample1 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 0L);
Pair<ByteBuffer, BufferInfo> track1Sample2 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 2000L);
Pair<ByteBuffer, BufferInfo> track1Sample3 =
MuxerTestUtil.getFakeSampleAndSampleInfo(/* presentationTimeUs= */ 1000L);
try {
TrackToken track1 = mp4Muxer.addTrack(/* sortKey= */ 0, FAKE_VIDEO_FORMAT);
mp4Muxer.writeSampleData(track1, track1Sample1.first, track1Sample1.second);
mp4Muxer.writeSampleData(track1, track1Sample2.first, track1Sample2.second);
assertThrows(
IllegalArgumentException.class,
() -> mp4Muxer.writeSampleData(track1, track1Sample3.first, track1Sample3.second));
} finally {
mp4Muxer.close();
}
}
}

View File

@ -7,149 +7,10 @@ seekMap:
getPosition(1065600) = [[timeUs=0, position=44]]
numberOfTracks = 2
track 0:
total output bytes = 89876
sample count = 30
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64001F
maxInputSize = 36722
width = 1080
height = 720
frameRate = 32.113037
colorInfo:
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000]
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 = 66722
flags = 0
data = length 5312, hash D45D3CA0
sample 2:
time = 33355
flags = 0
data = length 599, hash 1BE7812D
sample 3:
time = 200200
flags = 0
data = length 7735, hash 4490F110
sample 4:
time = 133455
flags = 0
data = length 987, hash 560B5036
sample 5:
time = 100100
flags = 0
data = length 673, hash ED7CD8C7
sample 6:
time = 166822
flags = 0
data = length 523, hash 3020DF50
sample 7:
time = 333655
flags = 0
data = length 6061, hash 736C72B2
sample 8:
time = 266922
flags = 0
data = length 992, hash FE132F23
sample 9:
time = 233555
flags = 0
data = length 623, hash 5B2C1816
sample 10:
time = 300300
flags = 0
data = length 421, hash 742E69C1
sample 11:
time = 433755
flags = 0
data = length 4899, hash F72F86A1
sample 12:
time = 400400
flags = 0
data = length 568, hash 519A8E50
sample 13:
time = 367022
flags = 0
data = length 620, hash 3990AA39
sample 14:
time = 567222
flags = 0
data = length 5450, hash F06EC4AA
sample 15:
time = 500500
flags = 0
data = length 1051, hash 92DFA63A
sample 16:
time = 467122
flags = 0
data = length 874, hash 69587FB4
sample 17:
time = 533855
flags = 0
data = length 781, hash 36BE495B
sample 18:
time = 700700
flags = 0
data = length 4725, hash AC0C8CD3
sample 19:
time = 633955
flags = 0
data = length 1022, hash 5D8BFF34
sample 20:
time = 600600
flags = 0
data = length 790, hash 99413A99
sample 21:
time = 667322
flags = 0
data = length 610, hash 5E129290
sample 22:
time = 834155
flags = 0
data = length 2751, hash 769974CB
sample 23:
time = 767422
flags = 0
data = length 745, hash B78A477A
sample 24:
time = 734055
flags = 0
data = length 621, hash CF741E7A
sample 25:
time = 800800
flags = 0
data = length 505, hash 1DB4894E
sample 26:
time = 967622
flags = 0
data = length 1268, hash C15348DC
sample 27:
time = 900900
flags = 0
data = length 880, hash C2DE85D0
sample 28:
time = 867522
flags = 0
data = length 530, hash C98BC6A8
sample 29:
time = 934255
flags = 536870912
data = length 568, hash 4FE5C8EA
track 1:
total output bytes = 9529
sample count = 45
format 0:
peakBitrate = 200000
id = 2
id = 1
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
maxInputSize = 294
@ -339,4 +200,145 @@ track 1:
time = 1065666
flags = 536870913
data = length 6, hash 31B22286
track 1:
total output bytes = 301392
sample count = 30
format 0:
id = 2
sampleMimeType = video/avc
codecs = avc1.640034
maxInputSize = 22910
width = 1080
height = 720
frameRate = 31.004547
colorInfo:
colorSpace = 1
colorRange = 2
colorTransfer = 3
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[Mp4Timestamp: creation time=2083344800, modification time=2083344800, timescale=10000]
initializationData:
data = length 23, hash 33E412EE
data = length 9, hash FBAFBC0C
sample 0:
time = 0
flags = 1
data = length 7744, hash DDF91733
sample 1:
time = 33355
flags = 0
data = length 1168, hash 89E48A20
sample 2:
time = 66722
flags = 0
data = length 960, hash D4AD9EF0
sample 3:
time = 100100
flags = 0
data = length 976, hash CD49C23C
sample 4:
time = 133455
flags = 0
data = length 1360, hash 337B78A9
sample 5:
time = 166822
flags = 0
data = length 2288, hash 5D5FD1C8
sample 6:
time = 200200
flags = 0
data = length 3856, hash 3D7DCD46
sample 7:
time = 233555
flags = 0
data = length 4048, hash 47C78814
sample 8:
time = 266922
flags = 0
data = length 6144, hash 8FD9AD7D
sample 9:
time = 300300
flags = 0
data = length 7632, hash 4245F848
sample 10:
time = 333655
flags = 0
data = length 9792, hash B2B9AB4B
sample 11:
time = 367022
flags = 0
data = length 14496, hash E0F2E0BA
sample 12:
time = 400400
flags = 0
data = length 17664, hash 3E3189E
sample 13:
time = 433755
flags = 0
data = length 5712, hash CA808ECF
sample 14:
time = 467122
flags = 0
data = length 9776, hash C875D1AA
sample 15:
time = 500500
flags = 0
data = length 17712, hash 69AE17D4
sample 16:
time = 533855
flags = 0
data = length 11440, hash 7370E78C
sample 17:
time = 567222
flags = 0
data = length 8544, hash 5A581986
sample 18:
time = 600600
flags = 0
data = length 19904, hash 98AB5C44
sample 19:
time = 633955
flags = 0
data = length 14352, hash 74B754E3
sample 20:
time = 667322
flags = 0
data = length 9568, hash 369746A6
sample 21:
time = 700700
flags = 0
data = length 12192, hash E0F8A71A
sample 22:
time = 734055
flags = 0
data = length 22880, hash 75E833BA
sample 23:
time = 767422
flags = 0
data = length 16832, hash E8BFCFE3
sample 24:
time = 800800
flags = 0
data = length 5120, hash E04AEF94
sample 25:
time = 834155
flags = 0
data = length 9888, hash 1166103E
sample 26:
time = 867522
flags = 0
data = length 17024, hash F9A96740
sample 27:
time = 900900
flags = 0
data = length 20864, hash DF9E88B8
sample 28:
time = 934255
flags = 0
data = length 7216, hash BE22BE2F
sample 29:
time = 967622
flags = 536870912
data = length 14240, hash E190BF31
tracksEnded = true

View File

@ -7,149 +7,150 @@ seekMap:
getPosition(1065600) = [[timeUs=0, position=44]]
numberOfTracks = 2
track 0:
total output bytes = 89876
total output bytes = 301392
sample count = 30
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64001F
maxInputSize = 36722
codecs = avc1.640034
maxInputSize = 22910
width = 1080
height = 720
frameRate = 32.113037
frameRate = 31.004547
colorInfo:
colorSpace = 1
colorRange = 2
colorTransfer = 3
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[mdta: key=com.android.capture.fps, value=60.0, xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, mdta: key=com.android.capture.fps, value=60.0, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 29, hash 4746B5D9
data = length 10, hash 7A0D0F2B
data = length 23, hash 33E412EE
data = length 9, hash FBAFBC0C
sample 0:
time = 0
flags = 1
data = length 36692, hash D216076E
data = length 7744, hash DDF91733
sample 1:
time = 66722
flags = 0
data = length 5312, hash D45D3CA0
sample 2:
time = 33355
flags = 0
data = length 599, hash 1BE7812D
sample 3:
time = 200200
data = length 1168, hash 89E48A20
sample 2:
time = 66722
flags = 0
data = length 7735, hash 4490F110
data = length 960, hash D4AD9EF0
sample 3:
time = 100100
flags = 0
data = length 976, hash CD49C23C
sample 4:
time = 133455
flags = 0
data = length 987, hash 560B5036
data = length 1360, hash 337B78A9
sample 5:
time = 100100
flags = 0
data = length 673, hash ED7CD8C7
sample 6:
time = 166822
flags = 0
data = length 523, hash 3020DF50
sample 7:
time = 333655
data = length 2288, hash 5D5FD1C8
sample 6:
time = 200200
flags = 0
data = length 6061, hash 736C72B2
data = length 3856, hash 3D7DCD46
sample 7:
time = 233555
flags = 0
data = length 4048, hash 47C78814
sample 8:
time = 266922
flags = 0
data = length 992, hash FE132F23
data = length 6144, hash 8FD9AD7D
sample 9:
time = 233555
flags = 0
data = length 623, hash 5B2C1816
sample 10:
time = 300300
flags = 0
data = length 421, hash 742E69C1
sample 11:
time = 433755
data = length 7632, hash 4245F848
sample 10:
time = 333655
flags = 0
data = length 4899, hash F72F86A1
data = length 9792, hash B2B9AB4B
sample 11:
time = 367022
flags = 0
data = length 14496, hash E0F2E0BA
sample 12:
time = 400400
flags = 0
data = length 568, hash 519A8E50
data = length 17664, hash 3E3189E
sample 13:
time = 367022
time = 433755
flags = 0
data = length 620, hash 3990AA39
data = length 5712, hash CA808ECF
sample 14:
time = 567222
time = 467122
flags = 0
data = length 5450, hash F06EC4AA
data = length 9776, hash C875D1AA
sample 15:
time = 500500
flags = 0
data = length 1051, hash 92DFA63A
data = length 17712, hash 69AE17D4
sample 16:
time = 467122
flags = 0
data = length 874, hash 69587FB4
sample 17:
time = 533855
flags = 0
data = length 781, hash 36BE495B
sample 18:
time = 700700
data = length 11440, hash 7370E78C
sample 17:
time = 567222
flags = 0
data = length 4725, hash AC0C8CD3
data = length 8544, hash 5A581986
sample 18:
time = 600600
flags = 0
data = length 19904, hash 98AB5C44
sample 19:
time = 633955
flags = 0
data = length 1022, hash 5D8BFF34
data = length 14352, hash 74B754E3
sample 20:
time = 600600
flags = 0
data = length 790, hash 99413A99
sample 21:
time = 667322
flags = 0
data = length 610, hash 5E129290
sample 22:
time = 834155
data = length 9568, hash 369746A6
sample 21:
time = 700700
flags = 0
data = length 2751, hash 769974CB
data = length 12192, hash E0F8A71A
sample 22:
time = 734055
flags = 0
data = length 22880, hash 75E833BA
sample 23:
time = 767422
flags = 0
data = length 745, hash B78A477A
data = length 16832, hash E8BFCFE3
sample 24:
time = 734055
flags = 0
data = length 621, hash CF741E7A
sample 25:
time = 800800
flags = 0
data = length 505, hash 1DB4894E
sample 26:
time = 967622
data = length 5120, hash E04AEF94
sample 25:
time = 834155
flags = 0
data = length 1268, hash C15348DC
data = length 9888, hash 1166103E
sample 26:
time = 867522
flags = 0
data = length 17024, hash F9A96740
sample 27:
time = 900900
flags = 0
data = length 880, hash C2DE85D0
data = length 20864, hash DF9E88B8
sample 28:
time = 867522
flags = 0
data = length 530, hash C98BC6A8
sample 29:
time = 934255
flags = 0
data = length 7216, hash BE22BE2F
sample 29:
time = 967622
flags = 536870912
data = length 568, hash 4FE5C8EA
data = length 14240, hash E190BF31
track 1:
total output bytes = 9529
sample count = 45
format 0:
peakBitrate = 200000
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
@ -157,7 +158,7 @@ track 1:
channelCount = 1
sampleRate = 44100
language = und
metadata = entries=[xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 2, hash 5F7
sample 0:

View File

@ -7,149 +7,150 @@ seekMap:
getPosition(1065600) = [[timeUs=0, position=44]]
numberOfTracks = 2
track 0:
total output bytes = 89876
total output bytes = 301392
sample count = 30
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64001F
maxInputSize = 36722
codecs = avc1.640034
maxInputSize = 22910
width = 1080
height = 720
frameRate = 32.113037
frameRate = 31.004547
colorInfo:
colorSpace = 1
colorRange = 2
colorTransfer = 3
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000]
initializationData:
data = length 29, hash 4746B5D9
data = length 10, hash 7A0D0F2B
data = length 23, hash 33E412EE
data = length 9, hash FBAFBC0C
sample 0:
time = 0
flags = 1
data = length 36692, hash D216076E
data = length 7744, hash DDF91733
sample 1:
time = 66722
flags = 0
data = length 5312, hash D45D3CA0
sample 2:
time = 33355
flags = 0
data = length 599, hash 1BE7812D
sample 3:
time = 200200
data = length 1168, hash 89E48A20
sample 2:
time = 66722
flags = 0
data = length 7735, hash 4490F110
data = length 960, hash D4AD9EF0
sample 3:
time = 100100
flags = 0
data = length 976, hash CD49C23C
sample 4:
time = 133455
flags = 0
data = length 987, hash 560B5036
data = length 1360, hash 337B78A9
sample 5:
time = 100100
flags = 0
data = length 673, hash ED7CD8C7
sample 6:
time = 166822
flags = 0
data = length 523, hash 3020DF50
sample 7:
time = 333655
data = length 2288, hash 5D5FD1C8
sample 6:
time = 200200
flags = 0
data = length 6061, hash 736C72B2
data = length 3856, hash 3D7DCD46
sample 7:
time = 233555
flags = 0
data = length 4048, hash 47C78814
sample 8:
time = 266922
flags = 0
data = length 992, hash FE132F23
data = length 6144, hash 8FD9AD7D
sample 9:
time = 233555
flags = 0
data = length 623, hash 5B2C1816
sample 10:
time = 300300
flags = 0
data = length 421, hash 742E69C1
sample 11:
time = 433755
data = length 7632, hash 4245F848
sample 10:
time = 333655
flags = 0
data = length 4899, hash F72F86A1
data = length 9792, hash B2B9AB4B
sample 11:
time = 367022
flags = 0
data = length 14496, hash E0F2E0BA
sample 12:
time = 400400
flags = 0
data = length 568, hash 519A8E50
data = length 17664, hash 3E3189E
sample 13:
time = 367022
time = 433755
flags = 0
data = length 620, hash 3990AA39
data = length 5712, hash CA808ECF
sample 14:
time = 567222
time = 467122
flags = 0
data = length 5450, hash F06EC4AA
data = length 9776, hash C875D1AA
sample 15:
time = 500500
flags = 0
data = length 1051, hash 92DFA63A
data = length 17712, hash 69AE17D4
sample 16:
time = 467122
flags = 0
data = length 874, hash 69587FB4
sample 17:
time = 533855
flags = 0
data = length 781, hash 36BE495B
sample 18:
time = 700700
data = length 11440, hash 7370E78C
sample 17:
time = 567222
flags = 0
data = length 4725, hash AC0C8CD3
data = length 8544, hash 5A581986
sample 18:
time = 600600
flags = 0
data = length 19904, hash 98AB5C44
sample 19:
time = 633955
flags = 0
data = length 1022, hash 5D8BFF34
data = length 14352, hash 74B754E3
sample 20:
time = 600600
flags = 0
data = length 790, hash 99413A99
sample 21:
time = 667322
flags = 0
data = length 610, hash 5E129290
sample 22:
time = 834155
data = length 9568, hash 369746A6
sample 21:
time = 700700
flags = 0
data = length 2751, hash 769974CB
data = length 12192, hash E0F8A71A
sample 22:
time = 734055
flags = 0
data = length 22880, hash 75E833BA
sample 23:
time = 767422
flags = 0
data = length 745, hash B78A477A
data = length 16832, hash E8BFCFE3
sample 24:
time = 734055
flags = 0
data = length 621, hash CF741E7A
sample 25:
time = 800800
flags = 0
data = length 505, hash 1DB4894E
sample 26:
time = 967622
data = length 5120, hash E04AEF94
sample 25:
time = 834155
flags = 0
data = length 1268, hash C15348DC
data = length 9888, hash 1166103E
sample 26:
time = 867522
flags = 0
data = length 17024, hash F9A96740
sample 27:
time = 900900
flags = 0
data = length 880, hash C2DE85D0
data = length 20864, hash DF9E88B8
sample 28:
time = 867522
flags = 0
data = length 530, hash C98BC6A8
sample 29:
time = 934255
flags = 0
data = length 7216, hash BE22BE2F
sample 29:
time = 967622
flags = 536870912
data = length 568, hash 4FE5C8EA
data = length 14240, hash E190BF31
track 1:
total output bytes = 9529
sample count = 45
format 0:
peakBitrate = 200000
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
@ -157,7 +158,7 @@ track 1:
channelCount = 1
sampleRate = 44100
language = und
metadata = entries=[xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=2000000000, modification time=2000000000, timescale=10000]
initializationData:
data = length 2, hash 5F7
sample 0:

View File

@ -7,149 +7,150 @@ seekMap:
getPosition(1065600) = [[timeUs=0, position=44]]
numberOfTracks = 2
track 0:
total output bytes = 89876
total output bytes = 301392
sample count = 30
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64001F
maxInputSize = 36722
codecs = avc1.640034
maxInputSize = 22910
width = 1080
height = 720
frameRate = 32.113037
frameRate = 31.004547
colorInfo:
colorSpace = 1
colorRange = 2
colorTransfer = 3
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[mdta: key=StringKey, value=StringValue, mdta: key=FloatKey, value=600.0, xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, mdta: key=StringKey, value=StringValue, mdta: key=FloatKey, value=600.0, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 29, hash 4746B5D9
data = length 10, hash 7A0D0F2B
data = length 23, hash 33E412EE
data = length 9, hash FBAFBC0C
sample 0:
time = 0
flags = 1
data = length 36692, hash D216076E
data = length 7744, hash DDF91733
sample 1:
time = 66722
flags = 0
data = length 5312, hash D45D3CA0
sample 2:
time = 33355
flags = 0
data = length 599, hash 1BE7812D
sample 3:
time = 200200
data = length 1168, hash 89E48A20
sample 2:
time = 66722
flags = 0
data = length 7735, hash 4490F110
data = length 960, hash D4AD9EF0
sample 3:
time = 100100
flags = 0
data = length 976, hash CD49C23C
sample 4:
time = 133455
flags = 0
data = length 987, hash 560B5036
data = length 1360, hash 337B78A9
sample 5:
time = 100100
flags = 0
data = length 673, hash ED7CD8C7
sample 6:
time = 166822
flags = 0
data = length 523, hash 3020DF50
sample 7:
time = 333655
data = length 2288, hash 5D5FD1C8
sample 6:
time = 200200
flags = 0
data = length 6061, hash 736C72B2
data = length 3856, hash 3D7DCD46
sample 7:
time = 233555
flags = 0
data = length 4048, hash 47C78814
sample 8:
time = 266922
flags = 0
data = length 992, hash FE132F23
data = length 6144, hash 8FD9AD7D
sample 9:
time = 233555
flags = 0
data = length 623, hash 5B2C1816
sample 10:
time = 300300
flags = 0
data = length 421, hash 742E69C1
sample 11:
time = 433755
data = length 7632, hash 4245F848
sample 10:
time = 333655
flags = 0
data = length 4899, hash F72F86A1
data = length 9792, hash B2B9AB4B
sample 11:
time = 367022
flags = 0
data = length 14496, hash E0F2E0BA
sample 12:
time = 400400
flags = 0
data = length 568, hash 519A8E50
data = length 17664, hash 3E3189E
sample 13:
time = 367022
time = 433755
flags = 0
data = length 620, hash 3990AA39
data = length 5712, hash CA808ECF
sample 14:
time = 567222
time = 467122
flags = 0
data = length 5450, hash F06EC4AA
data = length 9776, hash C875D1AA
sample 15:
time = 500500
flags = 0
data = length 1051, hash 92DFA63A
data = length 17712, hash 69AE17D4
sample 16:
time = 467122
flags = 0
data = length 874, hash 69587FB4
sample 17:
time = 533855
flags = 0
data = length 781, hash 36BE495B
sample 18:
time = 700700
data = length 11440, hash 7370E78C
sample 17:
time = 567222
flags = 0
data = length 4725, hash AC0C8CD3
data = length 8544, hash 5A581986
sample 18:
time = 600600
flags = 0
data = length 19904, hash 98AB5C44
sample 19:
time = 633955
flags = 0
data = length 1022, hash 5D8BFF34
data = length 14352, hash 74B754E3
sample 20:
time = 600600
flags = 0
data = length 790, hash 99413A99
sample 21:
time = 667322
flags = 0
data = length 610, hash 5E129290
sample 22:
time = 834155
data = length 9568, hash 369746A6
sample 21:
time = 700700
flags = 0
data = length 2751, hash 769974CB
data = length 12192, hash E0F8A71A
sample 22:
time = 734055
flags = 0
data = length 22880, hash 75E833BA
sample 23:
time = 767422
flags = 0
data = length 745, hash B78A477A
data = length 16832, hash E8BFCFE3
sample 24:
time = 734055
flags = 0
data = length 621, hash CF741E7A
sample 25:
time = 800800
flags = 0
data = length 505, hash 1DB4894E
sample 26:
time = 967622
data = length 5120, hash E04AEF94
sample 25:
time = 834155
flags = 0
data = length 1268, hash C15348DC
data = length 9888, hash 1166103E
sample 26:
time = 867522
flags = 0
data = length 17024, hash F9A96740
sample 27:
time = 900900
flags = 0
data = length 880, hash C2DE85D0
data = length 20864, hash DF9E88B8
sample 28:
time = 867522
flags = 0
data = length 530, hash C98BC6A8
sample 29:
time = 934255
flags = 0
data = length 7216, hash BE22BE2F
sample 29:
time = 967622
flags = 536870912
data = length 568, hash 4FE5C8EA
data = length 14240, hash E190BF31
track 1:
total output bytes = 9529
sample count = 45
format 0:
peakBitrate = 200000
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
@ -157,7 +158,7 @@ track 1:
channelCount = 1
sampleRate = 44100
language = und
metadata = entries=[mdta: key=StringKey, value=StringValue, mdta: key=FloatKey, value=600.0, xyz: latitude=40.68, longitude=-74.5, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, mdta: key=StringKey, value=StringValue, mdta: key=FloatKey, value=600.0, xyz: latitude=40.68, longitude=-74.4999, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 2, hash 5F7
sample 0:

View File

@ -7,149 +7,150 @@ seekMap:
getPosition(1065600) = [[timeUs=0, position=44]]
numberOfTracks = 2
track 0:
total output bytes = 89876
total output bytes = 301392
sample count = 30
format 0:
id = 1
sampleMimeType = video/avc
codecs = avc1.64001F
maxInputSize = 36722
codecs = avc1.640034
maxInputSize = 22910
width = 1080
height = 720
frameRate = 32.113037
frameRate = 31.004547
colorInfo:
colorSpace = 1
colorRange = 2
colorTransfer = 3
lumaBitdepth = 8
chromaBitdepth = 8
metadata = entries=[xyz: latitude=45.0, longitude=-90.0, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=45.0, longitude=-90.0, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 29, hash 4746B5D9
data = length 10, hash 7A0D0F2B
data = length 23, hash 33E412EE
data = length 9, hash FBAFBC0C
sample 0:
time = 0
flags = 1
data = length 36692, hash D216076E
data = length 7744, hash DDF91733
sample 1:
time = 66722
flags = 0
data = length 5312, hash D45D3CA0
sample 2:
time = 33355
flags = 0
data = length 599, hash 1BE7812D
sample 3:
time = 200200
data = length 1168, hash 89E48A20
sample 2:
time = 66722
flags = 0
data = length 7735, hash 4490F110
data = length 960, hash D4AD9EF0
sample 3:
time = 100100
flags = 0
data = length 976, hash CD49C23C
sample 4:
time = 133455
flags = 0
data = length 987, hash 560B5036
data = length 1360, hash 337B78A9
sample 5:
time = 100100
flags = 0
data = length 673, hash ED7CD8C7
sample 6:
time = 166822
flags = 0
data = length 523, hash 3020DF50
sample 7:
time = 333655
data = length 2288, hash 5D5FD1C8
sample 6:
time = 200200
flags = 0
data = length 6061, hash 736C72B2
data = length 3856, hash 3D7DCD46
sample 7:
time = 233555
flags = 0
data = length 4048, hash 47C78814
sample 8:
time = 266922
flags = 0
data = length 992, hash FE132F23
data = length 6144, hash 8FD9AD7D
sample 9:
time = 233555
flags = 0
data = length 623, hash 5B2C1816
sample 10:
time = 300300
flags = 0
data = length 421, hash 742E69C1
sample 11:
time = 433755
data = length 7632, hash 4245F848
sample 10:
time = 333655
flags = 0
data = length 4899, hash F72F86A1
data = length 9792, hash B2B9AB4B
sample 11:
time = 367022
flags = 0
data = length 14496, hash E0F2E0BA
sample 12:
time = 400400
flags = 0
data = length 568, hash 519A8E50
data = length 17664, hash 3E3189E
sample 13:
time = 367022
time = 433755
flags = 0
data = length 620, hash 3990AA39
data = length 5712, hash CA808ECF
sample 14:
time = 567222
time = 467122
flags = 0
data = length 5450, hash F06EC4AA
data = length 9776, hash C875D1AA
sample 15:
time = 500500
flags = 0
data = length 1051, hash 92DFA63A
data = length 17712, hash 69AE17D4
sample 16:
time = 467122
flags = 0
data = length 874, hash 69587FB4
sample 17:
time = 533855
flags = 0
data = length 781, hash 36BE495B
sample 18:
time = 700700
data = length 11440, hash 7370E78C
sample 17:
time = 567222
flags = 0
data = length 4725, hash AC0C8CD3
data = length 8544, hash 5A581986
sample 18:
time = 600600
flags = 0
data = length 19904, hash 98AB5C44
sample 19:
time = 633955
flags = 0
data = length 1022, hash 5D8BFF34
data = length 14352, hash 74B754E3
sample 20:
time = 600600
flags = 0
data = length 790, hash 99413A99
sample 21:
time = 667322
flags = 0
data = length 610, hash 5E129290
sample 22:
time = 834155
data = length 9568, hash 369746A6
sample 21:
time = 700700
flags = 0
data = length 2751, hash 769974CB
data = length 12192, hash E0F8A71A
sample 22:
time = 734055
flags = 0
data = length 22880, hash 75E833BA
sample 23:
time = 767422
flags = 0
data = length 745, hash B78A477A
data = length 16832, hash E8BFCFE3
sample 24:
time = 734055
flags = 0
data = length 621, hash CF741E7A
sample 25:
time = 800800
flags = 0
data = length 505, hash 1DB4894E
sample 26:
time = 967622
data = length 5120, hash E04AEF94
sample 25:
time = 834155
flags = 0
data = length 1268, hash C15348DC
data = length 9888, hash 1166103E
sample 26:
time = 867522
flags = 0
data = length 17024, hash F9A96740
sample 27:
time = 900900
flags = 0
data = length 880, hash C2DE85D0
data = length 20864, hash DF9E88B8
sample 28:
time = 867522
flags = 0
data = length 530, hash C98BC6A8
sample 29:
time = 934255
flags = 0
data = length 7216, hash BE22BE2F
sample 29:
time = 967622
flags = 536870912
data = length 568, hash 4FE5C8EA
data = length 14240, hash E190BF31
track 1:
total output bytes = 9529
sample count = 45
format 0:
peakBitrate = 200000
id = 2
sampleMimeType = audio/mp4a-latm
codecs = mp4a.40.2
@ -157,7 +158,7 @@ track 1:
channelCount = 1
sampleRate = 44100
language = und
metadata = entries=[xyz: latitude=45.0, longitude=-90.0, Mp4Timestamp: creation time=3547558895, modification time=3547558895, timescale=10000]
metadata = entries=[mdta: key=com.android.version, value=13, xyz: latitude=45.0, longitude=-90.0, Mp4Timestamp: creation time=3785416745, modification time=3785416745, timescale=10000]
initializationData:
data = length 2, hash 5F7
sample 0:

View File

@ -17,7 +17,6 @@ package androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_FORMAT;
import static androidx.media3.transformer.AndroidTestUtil.MP4_ASSET_URI_STRING;
import static org.junit.Assume.assumeTrue;
import android.content.Context;
@ -40,7 +39,7 @@ import org.junit.runners.Parameterized.Parameters;
@RunWith(Parameterized.class)
public class TransformerWithInAppMuxerEndToEndTest {
private static final String MP4_FILE_ASSET_DIRECTORY = "asset:///media/mp4/";
private static final String H264_MP4 = "sample.mp4";
private static final String H264_MP4 = "sample_no_bframes.mp4";
private static final String H265_MP4 = "h265_with_metadata_track.mp4";
@Parameters(name = "{0}")
@ -90,7 +89,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
ChannelMixingAudioProcessor channelMixingAudioProcessor = new ChannelMixingAudioProcessor();
channelMixingAudioProcessor.putChannelMixingMatrix(
ChannelMixingMatrix.create(/* inputChannelCount= */ 1, /* outputChannelCount= */ 2));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_ASSET_URI_STRING));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE_ASSET_DIRECTORY + H264_MP4));
EditedMediaItem editedMediaItem =
new EditedMediaItem.Builder(mediaItem)
.setEffects(

View File

@ -16,7 +16,6 @@
package androidx.media3.transformer;
import static androidx.media3.common.util.Assertions.checkNotNull;
import static androidx.media3.transformer.TestUtil.ASSET_URI_PREFIX;
import static androidx.media3.transformer.TestUtil.FILE_AUDIO_VIDEO;
import static com.google.common.truth.Truth.assertThat;
@ -44,8 +43,7 @@ import org.junit.runner.RunWith;
/** End-to-end test for {@link Transformer} with {@link InAppMuxer}. */
@RunWith(AndroidJUnit4.class)
public class TransformerWithInAppMuxerEndToEndTest {
private static final String XMP_SAMPLE_DATA = "media/xmp/sample_datetime_xmp.xmp";
private static final String MP4_FILE = "asset:///media/mp4/sample_no_bframes.mp4";
@Rule public final TemporaryFolder outputDir = new TemporaryFolder();
private final Context context = ApplicationProvider.getApplicationContext();
@ -70,7 +68,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
.setMuxerFactory(inAppMuxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE));
transformer.start(mediaItem, outputPath);
TransformerTestRunner.runLooper(transformer);
@ -89,7 +87,8 @@ public class TransformerWithInAppMuxerEndToEndTest {
@Test
public void transmux_withXmpData_completesSuccessfully() throws Exception {
byte[] xmpData = androidx.media3.test.utils.TestUtil.getByteArray(context, XMP_SAMPLE_DATA);
String xmpSampleData = "media/xmp/sample_datetime_xmp.xmp";
byte[] xmpData = androidx.media3.test.utils.TestUtil.getByteArray(context, xmpSampleData);
Muxer.Factory inAppMuxerFactory =
new InAppMuxer.Factory(
DefaultMuxer.Factory.DEFAULT_MAX_DELAY_BETWEEN_SAMPLES_MS,
@ -99,7 +98,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
.setMuxerFactory(inAppMuxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE));
transformer.start(mediaItem, outputPath);
ExportResult exportResult = TransformerTestRunner.runLooper(transformer);
@ -127,7 +126,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
.setMuxerFactory(inAppMuxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE));
transformer.start(mediaItem, outputPath);
TransformerTestRunner.runLooper(transformer);
@ -156,7 +155,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
.setMuxerFactory(inAppMuxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE));
transformer.start(mediaItem, outputPath);
TransformerTestRunner.runLooper(transformer);
@ -201,7 +200,7 @@ public class TransformerWithInAppMuxerEndToEndTest {
.setClock(new FakeClock(/* isAutoAdvancing= */ true))
.setMuxerFactory(inAppMuxerFactory)
.build();
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(ASSET_URI_PREFIX + FILE_AUDIO_VIDEO));
MediaItem mediaItem = MediaItem.fromUri(Uri.parse(MP4_FILE));
transformer.start(mediaItem, outputPath);
TransformerTestRunner.runLooper(transformer);