Write empty image byte arrays to sample queue
The number of empty image byte arrays written is one less than the total number of tiles in the image. The empty byte arrays act as placeholders for individual tiles inside ImageRenderer. PiperOrigin-RevId: 591231432
This commit is contained in:
parent
7e65cce967
commit
1096ae9145
@ -344,13 +344,26 @@ public class ImageRenderer extends BaseRenderer {
|
||||
return false;
|
||||
case C.RESULT_BUFFER_READ:
|
||||
inputBuffer.flip();
|
||||
checkNotNull(decoder).queueInputBuffer(inputBuffer);
|
||||
if (inputBuffer.isEndOfStream()) {
|
||||
// Input buffers with no data that are also non-EOS, only carry the timestamp for a grid
|
||||
// tile. These buffers are not queued.
|
||||
boolean shouldQueueBuffer =
|
||||
checkNotNull(inputBuffer.data).remaining() > 0
|
||||
|| checkNotNull(inputBuffer).isEndOfStream();
|
||||
if (shouldQueueBuffer) {
|
||||
checkNotNull(decoder).queueInputBuffer(checkNotNull(inputBuffer));
|
||||
}
|
||||
if (checkNotNull(inputBuffer).isEndOfStream()) {
|
||||
inputStreamEnded = true;
|
||||
inputBuffer = null;
|
||||
return false;
|
||||
}
|
||||
inputBuffer = null;
|
||||
// If inputBuffer was queued, the decoder already cleared it. Otherwise, inputBuffer is
|
||||
// cleared here.
|
||||
if (shouldQueueBuffer) {
|
||||
inputBuffer = null;
|
||||
} else {
|
||||
checkNotNull(inputBuffer).clear();
|
||||
}
|
||||
return true;
|
||||
case C.RESULT_FORMAT_READ:
|
||||
inputFormat = checkNotNull(formatHolder.format);
|
||||
|
@ -15,9 +15,13 @@
|
||||
*/
|
||||
package androidx.media3.exoplayer.source.chunk;
|
||||
|
||||
import static androidx.media3.common.C.BUFFER_FLAG_KEY_FRAME;
|
||||
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.ParsableByteArray;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.datasource.DataSource;
|
||||
import androidx.media3.datasource.DataSourceUtil;
|
||||
@ -26,6 +30,7 @@ import androidx.media3.exoplayer.source.chunk.ChunkExtractor.TrackOutputProvider
|
||||
import androidx.media3.extractor.DefaultExtractorInput;
|
||||
import androidx.media3.extractor.Extractor;
|
||||
import androidx.media3.extractor.ExtractorInput;
|
||||
import androidx.media3.extractor.TrackOutput;
|
||||
import java.io.IOException;
|
||||
|
||||
/** A {@link BaseMediaChunk} that uses an {@link Extractor} to decode sample data. */
|
||||
@ -109,9 +114,9 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
||||
@SuppressWarnings("NonAtomicVolatileUpdate")
|
||||
@Override
|
||||
public final void load() throws IOException {
|
||||
BaseMediaChunkOutput output = getOutput();
|
||||
if (nextLoadPosition == 0) {
|
||||
// Configure the output and set it as the target for the extractor wrapper.
|
||||
BaseMediaChunkOutput output = getOutput();
|
||||
output.setSampleOffsetUs(sampleOffsetUs);
|
||||
chunkExtractor.init(
|
||||
getTrackOutputProvider(output),
|
||||
@ -127,6 +132,7 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
||||
// Load and decode the sample data.
|
||||
try {
|
||||
while (!loadCanceled && chunkExtractor.read(input)) {}
|
||||
maybeWriteEmptySamples(output);
|
||||
} finally {
|
||||
nextLoadPosition = input.getPosition() - dataSpec.position;
|
||||
}
|
||||
@ -146,4 +152,30 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
||||
protected TrackOutputProvider getTrackOutputProvider(BaseMediaChunkOutput baseMediaChunkOutput) {
|
||||
return baseMediaChunkOutput;
|
||||
}
|
||||
|
||||
private void maybeWriteEmptySamples(BaseMediaChunkOutput output) {
|
||||
if (!MimeTypes.isImage(trackFormat.containerMimeType)) {
|
||||
return;
|
||||
}
|
||||
if ((trackFormat.tileCountHorizontal <= 1 && trackFormat.tileCountVertical <= 1)
|
||||
|| trackFormat.tileCountHorizontal == Format.NO_VALUE
|
||||
|| trackFormat.tileCountVertical == Format.NO_VALUE) {
|
||||
return;
|
||||
}
|
||||
|
||||
TrackOutput trackOutput = output.track(/* id= */ 0, C.TRACK_TYPE_IMAGE);
|
||||
int tileCount = trackFormat.tileCountHorizontal * trackFormat.tileCountVertical;
|
||||
long tileDurationUs = (endTimeUs - startTimeUs) / tileCount;
|
||||
|
||||
for (int i = 1; i < tileCount; ++i) {
|
||||
long tileStartTimeUs = i * tileDurationUs;
|
||||
trackOutput.sampleData(new ParsableByteArray(), /* length= */ 0);
|
||||
trackOutput.sampleMetadata(
|
||||
tileStartTimeUs,
|
||||
/* flags= */ BUFFER_FLAG_KEY_FRAME,
|
||||
/* size= */ 0,
|
||||
/* offset= */ 0,
|
||||
/* cryptoData= */ null);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -27,6 +27,7 @@ import androidx.annotation.CheckResult;
|
||||
import androidx.annotation.Nullable;
|
||||
import androidx.media3.common.C;
|
||||
import androidx.media3.common.Format;
|
||||
import androidx.media3.common.MimeTypes;
|
||||
import androidx.media3.common.util.UnstableApi;
|
||||
import androidx.media3.common.util.UriUtil;
|
||||
import androidx.media3.common.util.Util;
|
||||
@ -852,6 +853,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
||||
dataSpec = cmcdData.addToDataSpec(dataSpec);
|
||||
}
|
||||
long sampleOffsetUs = -representation.presentationTimeOffsetUs;
|
||||
if (MimeTypes.isImage(trackFormat.sampleMimeType)) {
|
||||
sampleOffsetUs += startTimeUs;
|
||||
}
|
||||
return new ContainerMediaChunk(
|
||||
dataSource,
|
||||
dataSpec,
|
||||
|
Loading…
x
Reference in New Issue
Block a user