Rename LAST_FRAME_DURATION_BEHAVIOR to LAST_SAMPLE_DURATION_BEHAVIOR

The original idea was to set duration for the last video frame, but this behavior actually applies to all tracks.

PiperOrigin-RevId: 667990099
This commit is contained in:
sheenachhabra 2024-08-27 08:06:02 -07:00 committed by Copybara-Service
parent d0676245b5
commit ebd60acc95
5 changed files with 46 additions and 47 deletions

View File

@ -131,7 +131,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
MetadataCollector metadataCollector,
long minInputPtsUs,
boolean isFragmentedMp4,
@Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior) {
@Mp4Muxer.LastSampleDurationBehavior int lastSampleDurationBehavior) {
// The timestamp will always fit into a 32-bit integer. This is already validated in the
// Mp4Muxer.setTimestampData() API. The value after type casting might be negative, but it is
// still valid because it is meant to be read as an unsigned integer.
@ -157,7 +157,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
track.writtenSamples(),
minInputPtsUs,
track.videoUnitTimebase(),
lastFrameDurationBehavior);
lastSampleDurationBehavior);
long trackDurationInTrackUnitsVu = 0;
for (int j = 0; j < sampleDurationsVu.size(); j++) {
@ -808,7 +808,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
* Otherwise this should be equal to the presentation timestamp of first sample present in the
* {@code samplesInfo} list.
* @param videoUnitTimescale The timescale of the track.
* @param lastDurationBehavior The behaviour for the last sample duration.
* @param lastSampleDurationBehavior The behaviour for the last sample duration.
* @return A list of all the sample durations.
*/
// TODO: b/280084657 - Add support for setting last sample duration.
@ -816,7 +816,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
List<BufferInfo> samplesInfo,
long firstSamplePresentationTimeUs,
int videoUnitTimescale,
@Mp4Muxer.LastFrameDurationBehavior int lastDurationBehavior) {
@Mp4Muxer.LastSampleDurationBehavior int lastSampleDurationBehavior) {
List<Long> presentationTimestampsUs = new ArrayList<>(samplesInfo.size());
List<Integer> durationsVu = new ArrayList<>(samplesInfo.size());
@ -855,7 +855,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
// Default duration for the last sample.
durationsVu.add(0);
adjustLastSampleDuration(durationsVu, lastDurationBehavior);
adjustLastSampleDuration(durationsVu, lastSampleDurationBehavior);
return durationsVu;
}
@ -1264,7 +1264,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
// TODO: b/317117431 - Change this method to getLastSampleDuration().
/** Adjusts the duration of the very last sample if needed. */
private static void adjustLastSampleDuration(
List<Integer> durationsToBeAdjustedVu, @Mp4Muxer.LastFrameDurationBehavior int behavior) {
List<Integer> durationsToBeAdjustedVu, @Mp4Muxer.LastSampleDurationBehavior int behavior) {
// Technically, MP4 file stores frame durations, not timestamps. If a frame starts at a
// given timestamp then the duration of the last frame is not obvious. If samples follow each
// other in roughly regular intervals (e.g. in a normal, 30 fps video), it can be safely assumed
@ -1278,14 +1278,14 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
}
switch (behavior) {
case Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION:
case Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION:
// This is the default MediaMuxer behavior: the last sample duration is a copy of the
// previous sample duration.
durationsToBeAdjustedVu.set(
durationsToBeAdjustedVu.size() - 1,
durationsToBeAdjustedVu.get(durationsToBeAdjustedVu.size() - 2));
break;
case Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME:
case Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE:
// Keep the last sample duration as short as possible.
checkState(Iterables.getLast(durationsToBeAdjustedVu) == 0L);
break;

View File

@ -68,7 +68,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
private final AnnexBToAvccConverter annexBToAvccConverter;
private final long fragmentDurationUs;
private final boolean sampleCopyEnabled;
private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior;
private final @Mp4Muxer.LastSampleDurationBehavior int lastSampleDurationBehavior;
private final List<Track> tracks;
private @MonotonicNonNull Track videoTrack;
@ -100,7 +100,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
this.annexBToAvccConverter = annexBToAvccConverter;
this.fragmentDurationUs = fragmentDurationMs * 1_000;
this.sampleCopyEnabled = sampleCopyEnabled;
lastFrameDurationBehavior = Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION;
lastSampleDurationBehavior = Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION;
tracks = new ArrayList<>();
minInputPresentationTimeUs = Long.MAX_VALUE;
currentFragmentSequenceNumber = 1;
@ -207,7 +207,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
metadataCollector,
/* minInputPtsUs= */ 0L,
/* isFragmentedMp4= */ true,
lastFrameDurationBehavior));
lastSampleDurationBehavior));
}
private boolean shouldFlushPendingSamples(
@ -333,7 +333,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
? minInputPresentationTimeUs
: pendingSamplesBufferInfo.get(0).presentationTimeUs,
track.videoUnitTimebase(),
Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
List<Integer> sampleCompositionTimeOffsets =
Boxes.calculateSampleCompositionTimeOffsets(

View File

@ -145,19 +145,19 @@ public final class Mp4Muxer implements Muxer {
@Retention(RetentionPolicy.SOURCE)
@Target(TYPE_USE)
@IntDef({
LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE,
LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION,
})
public @interface LastFrameDurationBehavior {}
public @interface LastSampleDurationBehavior {}
/** Insert a zero-length last sample. */
public static final int LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME = 0;
public static final int LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE = 0;
/**
* Use the difference between the last timestamp and the one before that as the duration of the
* last sample.
*/
public static final int LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION = 1;
public static final int LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION = 1;
/** The specific MP4 file format. */
@Documented
@ -183,7 +183,7 @@ public final class Mp4Muxer implements Muxer {
public static final class Builder {
private final FileOutputStream outputStream;
private @LastFrameDurationBehavior int lastFrameDurationBehavior;
private @LastSampleDurationBehavior int lastSampleDurationBehavior;
@Nullable private AnnexBToAvccConverter annexBToAvccConverter;
private boolean sampleCopyEnabled;
private boolean attemptStreamableOutputEnabled;
@ -197,21 +197,21 @@ public final class Mp4Muxer implements Muxer {
*/
public Builder(FileOutputStream outputStream) {
this.outputStream = outputStream;
lastFrameDurationBehavior = LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME;
lastSampleDurationBehavior = LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE;
sampleCopyEnabled = true;
attemptStreamableOutputEnabled = true;
outputFileFormat = FILE_FORMAT_DEFAULT;
}
/**
* Sets the {@link LastFrameDurationBehavior} for the video track.
* Sets the {@link LastSampleDurationBehavior}.
*
* <p>The default value is {@link #LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME}.
* <p>The default value is {@link #LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE}.
*/
@CanIgnoreReturnValue
public Mp4Muxer.Builder setLastFrameDurationBehavior(
@LastFrameDurationBehavior int lastFrameDurationBehavior) {
this.lastFrameDurationBehavior = lastFrameDurationBehavior;
public Mp4Muxer.Builder setLastSampleDurationBehavior(
@LastSampleDurationBehavior int lastSampleDurationBehavior) {
this.lastSampleDurationBehavior = lastSampleDurationBehavior;
return this;
}
@ -290,7 +290,7 @@ public final class Mp4Muxer implements Muxer {
"EditablevideoParameters must be set for FILE_FORMAT_EDITABLE_VIDEO");
return new Mp4Muxer(
outputStream,
lastFrameDurationBehavior,
lastSampleDurationBehavior,
annexBToAvccConverter == null ? AnnexBToAvccConverter.DEFAULT : annexBToAvccConverter,
sampleCopyEnabled,
attemptStreamableOutputEnabled,
@ -303,7 +303,7 @@ public final class Mp4Muxer implements Muxer {
private final FileOutputStream outputStream;
private final FileChannel outputChannel;
private final @LastFrameDurationBehavior int lastFrameDurationBehavior;
private final @LastSampleDurationBehavior int lastSampleDurationBehavior;
private final AnnexBToAvccConverter annexBToAvccConverter;
private final boolean sampleCopyEnabled;
private final boolean attemptStreamableOutputEnabled;
@ -320,7 +320,7 @@ public final class Mp4Muxer implements Muxer {
private Mp4Muxer(
FileOutputStream outputStream,
@LastFrameDurationBehavior int lastFrameDurationBehavior,
@LastSampleDurationBehavior int lastFrameDurationBehavior,
AnnexBToAvccConverter annexBToAvccConverter,
boolean sampleCopyEnabled,
boolean attemptStreamableOutputEnabled,
@ -328,7 +328,7 @@ public final class Mp4Muxer implements Muxer {
@Nullable EditableVideoParameters editableVideoParameters) {
this.outputStream = outputStream;
outputChannel = outputStream.getChannel();
this.lastFrameDurationBehavior = lastFrameDurationBehavior;
this.lastSampleDurationBehavior = lastFrameDurationBehavior;
this.annexBToAvccConverter = annexBToAvccConverter;
this.sampleCopyEnabled = sampleCopyEnabled;
this.attemptStreamableOutputEnabled = attemptStreamableOutputEnabled;
@ -504,7 +504,7 @@ public final class Mp4Muxer implements Muxer {
cacheFileOutputStream.getChannel(),
checkNotNull(editableVideoMetadataCollector),
annexBToAvccConverter,
lastFrameDurationBehavior,
lastSampleDurationBehavior,
sampleCopyEnabled,
attemptStreamableOutputEnabled);
}

View File

@ -49,7 +49,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
private final FileChannel outputFileChannel;
private final MetadataCollector metadataCollector;
private final AnnexBToAvccConverter annexBToAvccConverter;
private final @Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior;
private final @Mp4Muxer.LastSampleDurationBehavior int lastSampleDurationBehavior;
private final boolean sampleCopyEnabled;
private final List<Track> tracks;
private final List<Track> editableVideoTracks;
@ -77,8 +77,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
* @param annexBToAvccConverter The {@link AnnexBToAvccConverter} to be used to convert H.264 and
* 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 lastFrameDurationBehavior The {@link Mp4Muxer.LastFrameDurationBehavior} for the video
* track.
* @param lastSampleDurationBehavior The {@link Mp4Muxer.LastSampleDurationBehavior}.
* @param sampleCopyEnabled Whether sample copying is enabled.
* @param attemptStreamableOutputEnabled Whether to attempt to write a streamable output.
*/
@ -86,13 +85,13 @@ import java.util.concurrent.atomic.AtomicBoolean;
FileChannel fileChannel,
MetadataCollector metadataCollector,
AnnexBToAvccConverter annexBToAvccConverter,
@Mp4Muxer.LastFrameDurationBehavior int lastFrameDurationBehavior,
@Mp4Muxer.LastSampleDurationBehavior int lastSampleDurationBehavior,
boolean sampleCopyEnabled,
boolean attemptStreamableOutputEnabled) {
this.outputFileChannel = fileChannel;
this.metadataCollector = metadataCollector;
this.annexBToAvccConverter = annexBToAvccConverter;
this.lastFrameDurationBehavior = lastFrameDurationBehavior;
this.lastSampleDurationBehavior = lastSampleDurationBehavior;
this.sampleCopyEnabled = sampleCopyEnabled;
tracks = new ArrayList<>();
editableVideoTracks = new ArrayList<>();
@ -205,7 +204,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
editableVideoMetadataCollector,
findMinimumPresentationTimestampUsAcrossTracks(editableVideoTracks),
/* isFragmentedMp4= */ false,
lastFrameDurationBehavior);
lastSampleDurationBehavior);
ByteBuffer edvdBoxHeader =
getEdvdBoxHeader(/* payloadSize= */ ftypBox.remaining() + moovBox.remaining());
return BoxUtils.concatenateBuffers(edvdBoxHeader, ftypBox, moovBox);
@ -323,7 +322,7 @@ import java.util.concurrent.atomic.AtomicBoolean;
metadataCollector,
minInputPtsUs,
/* isFragmentedMp4= */ false,
lastFrameDurationBehavior);
lastSampleDurationBehavior);
} else {
// Skip moov box, if there are no samples.
moovHeader = ByteBuffer.allocate(0);

View File

@ -15,8 +15,8 @@
*/
package androidx.media3.muxer;
import static androidx.media3.muxer.Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION;
import static androidx.media3.muxer.Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME;
import static androidx.media3.muxer.Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION;
import static androidx.media3.muxer.Mp4Muxer.LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_AUDIO_FORMAT;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_CSD_0;
import static androidx.media3.muxer.MuxerTestUtil.FAKE_VIDEO_FORMAT;
@ -477,7 +477,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
assertThat(durationsVu).containsExactly(0);
}
@ -493,7 +493,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
assertThat(durationsVu).containsExactly(0);
}
@ -509,7 +509,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
assertThat(durationsVu).containsExactly(3_000, 5_000, 0);
}
@ -525,7 +525,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
LAST_SAMPLE_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
assertThat(durationsVu).containsExactly(3_000, 5_000, 5_000);
}
@ -541,7 +541,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
assertThat(durationsVu).containsExactly(100, 100, 800, 100, 0);
}
@ -595,7 +595,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
ByteBuffer cttsBox = Boxes.ctts(sampleBufferInfos, durationsVu, VU_TIMEBASE);
@ -612,7 +612,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
ByteBuffer cttsBox = Boxes.ctts(sampleBufferInfos, durationsVu, VU_TIMEBASE);
@ -631,7 +631,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 0L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
ByteBuffer cttsBox = Boxes.ctts(sampleBufferInfos, durationsVu, VU_TIMEBASE);
@ -651,7 +651,7 @@ public class BoxesTest {
sampleBufferInfos,
/* firstSamplePresentationTimeUs= */ 23698215060L,
VU_TIMEBASE,
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
LAST_SAMPLE_DURATION_BEHAVIOR_INSERT_SHORT_SAMPLE);
ByteBuffer cttsBox = Boxes.ctts(sampleBufferInfos, durationsVu, VU_TIMEBASE);