Process all tracks before writing fragment in fragmented MP4
Earlier implementation processed each track (pending sample's buffer info) individually when writing their corresponding "traf" box in a fragment. The change involves processing all tracks before start writing "traf" boxes. #minor-release PiperOrigin-RevId: 600811093
This commit is contained in:
parent
b64d754670
commit
4c1581a175
@ -27,6 +27,7 @@ import androidx.media3.common.Format;
|
|||||||
import androidx.media3.common.MimeTypes;
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
import androidx.media3.muxer.Mp4Muxer.TrackToken;
|
||||||
|
import com.google.common.collect.ImmutableList;
|
||||||
import java.io.FileOutputStream;
|
import java.io.FileOutputStream;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
import java.nio.ByteBuffer;
|
import java.nio.ByteBuffer;
|
||||||
@ -115,6 +116,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private static ImmutableList<ByteBuffer> createTrafBoxes(List<ProcessedTrackInfo> trackInfos) {
|
||||||
|
ImmutableList.Builder<ByteBuffer> trafBoxes = new ImmutableList.Builder<>();
|
||||||
|
for (int i = 0; i < trackInfos.size(); i++) {
|
||||||
|
ProcessedTrackInfo currentTrackInfo = trackInfos.get(i);
|
||||||
|
ByteBuffer trun = Boxes.trun(currentTrackInfo.pendingSamplesMetadata);
|
||||||
|
trafBoxes.add(Boxes.traf(Boxes.tfhd(currentTrackInfo.trackId), trun));
|
||||||
|
}
|
||||||
|
return trafBoxes.build();
|
||||||
|
}
|
||||||
|
|
||||||
private void createHeader() throws IOException {
|
private void createHeader() throws IOException {
|
||||||
output.position(0L);
|
output.position(0L);
|
||||||
output.write(Boxes.ftyp());
|
output.write(Boxes.ftyp());
|
||||||
@ -147,8 +158,9 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
}
|
}
|
||||||
|
|
||||||
private void createFragment() throws IOException {
|
private void createFragment() throws IOException {
|
||||||
|
ImmutableList<ProcessedTrackInfo> trackInfos = processAllTracks();
|
||||||
// Write moof box.
|
// Write moof box.
|
||||||
List<ByteBuffer> trafBoxes = createTrafBoxes();
|
ImmutableList<ByteBuffer> trafBoxes = createTrafBoxes(trackInfos);
|
||||||
if (trafBoxes.isEmpty()) {
|
if (trafBoxes.isEmpty()) {
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
@ -159,19 +171,6 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
currentFragmentSequenceNumber++;
|
currentFragmentSequenceNumber++;
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<ByteBuffer> createTrafBoxes() {
|
|
||||||
List<ByteBuffer> trafBoxes = new ArrayList<>();
|
|
||||||
for (int i = 0; i < tracks.size(); i++) {
|
|
||||||
Track currentTrack = tracks.get(i);
|
|
||||||
if (!currentTrack.pendingSamplesBufferInfo.isEmpty()) {
|
|
||||||
List<SampleMetadata> samplesMetadata = processPendingSamplesBufferInfo(currentTrack);
|
|
||||||
ByteBuffer trun = Boxes.trun(samplesMetadata);
|
|
||||||
trafBoxes.add(Boxes.traf(Boxes.tfhd(/* trackId= */ i + 1), trun));
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return trafBoxes;
|
|
||||||
}
|
|
||||||
|
|
||||||
private void writeMdatBox() throws IOException {
|
private void writeMdatBox() throws IOException {
|
||||||
long mdatStartPosition = output.position();
|
long mdatStartPosition = output.position();
|
||||||
int mdatHeaderSize = 8; // 4 bytes (box size) + 4 bytes (box name)
|
int mdatHeaderSize = 8; // 4 bytes (box size) + 4 bytes (box name)
|
||||||
@ -210,7 +209,17 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
output.position(currentPosition);
|
output.position(currentPosition);
|
||||||
}
|
}
|
||||||
|
|
||||||
private List<SampleMetadata> processPendingSamplesBufferInfo(Track track) {
|
private ImmutableList<ProcessedTrackInfo> processAllTracks() {
|
||||||
|
ImmutableList.Builder<ProcessedTrackInfo> trackInfos = new ImmutableList.Builder<>();
|
||||||
|
for (int i = 0; i < tracks.size(); i++) {
|
||||||
|
if (!tracks.get(i).pendingSamplesBufferInfo.isEmpty()) {
|
||||||
|
trackInfos.add(processTrack(/* trackId= */ i + 1, tracks.get(i)));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return trackInfos.build();
|
||||||
|
}
|
||||||
|
|
||||||
|
private ProcessedTrackInfo processTrack(int trackId, Track track) {
|
||||||
List<BufferInfo> sampleBufferInfos = new ArrayList<>(track.pendingSamplesBufferInfo);
|
List<BufferInfo> sampleBufferInfos = new ArrayList<>(track.pendingSamplesBufferInfo);
|
||||||
|
|
||||||
List<Long> sampleDurations =
|
List<Long> sampleDurations =
|
||||||
@ -222,7 +231,7 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
track.videoUnitTimebase(),
|
track.videoUnitTimebase(),
|
||||||
Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
|
Mp4Muxer.LAST_FRAME_DURATION_BEHAVIOR_DUPLICATE_PREV_DURATION);
|
||||||
|
|
||||||
List<SampleMetadata> pendingSamplesMetadata = new ArrayList<>(sampleBufferInfos.size());
|
ImmutableList.Builder<SampleMetadata> pendingSamplesMetadata = new ImmutableList.Builder<>();
|
||||||
for (int i = 0; i < sampleBufferInfos.size(); i++) {
|
for (int i = 0; i < sampleBufferInfos.size(); i++) {
|
||||||
pendingSamplesMetadata.add(
|
pendingSamplesMetadata.add(
|
||||||
new SampleMetadata(
|
new SampleMetadata(
|
||||||
@ -233,6 +242,16 @@ import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
|
|||||||
|
|
||||||
// Clear the queue.
|
// Clear the queue.
|
||||||
track.pendingSamplesBufferInfo.clear();
|
track.pendingSamplesBufferInfo.clear();
|
||||||
return pendingSamplesMetadata;
|
return new ProcessedTrackInfo(trackId, pendingSamplesMetadata.build());
|
||||||
|
}
|
||||||
|
|
||||||
|
private static class ProcessedTrackInfo {
|
||||||
|
public final int trackId;
|
||||||
|
public final ImmutableList<SampleMetadata> pendingSamplesMetadata;
|
||||||
|
|
||||||
|
public ProcessedTrackInfo(int trackId, ImmutableList<SampleMetadata> pendingSamplesMetadata) {
|
||||||
|
this.trackId = trackId;
|
||||||
|
this.pendingSamplesMetadata = pendingSamplesMetadata;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user