mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
Change sample duration type from Long to Integer
In muxer only 32-bit sample duration is supported. Earlier the duration was type casted at different places. PiperOrigin-RevId: 643954226
This commit is contained in:
parent
eedfb9960e
commit
ded1adc092
@ -42,7 +42,6 @@ import java.util.ArrayList;
|
||||
import java.util.Arrays;
|
||||
import java.util.Collections;
|
||||
import java.util.List;
|
||||
import java.util.Locale;
|
||||
|
||||
/**
|
||||
* Writes out various types of boxes as per MP4 (ISO/IEC 14496-12) standards.
|
||||
@ -636,14 +635,13 @@ import java.util.Locale;
|
||||
* @return A list of all the sample durations.
|
||||
*/
|
||||
// TODO: b/280084657 - Add support for setting last sample duration.
|
||||
// TODO: b/317373578 - Consider changing return type to List<Integer>.
|
||||
public static List<Long> convertPresentationTimestampsToDurationsVu(
|
||||
public static List<Integer> convertPresentationTimestampsToDurationsVu(
|
||||
List<BufferInfo> samplesInfo,
|
||||
long firstSamplePresentationTimeUs,
|
||||
int videoUnitTimescale,
|
||||
@Mp4Muxer.LastFrameDurationBehavior int lastDurationBehavior) {
|
||||
List<Long> presentationTimestampsUs = new ArrayList<>(samplesInfo.size());
|
||||
List<Long> durationsVu = new ArrayList<>(samplesInfo.size());
|
||||
List<Integer> durationsVu = new ArrayList<>(samplesInfo.size());
|
||||
|
||||
if (samplesInfo.isEmpty()) {
|
||||
return durationsVu;
|
||||
@ -672,23 +670,20 @@ import java.util.Locale;
|
||||
long currentSampleDurationVu =
|
||||
vuFromUs(nextSampleTimeUs, videoUnitTimescale)
|
||||
- vuFromUs(currentSampleTimeUs, videoUnitTimescale);
|
||||
if (currentSampleDurationVu > Integer.MAX_VALUE) {
|
||||
throw new IllegalArgumentException(
|
||||
String.format(
|
||||
Locale.US, "Timestamp delta %d doesn't fit into an int", currentSampleDurationVu));
|
||||
}
|
||||
durationsVu.add(currentSampleDurationVu);
|
||||
checkState(
|
||||
currentSampleDurationVu <= Integer.MAX_VALUE, "Only 32-bit sample duration is allowed");
|
||||
durationsVu.add((int) currentSampleDurationVu);
|
||||
currentSampleTimeUs = nextSampleTimeUs;
|
||||
}
|
||||
// Default duration for the last sample.
|
||||
durationsVu.add(0L);
|
||||
durationsVu.add(0);
|
||||
|
||||
adjustLastSampleDuration(durationsVu, lastDurationBehavior);
|
||||
return durationsVu;
|
||||
}
|
||||
|
||||
/** Generates the stts (decoding time to sample) box. */
|
||||
public static ByteBuffer stts(List<Long> durationsVu) {
|
||||
public static ByteBuffer stts(List<Integer> durationsVu) {
|
||||
ByteBuffer contents = ByteBuffer.allocate(durationsVu.size() * 8 + MAX_FIXED_LEAF_BOX_SIZE);
|
||||
|
||||
contents.putInt(0x0); // version and flags.
|
||||
@ -705,7 +700,7 @@ import java.util.Locale;
|
||||
// Note that the framework MediaMuxer adjust time deltas within plus-minus 100 us, so that
|
||||
// samples have repeating duration values. It saves few entries in the table.
|
||||
for (int i = 0; i < durationsVu.size(); i++) {
|
||||
long durationVu = durationsVu.get(i);
|
||||
int durationVu = durationsVu.get(i);
|
||||
if (lastDurationVu != durationVu) {
|
||||
lastDurationVu = durationVu;
|
||||
lastSampleCountIndex = contents.position();
|
||||
@ -713,7 +708,7 @@ import java.util.Locale;
|
||||
// sample_count; this will be updated instead of adding a new entry if the next sample has
|
||||
// the same duration.
|
||||
contents.putInt(1);
|
||||
contents.putInt((int) durationVu); // sample_delta.
|
||||
contents.putInt(durationVu); // sample_delta
|
||||
totalEntryCount++;
|
||||
} else {
|
||||
contents.putInt(lastSampleCountIndex, contents.getInt(lastSampleCountIndex) + 1);
|
||||
@ -728,7 +723,7 @@ import java.util.Locale;
|
||||
|
||||
/** Returns the ctts (composition time to sample) box. */
|
||||
public static ByteBuffer ctts(
|
||||
List<BufferInfo> samplesInfo, List<Long> durationVu, int videoUnitTimescale) {
|
||||
List<BufferInfo> samplesInfo, List<Integer> durationVu, int videoUnitTimescale) {
|
||||
// Generate the sample composition offsets list to create ctts box.
|
||||
List<Integer> compositionOffsets =
|
||||
Boxes.calculateSampleCompositionTimeOffsets(samplesInfo, durationVu, videoUnitTimescale);
|
||||
@ -786,7 +781,7 @@ import java.util.Locale;
|
||||
* @return A list of all the sample composition time offsets.
|
||||
*/
|
||||
public static List<Integer> calculateSampleCompositionTimeOffsets(
|
||||
List<BufferInfo> samplesInfo, List<Long> durationVu, int videoUnitTimescale) {
|
||||
List<BufferInfo> samplesInfo, List<Integer> durationVu, int videoUnitTimescale) {
|
||||
List<Integer> compositionOffsets = new ArrayList<>(samplesInfo.size());
|
||||
if (samplesInfo.isEmpty()) {
|
||||
return compositionOffsets;
|
||||
@ -802,7 +797,9 @@ import java.util.Locale;
|
||||
samplesInfo.get(sampleId).presentationTimeUs - firstSamplePresentationTimeUs;
|
||||
long currentCompositionOffsetVu =
|
||||
vuFromUs(currentSampleCompositionTimeUs, videoUnitTimescale) - currentSampleDecodeTime;
|
||||
checkState(currentCompositionOffsetVu <= Integer.MAX_VALUE, "Only 32-bit offset is allowed");
|
||||
checkState(
|
||||
currentCompositionOffsetVu <= Integer.MAX_VALUE,
|
||||
"Only 32-bit composition offset is allowed");
|
||||
currentSampleDecodeTime += durationVu.get(sampleId); // DT(n+1) = DT(n) + STTS(n)
|
||||
compositionOffsets.add((int) currentCompositionOffsetVu);
|
||||
|
||||
@ -1022,7 +1019,7 @@ import java.util.Locale;
|
||||
contents.putInt(dataOffset); // A signed int(32)
|
||||
for (int i = 0; i < samplesMetadata.size(); i++) {
|
||||
SampleMetadata currentSampleMetadata = samplesMetadata.get(i);
|
||||
contents.putInt((int) currentSampleMetadata.durationVu); // An unsigned int(32)
|
||||
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
|
||||
@ -1064,7 +1061,7 @@ import java.util.Locale;
|
||||
// TODO: b/317117431 - Change this method to getLastSampleDuration().
|
||||
/** Adjusts the duration of the very last sample if needed. */
|
||||
private static void adjustLastSampleDuration(
|
||||
List<Long> durationsToBeAdjustedVu, @Mp4Muxer.LastFrameDurationBehavior int behavior) {
|
||||
List<Integer> durationsToBeAdjustedVu, @Mp4Muxer.LastFrameDurationBehavior 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
|
||||
|
@ -49,12 +49,12 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
/* package */ final class FragmentedMp4Writer {
|
||||
/** Provides a limited set of sample metadata. */
|
||||
public static class SampleMetadata {
|
||||
public final long durationVu;
|
||||
public final int durationVu;
|
||||
public final int size;
|
||||
public final int flags;
|
||||
public final int compositionTimeOffsetVu;
|
||||
|
||||
public SampleMetadata(long durationsVu, int size, int flags, int compositionTimeOffsetVu) {
|
||||
public SampleMetadata(int durationsVu, int size, int flags, int compositionTimeOffsetVu) {
|
||||
this.durationVu = durationsVu;
|
||||
this.size = size;
|
||||
this.flags = flags;
|
||||
@ -320,7 +320,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
||||
|
||||
boolean hasBFrame = false;
|
||||
ImmutableList<BufferInfo> pendingSamplesBufferInfo = pendingSamplesBufferInfoBuilder.build();
|
||||
List<Long> sampleDurations =
|
||||
List<Integer> sampleDurations =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
pendingSamplesBufferInfo,
|
||||
/* firstSamplePresentationTimeUs= */ currentFragmentSequenceNumber == 1
|
||||
|
@ -79,7 +79,7 @@ import org.checkerframework.checker.nullness.qual.PolyNull;
|
||||
String languageCode = bcp47LanguageTagToIso3(format.language);
|
||||
|
||||
// Generate the sample durations to calculate the total duration for tkhd box.
|
||||
List<Long> sampleDurationsVu =
|
||||
List<Integer> sampleDurationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
track.writtenSamples(),
|
||||
minInputPtsUs,
|
||||
|
@ -403,14 +403,14 @@ public class BoxesTest {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
VU_TIMEBASE,
|
||||
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
|
||||
|
||||
assertThat(durationsVu).containsExactly(0L);
|
||||
assertThat(durationsVu).containsExactly(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -419,14 +419,14 @@ public class BoxesTest {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(5_000L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
VU_TIMEBASE,
|
||||
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
|
||||
|
||||
assertThat(durationsVu).containsExactly(0L);
|
||||
assertThat(durationsVu).containsExactly(0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -435,14 +435,14 @@ public class BoxesTest {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 30_000L, 80_000L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
VU_TIMEBASE,
|
||||
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
|
||||
|
||||
assertThat(durationsVu).containsExactly(3_000L, 5_000L, 0L);
|
||||
assertThat(durationsVu).containsExactly(3_000, 5_000, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -451,14 +451,14 @@ public class BoxesTest {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 30_000L, 80_000L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
VU_TIMEBASE,
|
||||
LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
|
||||
|
||||
assertThat(durationsVu).containsExactly(3_000L, 5_000L, 5_000L);
|
||||
assertThat(durationsVu).containsExactly(3_000, 5_000, 5_000);
|
||||
}
|
||||
|
||||
@Test
|
||||
@ -467,19 +467,19 @@ public class BoxesTest {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 10_000L, 1_000L, 2_000L, 11_000L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
VU_TIMEBASE,
|
||||
LAST_FRAME_DURATION_BEHAVIOR_INSERT_SHORT_FRAME);
|
||||
|
||||
assertThat(durationsVu).containsExactly(100L, 100L, 800L, 100L, 0L);
|
||||
assertThat(durationsVu).containsExactly(100, 100, 800, 100, 0);
|
||||
}
|
||||
|
||||
@Test
|
||||
public void createSttsBox_withSingleSampleDuration_matchesExpected() throws IOException {
|
||||
ImmutableList<Long> sampleDurations = ImmutableList.of(500L);
|
||||
ImmutableList<Integer> sampleDurations = ImmutableList.of(500);
|
||||
|
||||
ByteBuffer sttsBox = Boxes.stts(sampleDurations);
|
||||
|
||||
@ -492,7 +492,7 @@ public class BoxesTest {
|
||||
|
||||
@Test
|
||||
public void createSttsBox_withAllDifferentSampleDurations_matchesExpected() throws IOException {
|
||||
ImmutableList<Long> sampleDurations = ImmutableList.of(1_000L, 2_000L, 3_000L, 5_000L);
|
||||
ImmutableList<Integer> sampleDurations = ImmutableList.of(1_000, 2_000, 3_000, 5_000);
|
||||
|
||||
ByteBuffer sttsBox = Boxes.stts(sampleDurations);
|
||||
|
||||
@ -506,7 +506,7 @@ public class BoxesTest {
|
||||
@Test
|
||||
public void createSttsBox_withFewConsecutiveSameSampleDurations_matchesExpected()
|
||||
throws IOException {
|
||||
ImmutableList<Long> sampleDurations = ImmutableList.of(1_000L, 2_000L, 2_000L, 2_000L);
|
||||
ImmutableList<Integer> sampleDurations = ImmutableList.of(1_000, 2_000, 2_000, 2_000);
|
||||
|
||||
ByteBuffer sttsBox = Boxes.stts(sampleDurations);
|
||||
|
||||
@ -521,7 +521,7 @@ public class BoxesTest {
|
||||
public void createCttsBox_withSingleSampleTimestamp_returnsEmptyBox() {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(400);
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
@ -538,7 +538,7 @@ public class BoxesTest {
|
||||
public void createCttsBox_withNoBframesSampleTimestamps_returnsEmptyBox() throws IOException {
|
||||
List<MediaCodec.BufferInfo> sampleBufferInfos =
|
||||
createBufferInfoListWithSamplePresentationTimestamps(0L, 1000L, 2000L);
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
@ -557,7 +557,7 @@ public class BoxesTest {
|
||||
createBufferInfoListWithSamplePresentationTimestamps(
|
||||
0, 400, 200, 100, 300, 800, 600, 500, 700);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 0L,
|
||||
@ -577,7 +577,7 @@ public class BoxesTest {
|
||||
createBufferInfoListWithSamplePresentationTimestamps(
|
||||
23698215060L, 23698248252L, 23698347988L, 23698488968L, 23698547416L);
|
||||
|
||||
List<Long> durationsVu =
|
||||
List<Integer> durationsVu =
|
||||
Boxes.convertPresentationTimestampsToDurationsVu(
|
||||
sampleBufferInfos,
|
||||
/* firstSamplePresentationTimeUs= */ 23698215060L,
|
||||
@ -679,7 +679,7 @@ public class BoxesTest {
|
||||
for (int i = 0; i < sampleCount; i++) {
|
||||
samplesMetadata.add(
|
||||
new SampleMetadata(
|
||||
/* durationsVu= */ 2_000L,
|
||||
/* durationsVu= */ 2_000,
|
||||
/* size= */ 5_000,
|
||||
/* flags= */ i == 0 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0,
|
||||
/* compositionTimeOffsetVu= */ 0));
|
||||
@ -700,7 +700,7 @@ public class BoxesTest {
|
||||
for (int i = 0; i < sampleCount; i++) {
|
||||
samplesMetadata.add(
|
||||
new SampleMetadata(
|
||||
/* durationsVu= */ 2_000L,
|
||||
/* durationsVu= */ 2_000,
|
||||
/* size= */ 5_000,
|
||||
/* flags= */ i == 0 ? MediaCodec.BUFFER_FLAG_KEY_FRAME : 0,
|
||||
/* compositionTimeOffsetVu= */ 100));
|
||||
|
Loading…
x
Reference in New Issue
Block a user