mirror of
https://github.com/androidx/media.git
synced 2025-04-30 06:46:50 +08:00
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;
|
return false;
|
||||||
case C.RESULT_BUFFER_READ:
|
case C.RESULT_BUFFER_READ:
|
||||||
inputBuffer.flip();
|
inputBuffer.flip();
|
||||||
checkNotNull(decoder).queueInputBuffer(inputBuffer);
|
// Input buffers with no data that are also non-EOS, only carry the timestamp for a grid
|
||||||
if (inputBuffer.isEndOfStream()) {
|
// 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;
|
inputStreamEnded = true;
|
||||||
inputBuffer = null;
|
inputBuffer = null;
|
||||||
return false;
|
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;
|
return true;
|
||||||
case C.RESULT_FORMAT_READ:
|
case C.RESULT_FORMAT_READ:
|
||||||
inputFormat = checkNotNull(formatHolder.format);
|
inputFormat = checkNotNull(formatHolder.format);
|
||||||
|
@ -15,9 +15,13 @@
|
|||||||
*/
|
*/
|
||||||
package androidx.media3.exoplayer.source.chunk;
|
package androidx.media3.exoplayer.source.chunk;
|
||||||
|
|
||||||
|
import static androidx.media3.common.C.BUFFER_FLAG_KEY_FRAME;
|
||||||
|
|
||||||
import androidx.annotation.Nullable;
|
import androidx.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
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.common.util.UnstableApi;
|
||||||
import androidx.media3.datasource.DataSource;
|
import androidx.media3.datasource.DataSource;
|
||||||
import androidx.media3.datasource.DataSourceUtil;
|
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.DefaultExtractorInput;
|
||||||
import androidx.media3.extractor.Extractor;
|
import androidx.media3.extractor.Extractor;
|
||||||
import androidx.media3.extractor.ExtractorInput;
|
import androidx.media3.extractor.ExtractorInput;
|
||||||
|
import androidx.media3.extractor.TrackOutput;
|
||||||
import java.io.IOException;
|
import java.io.IOException;
|
||||||
|
|
||||||
/** A {@link BaseMediaChunk} that uses an {@link Extractor} to decode sample data. */
|
/** A {@link BaseMediaChunk} that uses an {@link Extractor} to decode sample data. */
|
||||||
@ -109,9 +114,9 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
@SuppressWarnings("NonAtomicVolatileUpdate")
|
@SuppressWarnings("NonAtomicVolatileUpdate")
|
||||||
@Override
|
@Override
|
||||||
public final void load() throws IOException {
|
public final void load() throws IOException {
|
||||||
|
BaseMediaChunkOutput output = getOutput();
|
||||||
if (nextLoadPosition == 0) {
|
if (nextLoadPosition == 0) {
|
||||||
// Configure the output and set it as the target for the extractor wrapper.
|
// Configure the output and set it as the target for the extractor wrapper.
|
||||||
BaseMediaChunkOutput output = getOutput();
|
|
||||||
output.setSampleOffsetUs(sampleOffsetUs);
|
output.setSampleOffsetUs(sampleOffsetUs);
|
||||||
chunkExtractor.init(
|
chunkExtractor.init(
|
||||||
getTrackOutputProvider(output),
|
getTrackOutputProvider(output),
|
||||||
@ -127,6 +132,7 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
// Load and decode the sample data.
|
// Load and decode the sample data.
|
||||||
try {
|
try {
|
||||||
while (!loadCanceled && chunkExtractor.read(input)) {}
|
while (!loadCanceled && chunkExtractor.read(input)) {}
|
||||||
|
maybeWriteEmptySamples(output);
|
||||||
} finally {
|
} finally {
|
||||||
nextLoadPosition = input.getPosition() - dataSpec.position;
|
nextLoadPosition = input.getPosition() - dataSpec.position;
|
||||||
}
|
}
|
||||||
@ -146,4 +152,30 @@ public class ContainerMediaChunk extends BaseMediaChunk {
|
|||||||
protected TrackOutputProvider getTrackOutputProvider(BaseMediaChunkOutput baseMediaChunkOutput) {
|
protected TrackOutputProvider getTrackOutputProvider(BaseMediaChunkOutput baseMediaChunkOutput) {
|
||||||
return 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.annotation.Nullable;
|
||||||
import androidx.media3.common.C;
|
import androidx.media3.common.C;
|
||||||
import androidx.media3.common.Format;
|
import androidx.media3.common.Format;
|
||||||
|
import androidx.media3.common.MimeTypes;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.common.util.UriUtil;
|
import androidx.media3.common.util.UriUtil;
|
||||||
import androidx.media3.common.util.Util;
|
import androidx.media3.common.util.Util;
|
||||||
@ -852,6 +853,9 @@ public class DefaultDashChunkSource implements DashChunkSource {
|
|||||||
dataSpec = cmcdData.addToDataSpec(dataSpec);
|
dataSpec = cmcdData.addToDataSpec(dataSpec);
|
||||||
}
|
}
|
||||||
long sampleOffsetUs = -representation.presentationTimeOffsetUs;
|
long sampleOffsetUs = -representation.presentationTimeOffsetUs;
|
||||||
|
if (MimeTypes.isImage(trackFormat.sampleMimeType)) {
|
||||||
|
sampleOffsetUs += startTimeUs;
|
||||||
|
}
|
||||||
return new ContainerMediaChunk(
|
return new ContainerMediaChunk(
|
||||||
dataSource,
|
dataSource,
|
||||||
dataSpec,
|
dataSpec,
|
||||||
|
Loading…
x
Reference in New Issue
Block a user