mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Create muxer specific BufferInfo
class
Muxer does not use `offset` field, hence not added. PiperOrigin-RevId: 728625538
This commit is contained in:
parent
1461e9e93a
commit
462533219d
@ -20,6 +20,8 @@
|
||||
* DRM:
|
||||
* Effect:
|
||||
* Muxers:
|
||||
* `writeSampleData()` API now uses muxer specific `BufferInfo` class
|
||||
instead of `MediaCodec.BufferInfo`.
|
||||
* IMA extension:
|
||||
* Session:
|
||||
* Make `MediaSession.setSessionActivity(PendingIntent)` accept null
|
||||
|
@ -3478,6 +3478,20 @@ public final class Util {
|
||||
}
|
||||
}
|
||||
|
||||
/** Returns {@link C.BufferFlags} corresponding to {@link MediaCodec} flags. */
|
||||
@UnstableApi
|
||||
public static @C.BufferFlags int getBufferFlagsFromMediaCodecFlags(int mediaCodecFlags) {
|
||||
@C.BufferFlags int flags = 0;
|
||||
if ((mediaCodecFlags & MediaCodec.BUFFER_FLAG_KEY_FRAME) == MediaCodec.BUFFER_FLAG_KEY_FRAME) {
|
||||
flags |= C.BUFFER_FLAG_KEY_FRAME;
|
||||
}
|
||||
if ((mediaCodecFlags & MediaCodec.BUFFER_FLAG_END_OF_STREAM)
|
||||
== MediaCodec.BUFFER_FLAG_END_OF_STREAM) {
|
||||
flags |= C.BUFFER_FLAG_END_OF_STREAM;
|
||||
}
|
||||
return flags;
|
||||
}
|
||||
|
||||
@UnstableApi
|
||||
public static boolean isFrameDropAllowedOnSurfaceInput(Context context) {
|
||||
// Prior to API 29, decoders may drop frames to keep their output surface from growing out of
|
||||
|
@ -24,8 +24,6 @@ import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
import static java.nio.charset.StandardCharsets.UTF_8;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.media.MediaCodecInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.annotation.Nullable;
|
||||
@ -1045,7 +1043,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
}
|
||||
|
||||
/** Returns the stsz (sample size) box. */
|
||||
public static ByteBuffer stsz(List<MediaCodec.BufferInfo> writtenSamples) {
|
||||
public static ByteBuffer stsz(List<BufferInfo> writtenSamples) {
|
||||
ByteBuffer contents = ByteBuffer.allocate(writtenSamples.size() * 4 + MAX_FIXED_LEAF_BOX_SIZE);
|
||||
|
||||
contents.putInt(0x0); // version and flags
|
||||
@ -1133,7 +1131,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
}
|
||||
|
||||
/** Returns the stss (sync sample) box. */
|
||||
public static ByteBuffer stss(List<MediaCodec.BufferInfo> writtenSamples) {
|
||||
public static ByteBuffer stss(List<BufferInfo> writtenSamples) {
|
||||
ByteBuffer contents = ByteBuffer.allocate(writtenSamples.size() * 4 + MAX_FIXED_LEAF_BOX_SIZE);
|
||||
|
||||
contents.putInt(0x0); // version and flags
|
||||
@ -1146,8 +1144,8 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
int currentSampleNumber = 1;
|
||||
int totalKeyFrames = 0;
|
||||
for (int i = 0; i < writtenSamples.size(); i++) {
|
||||
MediaCodec.BufferInfo info = writtenSamples.get(i);
|
||||
if ((info.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) > 0) {
|
||||
BufferInfo info = writtenSamples.get(i);
|
||||
if ((info.flags & C.BUFFER_FLAG_KEY_FRAME) > 0) {
|
||||
contents.putInt(currentSampleNumber);
|
||||
totalKeyFrames++;
|
||||
}
|
||||
@ -1258,7 +1256,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
contents.putInt(currentSampleMetadata.durationVu); // An unsigned int(32)
|
||||
contents.putInt(currentSampleMetadata.size); // An unsigned int(32)
|
||||
contents.putInt(
|
||||
(currentSampleMetadata.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) != 0
|
||||
(currentSampleMetadata.flags & C.BUFFER_FLAG_KEY_FRAME) != 0
|
||||
? TRUN_BOX_SYNC_SAMPLE_FLAGS
|
||||
: TRUN_BOX_NON_SYNC_SAMPLE_FLAGS);
|
||||
if (hasBFrame) {
|
||||
|
@ -0,0 +1,46 @@
|
||||
/*
|
||||
* Copyright 2025 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* https://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package androidx.media3.muxer;
|
||||
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import java.nio.ByteBuffer;
|
||||
|
||||
/** Contains metadata of a sample {@link ByteBuffer}. */
|
||||
@UnstableApi
|
||||
public final class BufferInfo {
|
||||
/** The presentation timestamp of sample (in microseconds). */
|
||||
public final long presentationTimeUs;
|
||||
|
||||
/** The amount of data (in bytes) in the buffer. */
|
||||
public final int size;
|
||||
|
||||
/** The buffer flags, which should be a combination of the {@code C.BUFFER_FLAG_*}. */
|
||||
public final @C.BufferFlags int flags;
|
||||
|
||||
/**
|
||||
* Creates an instance.
|
||||
*
|
||||
* @param presentationTimeUs The presentation timestamp of sample (in microseconds).
|
||||
* @param size The amount of data (in bytes) in the buffer.
|
||||
* @param flags The buffer flags, which should be a combination of the {@code C.BUFFER_FLAG_*}.
|
||||
*/
|
||||
public BufferInfo(long presentationTimeUs, int size, @C.BufferFlags int flags) {
|
||||
this.presentationTimeUs = presentationTimeUs;
|
||||
this.size = size;
|
||||
this.flags = flags;
|
||||
}
|
||||
}
|
@ -18,7 +18,6 @@ package androidx.media3.muxer;
|
||||
import static androidx.media3.common.util.Assertions.checkArgument;
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.util.SparseArray;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Metadata;
|
||||
|
@ -28,8 +28,7 @@ import static androidx.media3.muxer.MuxerUtil.UNSIGNED_INT_MAX_VALUE;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
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.common.util.Util;
|
||||
@ -164,7 +163,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
return track;
|
||||
}
|
||||
|
||||
public void writeSampleData(Track track, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo)
|
||||
public void writeSampleData(Track track, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||
throws IOException {
|
||||
if (!headerCreated) {
|
||||
createHeader();
|
||||
@ -250,15 +249,14 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
tracks, metadataCollector, /* isFragmentedMp4= */ true, lastSampleDurationBehavior));
|
||||
}
|
||||
|
||||
private boolean shouldFlushPendingSamples(
|
||||
Track track, MediaCodec.BufferInfo nextSampleBufferInfo) {
|
||||
private boolean shouldFlushPendingSamples(Track track, BufferInfo nextSampleBufferInfo) {
|
||||
// If video track is present then fragment will be created based on group of pictures and
|
||||
// track's duration so far.
|
||||
if (videoTrack != null) {
|
||||
// Video samples can be written only when complete group of pictures are present.
|
||||
if (track.equals(videoTrack)
|
||||
&& track.hadKeyframe
|
||||
&& ((nextSampleBufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) > 0)) {
|
||||
&& ((nextSampleBufferInfo.flags & C.BUFFER_FLAG_KEY_FRAME) > 0)) {
|
||||
BufferInfo firstPendingSample = checkNotNull(track.pendingSamplesBufferInfo.peekFirst());
|
||||
BufferInfo lastPendingSample = checkNotNull(track.pendingSamplesBufferInfo.peekLast());
|
||||
return lastPendingSample.presentationTimeUs - firstPendingSample.presentationTimeUs
|
||||
@ -353,10 +351,10 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
annexBToAvccConverter.process(currentSampleByteBuffer, linearByteBufferAllocator);
|
||||
pendingSamplesByteBuffer.add(currentSampleByteBuffer);
|
||||
BufferInfo currentSampleBufferInfo = track.pendingSamplesBufferInfo.removeFirst();
|
||||
currentSampleBufferInfo.set(
|
||||
currentSampleByteBuffer.position(),
|
||||
currentSampleByteBuffer.remaining(),
|
||||
currentSampleBufferInfo =
|
||||
new BufferInfo(
|
||||
currentSampleBufferInfo.presentationTimeUs,
|
||||
currentSampleByteBuffer.remaining(),
|
||||
currentSampleBufferInfo.flags);
|
||||
pendingSamplesBufferInfoBuilder.add(currentSampleBufferInfo);
|
||||
}
|
||||
|
@ -27,8 +27,6 @@ import static androidx.media3.muxer.MuxerUtil.isMetadataSupported;
|
||||
import static androidx.media3.muxer.MuxerUtil.populateAuxiliaryTracksMetadata;
|
||||
import static java.lang.annotation.ElementType.TYPE_USE;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.annotation.IntDef;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
@ -160,19 +158,19 @@ public final class Mp4Muxer implements AutoCloseable {
|
||||
public static final int LAST_SAMPLE_DURATION_BEHAVIOR_SET_TO_ZERO = 0;
|
||||
|
||||
/**
|
||||
* Use the {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM end of stream sample} to set the duration
|
||||
* of the last sample.
|
||||
* Use the {@link C#BUFFER_FLAG_END_OF_STREAM end of stream sample} to set the duration of the
|
||||
* last sample.
|
||||
*
|
||||
* <p>After {@linkplain #writeSampleData writing} all the samples for a track, the app must
|
||||
* {@linkplain #writeSampleData write} an empty sample with flag {@link
|
||||
* MediaCodec#BUFFER_FLAG_END_OF_STREAM}. The timestamp of this sample should be equal to the
|
||||
* desired track duration.
|
||||
* C#BUFFER_FLAG_END_OF_STREAM}. The timestamp of this sample should be equal to the desired track
|
||||
* duration.
|
||||
*
|
||||
* <p>Once a sample with flag {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} is {@linkplain
|
||||
* #writeSampleData written}, no more samples can be written for that track.
|
||||
* <p>Once a sample with flag {@link C#BUFFER_FLAG_END_OF_STREAM} is {@linkplain #writeSampleData
|
||||
* written}, no more samples can be written for that track.
|
||||
*
|
||||
* <p>If no explicit {@link MediaCodec#BUFFER_FLAG_END_OF_STREAM} sample is passed, then the
|
||||
* duration of the last sample will be same as that of the sample before that.
|
||||
* <p>If no explicit {@link C#BUFFER_FLAG_END_OF_STREAM} sample is passed, then the duration of
|
||||
* the last sample will be same as that of the sample before that.
|
||||
*/
|
||||
public static final int
|
||||
LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS = 1;
|
||||
|
@ -27,7 +27,6 @@ import static androidx.media3.muxer.MuxerUtil.populateAuxiliaryTracksMetadata;
|
||||
import static java.lang.Math.max;
|
||||
import static java.lang.Math.min;
|
||||
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.container.MdtaMetadataEntry;
|
||||
@ -463,10 +462,10 @@ import java.util.concurrent.atomic.AtomicBoolean;
|
||||
if (doesSampleContainAnnexBNalUnits(checkNotNull(track.format.sampleMimeType))) {
|
||||
currentSampleByteBuffer =
|
||||
annexBToAvccConverter.process(currentSampleByteBuffer, linearByteBufferAllocator);
|
||||
currentSampleBufferInfo.set(
|
||||
currentSampleByteBuffer.position(),
|
||||
currentSampleByteBuffer.remaining(),
|
||||
currentSampleBufferInfo =
|
||||
new BufferInfo(
|
||||
currentSampleBufferInfo.presentationTimeUs,
|
||||
currentSampleByteBuffer.remaining(),
|
||||
currentSampleBufferInfo.flags);
|
||||
}
|
||||
|
||||
|
@ -15,10 +15,12 @@
|
||||
*/
|
||||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.common.util.Util.getBufferFlagsFromMediaCodecFlags;
|
||||
import static androidx.media3.container.MdtaMetadataEntry.AUXILIARY_TRACKS_SAMPLES_INTERLEAVED;
|
||||
import static androidx.media3.container.MdtaMetadataEntry.AUXILIARY_TRACKS_SAMPLES_NOT_INTERLEAVED;
|
||||
import static androidx.media3.container.MdtaMetadataEntry.TYPE_INDICATOR_8_BIT_UNSIGNED_INT;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.Metadata;
|
||||
@ -50,6 +52,15 @@ public final class MuxerUtil {
|
||||
|| metadata instanceof XmpData;
|
||||
}
|
||||
|
||||
/** Returns {@link BufferInfo} corresponding to the {@link MediaCodec.BufferInfo}. */
|
||||
public static BufferInfo getMuxerBufferInfoFromMediaCodecBufferInfo(
|
||||
MediaCodec.BufferInfo mediaCodecBufferInfo) {
|
||||
return new BufferInfo(
|
||||
mediaCodecBufferInfo.presentationTimeUs,
|
||||
mediaCodecBufferInfo.size,
|
||||
getBufferFlagsFromMediaCodecFlags(mediaCodecBufferInfo.flags));
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether the given {@linkplain Format track format} is an auxiliary track.
|
||||
*
|
||||
|
@ -17,8 +17,6 @@ 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;
|
||||
@ -76,13 +74,13 @@ import java.util.List;
|
||||
+ " MediaCodec.BUFFER_FLAG_END_OF_STREAM flag");
|
||||
// Skip empty samples.
|
||||
if (bufferInfo.size == 0 || byteBuffer.remaining() == 0) {
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
if ((bufferInfo.flags & C.BUFFER_FLAG_END_OF_STREAM) != 0) {
|
||||
endOfStreamTimestampUs = bufferInfo.presentationTimeUs;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if ((bufferInfo.flags & MediaCodec.BUFFER_FLAG_KEY_FRAME) > 0) {
|
||||
if ((bufferInfo.flags & C.BUFFER_FLAG_KEY_FRAME) > 0) {
|
||||
hadKeyframe = true;
|
||||
}
|
||||
|
||||
@ -100,12 +98,9 @@ import java.util.List;
|
||||
}
|
||||
|
||||
// Always copy the buffer info as it is retained until the track is finalized.
|
||||
BufferInfo bufferInfoToAdd = new BufferInfo();
|
||||
bufferInfoToAdd.set(
|
||||
/* newOffset= */ byteBufferToAdd.position(),
|
||||
/* newSize= */ byteBufferToAdd.remaining(),
|
||||
bufferInfo.presentationTimeUs,
|
||||
bufferInfo.flags);
|
||||
BufferInfo bufferInfoToAdd =
|
||||
new BufferInfo(
|
||||
bufferInfo.presentationTimeUs, byteBufferToAdd.remaining(), bufferInfo.flags);
|
||||
|
||||
pendingSamplesBufferInfo.addLast(bufferInfoToAdd);
|
||||
pendingSamplesByteBuffer.addLast(byteBufferToAdd);
|
||||
|
@ -517,8 +517,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_singleSampleAtZeroTimestamp_returnsSampleLengthEqualsZero() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L);
|
||||
List<BufferInfo> sampleBufferInfos = createBufferInfoListWithSamplePresentationTimestamps(0L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
@ -533,7 +532,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_singleSampleAtNonZeroTimestamp_returnsSampleLengthEqualsZero() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(5_000L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
@ -549,7 +548,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_differentSampleDurations_lastFrameDurationShort_returnsLastSampleOfZeroDuration() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 30_000L, 80_000L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
@ -565,7 +564,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_differentSampleDurations_lastFrameDurationDuplicate_returnsLastSampleOfDuplicateDuration() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 30_000L, 80_000L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
@ -581,7 +580,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_withOutOfOrderSampleTimestamps_returnsExpectedDurations() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 10_000L, 1_000L, 2_000L, 11_000L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
@ -597,7 +596,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void
|
||||
convertPresentationTimestampsToDurationsVu_withLastSampleDurationBehaviorUsingEndOfStreamFlag_returnsExpectedDurations() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 1_000L, 2_000L, 3_000L, 4_000L);
|
||||
|
||||
List<Integer> durationsVu =
|
||||
@ -652,8 +651,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createCttsBox_withSingleSampleTimestamp_returnsEmptyBox() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(400);
|
||||
List<BufferInfo> sampleBufferInfos = createBufferInfoListWithSamplePresentationTimestamps(400);
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
@ -669,7 +667,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createCttsBox_withNoBframesSampleTimestamps_returnsEmptyBox() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 1000L, 2000L);
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
@ -686,7 +684,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createCttsBox_withBFramesSampleTimestamps_matchesExpected() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(
|
||||
0, 400, 200, 100, 300, 800, 600, 500, 700);
|
||||
|
||||
@ -706,7 +704,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createCttsBox_withLargeSampleTimestamps_matchesExpected() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
List<BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(
|
||||
23698215060L, 23698248252L, 23698347988L, 23698488968L, 23698547416L);
|
||||
|
||||
@ -724,8 +722,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createStszBox_matchesExpected() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSampleSizes(100, 200, 150, 200);
|
||||
List<BufferInfo> sampleBufferInfos = createBufferInfoListWithSampleSizes(100, 200, 150, 200);
|
||||
|
||||
ByteBuffer stszBox = Boxes.stsz(sampleBufferInfos);
|
||||
|
||||
@ -780,7 +777,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createStssBox_matchesExpected() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos = createBufferInfoListWithSomeKeyFrames();
|
||||
List<BufferInfo> sampleBufferInfos = createBufferInfoListWithSomeKeyFrames();
|
||||
|
||||
ByteBuffer stssBox = Boxes.stss(sampleBufferInfos);
|
||||
|
||||
@ -867,37 +864,35 @@ public class BoxesTest {
|
||||
context, dumpableBox, MuxerTestUtil.getExpectedDumpFilePath("trex_box"));
|
||||
}
|
||||
|
||||
private static List<MediaCodec.BufferInfo> createBufferInfoListWithSamplePresentationTimestamps(
|
||||
private static List<BufferInfo> createBufferInfoListWithSamplePresentationTimestamps(
|
||||
long... timestampsUs) {
|
||||
List<MediaCodec.BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
List<BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
for (long timestampUs : timestampsUs) {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.presentationTimeUs = timestampUs;
|
||||
BufferInfo bufferInfo = new BufferInfo(timestampUs, /* size= */ 0, /* flags= */ 0);
|
||||
bufferInfoList.add(bufferInfo);
|
||||
}
|
||||
|
||||
return bufferInfoList;
|
||||
}
|
||||
|
||||
private static List<MediaCodec.BufferInfo> createBufferInfoListWithSampleSizes(int... sizes) {
|
||||
List<MediaCodec.BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
private static List<BufferInfo> createBufferInfoListWithSampleSizes(int... sizes) {
|
||||
List<BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
for (int size : sizes) {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.size = size;
|
||||
BufferInfo bufferInfo = new BufferInfo(/* presentationTimeUs= */ 0, size, /* flags= */ 0);
|
||||
bufferInfoList.add(bufferInfo);
|
||||
}
|
||||
|
||||
return bufferInfoList;
|
||||
}
|
||||
|
||||
private static List<MediaCodec.BufferInfo> createBufferInfoListWithSomeKeyFrames() {
|
||||
List<MediaCodec.BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
private static List<BufferInfo> createBufferInfoListWithSomeKeyFrames() {
|
||||
List<BufferInfo> bufferInfoList = new ArrayList<>();
|
||||
for (int i = 0; i < 30; i++) {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
@C.BufferFlags int flags = 0;
|
||||
if (i % 5 == 0) { // Make every 5th frame as key frame.
|
||||
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
||||
flags = C.BUFFER_FLAG_KEY_FRAME;
|
||||
}
|
||||
bufferInfoList.add(bufferInfo);
|
||||
bufferInfoList.add(new BufferInfo(/* presentationTimeUs= */ 0, /* size= */ 0, flags));
|
||||
}
|
||||
|
||||
return bufferInfoList;
|
||||
|
@ -16,10 +16,10 @@
|
||||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.getBufferFlagsFromMediaCodecFlags;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.MP4_FILE_ASSET_DIRECTORY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.util.MediaFormatUtil;
|
||||
@ -149,12 +149,12 @@ public class FragmentedMp4MuxerEndToEndTest {
|
||||
}
|
||||
|
||||
do {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.flags = extractor.getSampleFlags();
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.presentationTimeUs = extractor.getSampleTime();
|
||||
int sampleSize = (int) extractor.getSampleSize();
|
||||
bufferInfo.size = sampleSize;
|
||||
BufferInfo bufferInfo =
|
||||
new BufferInfo(
|
||||
extractor.getSampleTime(),
|
||||
sampleSize,
|
||||
getBufferFlagsFromMediaCodecFlags(extractor.getSampleFlags()));
|
||||
|
||||
ByteBuffer sampleBuffer = ByteBuffer.allocateDirect(sampleSize);
|
||||
extractor.readSampleData(sampleBuffer, /* offset= */ 0);
|
||||
|
@ -16,10 +16,10 @@
|
||||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.getBufferFlagsFromMediaCodecFlags;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.MP4_FILE_ASSET_DIRECTORY;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.net.Uri;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.util.MediaFormatUtil;
|
||||
@ -153,12 +153,12 @@ public class Mp4MuxerEndToEndParameterizedTest {
|
||||
}
|
||||
|
||||
do {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.flags = extractor.getSampleFlags();
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.presentationTimeUs = extractor.getSampleTime();
|
||||
int sampleSize = (int) extractor.getSampleSize();
|
||||
bufferInfo.size = sampleSize;
|
||||
BufferInfo bufferInfo =
|
||||
new BufferInfo(
|
||||
extractor.getSampleTime(),
|
||||
sampleSize,
|
||||
getBufferFlagsFromMediaCodecFlags(extractor.getSampleFlags()));
|
||||
|
||||
ByteBuffer sampleBuffer = ByteBuffer.allocateDirect(sampleSize);
|
||||
extractor.readSampleData(sampleBuffer, /* offset= */ 0);
|
||||
|
@ -16,6 +16,7 @@
|
||||
package androidx.media3.muxer;
|
||||
|
||||
import static androidx.media3.common.util.Assertions.checkNotNull;
|
||||
import static androidx.media3.common.util.Util.getBufferFlagsFromMediaCodecFlags;
|
||||
import static androidx.media3.muxer.Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_SET_FROM_END_OF_STREAM_BUFFER_OR_DUPLICATE_PREVIOUS;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.MP4_FILE_ASSET_DIRECTORY;
|
||||
@ -25,8 +26,6 @@ import static com.google.common.truth.Truth.assertThat;
|
||||
import static org.junit.Assert.assertThrows;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.net.Uri;
|
||||
import android.util.Pair;
|
||||
import androidx.media3.common.C;
|
||||
@ -791,12 +790,11 @@ public class Mp4MuxerEndToEndTest {
|
||||
mp4Muxer.writeSampleData(track, sample3.first, sample3.second);
|
||||
mp4Muxer.writeSampleData(track, sample4.first, sample4.second);
|
||||
// Write end of stream sample.
|
||||
BufferInfo endOfStreamBufferInfo = new BufferInfo();
|
||||
endOfStreamBufferInfo.set(
|
||||
/* newOffset= */ 0,
|
||||
/* newSize= */ 0,
|
||||
/* newTimeUs= */ expectedDurationUs,
|
||||
/* newFlags= */ MediaCodec.BUFFER_FLAG_END_OF_STREAM);
|
||||
BufferInfo endOfStreamBufferInfo =
|
||||
new BufferInfo(
|
||||
/* presentationTimeUs= */ expectedDurationUs,
|
||||
/* size= */ 0,
|
||||
C.BUFFER_FLAG_END_OF_STREAM);
|
||||
mp4Muxer.writeSampleData(track, ByteBuffer.allocate(0), endOfStreamBufferInfo);
|
||||
} finally {
|
||||
mp4Muxer.close();
|
||||
@ -929,12 +927,12 @@ public class Mp4MuxerEndToEndTest {
|
||||
}
|
||||
|
||||
do {
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.flags = extractor.getSampleFlags();
|
||||
bufferInfo.offset = 0;
|
||||
bufferInfo.presentationTimeUs = extractor.getSampleTime();
|
||||
int sampleSize = (int) extractor.getSampleSize();
|
||||
bufferInfo.size = sampleSize;
|
||||
BufferInfo bufferInfo =
|
||||
new BufferInfo(
|
||||
extractor.getSampleTime(),
|
||||
sampleSize,
|
||||
getBufferFlagsFromMediaCodecFlags(extractor.getSampleFlags()));
|
||||
|
||||
ByteBuffer sampleBuffer = ByteBuffer.allocateDirect(sampleSize);
|
||||
extractor.readSampleData(sampleBuffer, /* offset= */ 0);
|
||||
|
@ -22,7 +22,6 @@ import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
|
||||
import static androidx.media3.muxer.MuxerTestUtil.XMP_SAMPLE_DATA;
|
||||
|
||||
import android.content.Context;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.media3.common.util.Util;
|
||||
import androidx.media3.container.MdtaMetadataEntry;
|
||||
|
@ -18,9 +18,8 @@ package androidx.media3.muxer;
|
||||
import static androidx.media3.common.MimeTypes.AUDIO_AAC;
|
||||
import static androidx.media3.common.MimeTypes.VIDEO_H264;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import android.util.Pair;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import com.google.common.collect.ImmutableList;
|
||||
import com.google.common.io.BaseEncoding;
|
||||
@ -66,10 +65,8 @@ import java.nio.ByteBuffer;
|
||||
sampleDirectBuffer.put(FAKE_H264_SAMPLE);
|
||||
sampleDirectBuffer.rewind();
|
||||
|
||||
BufferInfo bufferInfo = new BufferInfo();
|
||||
bufferInfo.presentationTimeUs = presentationTimeUs;
|
||||
bufferInfo.flags = MediaCodec.BUFFER_FLAG_KEY_FRAME;
|
||||
bufferInfo.size = FAKE_H264_SAMPLE.length;
|
||||
BufferInfo bufferInfo =
|
||||
new BufferInfo(presentationTimeUs, FAKE_H264_SAMPLE.length, C.BUFFER_FLAG_KEY_FRAME);
|
||||
|
||||
return new Pair<>(sampleDirectBuffer, bufferInfo);
|
||||
}
|
||||
|
@ -15,8 +15,9 @@
|
||||
*/
|
||||
package androidx.media3.transformer;
|
||||
|
||||
import static androidx.media3.muxer.MuxerUtil.getMuxerBufferInfoFromMediaCodecBufferInfo;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MediaLibraryInfo;
|
||||
@ -138,7 +139,7 @@ public final class InAppFragmentedMp4Muxer implements Muxer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||
public void writeSampleData(int trackId, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo)
|
||||
throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET
|
||||
&& trackId == videoTrackId
|
||||
@ -152,7 +153,8 @@ public final class InAppFragmentedMp4Muxer implements Muxer {
|
||||
videoDurationUs));
|
||||
return;
|
||||
}
|
||||
muxer.writeSampleData(trackId, byteBuffer, bufferInfo);
|
||||
muxer.writeSampleData(
|
||||
trackId, byteBuffer, getMuxerBufferInfoFromMediaCodecBufferInfo(bufferInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -165,7 +167,7 @@ public final class InAppFragmentedMp4Muxer implements Muxer {
|
||||
@Override
|
||||
public void close() throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET && videoTrackId != TRACK_ID_UNSET) {
|
||||
BufferInfo bufferInfo = new BufferInfo();
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.set(
|
||||
/* newOffset= */ 0,
|
||||
/* newSize= */ 0,
|
||||
|
@ -15,8 +15,9 @@
|
||||
*/
|
||||
package androidx.media3.transformer;
|
||||
|
||||
import static androidx.media3.muxer.MuxerUtil.getMuxerBufferInfoFromMediaCodecBufferInfo;
|
||||
|
||||
import android.media.MediaCodec;
|
||||
import android.media.MediaCodec.BufferInfo;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
@ -157,7 +158,7 @@ public final class InAppMp4Muxer implements Muxer {
|
||||
}
|
||||
|
||||
@Override
|
||||
public void writeSampleData(int trackId, ByteBuffer byteBuffer, BufferInfo bufferInfo)
|
||||
public void writeSampleData(int trackId, ByteBuffer byteBuffer, MediaCodec.BufferInfo bufferInfo)
|
||||
throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET
|
||||
&& trackId == videoTrackId
|
||||
@ -171,7 +172,8 @@ public final class InAppMp4Muxer implements Muxer {
|
||||
videoDurationUs));
|
||||
return;
|
||||
}
|
||||
muxer.writeSampleData(trackId, byteBuffer, bufferInfo);
|
||||
muxer.writeSampleData(
|
||||
trackId, byteBuffer, getMuxerBufferInfoFromMediaCodecBufferInfo(bufferInfo));
|
||||
}
|
||||
|
||||
@Override
|
||||
@ -184,7 +186,7 @@ public final class InAppMp4Muxer implements Muxer {
|
||||
@Override
|
||||
public void close() throws MuxerException {
|
||||
if (videoDurationUs != C.TIME_UNSET && videoTrackId != TRACK_ID_UNSET) {
|
||||
BufferInfo bufferInfo = new BufferInfo();
|
||||
MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
|
||||
bufferInfo.set(
|
||||
/* newOffset= */ 0,
|
||||
/* newSize= */ 0,
|
||||
|
Loading…
x
Reference in New Issue
Block a user