Add ability to queue bitmap by timestamp to the sampleConsumer
PiperOrigin-RevId: 557837922
This commit is contained in:
parent
a8944ef2f0
commit
dd0f88490c
@ -22,6 +22,7 @@ import androidx.media3.common.ColorInfo;
|
|||||||
import androidx.media3.common.OnInputFrameProcessedListener;
|
import androidx.media3.common.OnInputFrameProcessedListener;
|
||||||
import androidx.media3.common.util.UnstableApi;
|
import androidx.media3.common.util.UnstableApi;
|
||||||
import androidx.media3.decoder.DecoderInputBuffer;
|
import androidx.media3.decoder.DecoderInputBuffer;
|
||||||
|
import java.util.Iterator;
|
||||||
|
|
||||||
/** Consumer of encoded media samples, raw audio or raw video frames. */
|
/** Consumer of encoded media samples, raw audio or raw video frames. */
|
||||||
@UnstableApi
|
@UnstableApi
|
||||||
@ -77,10 +78,25 @@ public interface SampleConsumer {
|
|||||||
* @return Whether the {@link Bitmap} was successfully queued. If {@code false}, the caller should
|
* @return Whether the {@link Bitmap} was successfully queued. If {@code false}, the caller should
|
||||||
* try again later.
|
* try again later.
|
||||||
*/
|
*/
|
||||||
|
// TODO(b/262693274): Delete this method and usages in favor of the one below (Note it is not
|
||||||
|
// deprecated because transformer still relies on this method for frame duplication).
|
||||||
default boolean queueInputBitmap(Bitmap inputBitmap, long durationUs, int frameRate) {
|
default boolean queueInputBitmap(Bitmap inputBitmap, long durationUs, int frameRate) {
|
||||||
throw new UnsupportedOperationException();
|
throw new UnsupportedOperationException();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Attempts to provide an input {@link Bitmap} to the consumer.
|
||||||
|
*
|
||||||
|
* <p>Should only be used for image data.
|
||||||
|
*
|
||||||
|
* @param inputBitmap The {@link Bitmap} to queue to the consumer.
|
||||||
|
* @param inStreamOffsetsUs The times within the current stream that the bitmap should be
|
||||||
|
* displayed at. The timestamps should be monotonically increasing.
|
||||||
|
*/
|
||||||
|
default boolean queueInputBitmap(Bitmap inputBitmap, Iterator<Long> inStreamOffsetsUs) {
|
||||||
|
throw new UnsupportedOperationException();
|
||||||
|
}
|
||||||
|
|
||||||
// Methods to pass raw video input.
|
// Methods to pass raw video input.
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -39,6 +39,7 @@ import androidx.media3.decoder.DecoderInputBuffer;
|
|||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
import com.google.common.collect.ImmutableMap;
|
import com.google.common.collect.ImmutableMap;
|
||||||
import java.util.HashMap;
|
import java.util.HashMap;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.Map;
|
import java.util.Map;
|
||||||
import java.util.concurrent.atomic.AtomicInteger;
|
import java.util.concurrent.atomic.AtomicInteger;
|
||||||
@ -347,6 +348,38 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
sequenceAssetLoaderListener.onError(exportException);
|
sequenceAssetLoaderListener.onError(exportException);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Given an {@link Iterator}, creates an iterator that includes all the values in the original
|
||||||
|
* iterator (in the same order) up to and including the first occurrence of the {@code
|
||||||
|
* clippingValue}.
|
||||||
|
*/
|
||||||
|
private static final class ClippingIterator implements Iterator<Long> {
|
||||||
|
|
||||||
|
private final Iterator<Long> iterator;
|
||||||
|
private final long clippingValue;
|
||||||
|
private boolean hasReachedClippingValue;
|
||||||
|
|
||||||
|
public ClippingIterator(Iterator<Long> iterator, long clippingValue) {
|
||||||
|
this.iterator = iterator;
|
||||||
|
this.clippingValue = clippingValue;
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean hasNext() {
|
||||||
|
return !hasReachedClippingValue && iterator.hasNext();
|
||||||
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public Long next() {
|
||||||
|
checkState(hasNext());
|
||||||
|
Long next = iterator.next();
|
||||||
|
if (clippingValue == next) {
|
||||||
|
hasReachedClippingValue = true;
|
||||||
|
}
|
||||||
|
return next;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Classes accessed from AssetLoader threads.
|
// Classes accessed from AssetLoader threads.
|
||||||
|
|
||||||
private final class SampleConsumerWrapper implements SampleConsumer {
|
private final class SampleConsumerWrapper implements SampleConsumer {
|
||||||
@ -396,8 +429,6 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO(b/262693274): Test that concatenate 2 images or an image and a video works as expected
|
|
||||||
// once ImageAssetLoader implementation is complete.
|
|
||||||
@Override
|
@Override
|
||||||
public boolean queueInputBitmap(Bitmap inputBitmap, long durationUs, int frameRate) {
|
public boolean queueInputBitmap(Bitmap inputBitmap, long durationUs, int frameRate) {
|
||||||
if (isLooping && totalDurationUs + durationUs > maxSequenceDurationUs) {
|
if (isLooping && totalDurationUs + durationUs > maxSequenceDurationUs) {
|
||||||
@ -418,6 +449,33 @@ import java.util.concurrent.atomic.AtomicInteger;
|
|||||||
return sampleConsumer.queueInputBitmap(inputBitmap, durationUs, frameRate);
|
return sampleConsumer.queueInputBitmap(inputBitmap, durationUs, frameRate);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean queueInputBitmap(Bitmap inputBitmap, Iterator<Long> inStreamOffsetsUs) {
|
||||||
|
Iterator<Long> iteratorToUse = inStreamOffsetsUs;
|
||||||
|
if (isLooping) {
|
||||||
|
long durationLeftUs = maxSequenceDurationUs - totalDurationUs;
|
||||||
|
if (durationLeftUs <= 0) {
|
||||||
|
if (!videoLoopingEnded) {
|
||||||
|
videoLoopingEnded = true;
|
||||||
|
signalEndOfVideoInput();
|
||||||
|
}
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
while (inStreamOffsetsUs.hasNext()) {
|
||||||
|
long offsetUs = inStreamOffsetsUs.next();
|
||||||
|
if (totalDurationUs + offsetUs > maxSequenceDurationUs) {
|
||||||
|
if (!isMaxSequenceDurationUsFinal) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
iteratorToUse = new ClippingIterator(inStreamOffsetsUs, offsetUs);
|
||||||
|
videoLoopingEnded = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return sampleConsumer.queueInputBitmap(inputBitmap, iteratorToUse);
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
|
public void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
|
||||||
sampleConsumer.setOnInputFrameProcessedListener(listener);
|
sampleConsumer.setOnInputFrameProcessedListener(listener);
|
||||||
|
@ -39,6 +39,7 @@ import androidx.media3.common.util.Consumer;
|
|||||||
import androidx.media3.common.util.Size;
|
import androidx.media3.common.util.Size;
|
||||||
import androidx.media3.effect.Presentation;
|
import androidx.media3.effect.Presentation;
|
||||||
import com.google.common.collect.ImmutableList;
|
import com.google.common.collect.ImmutableList;
|
||||||
|
import java.util.Iterator;
|
||||||
import java.util.List;
|
import java.util.List;
|
||||||
import java.util.concurrent.Executor;
|
import java.util.concurrent.Executor;
|
||||||
import java.util.concurrent.atomic.AtomicLong;
|
import java.util.concurrent.atomic.AtomicLong;
|
||||||
@ -173,6 +174,12 @@ import java.util.concurrent.atomic.AtomicLong;
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Override
|
||||||
|
public boolean queueInputBitmap(Bitmap inputBitmap, Iterator<Long> inStreamOffsetsUs) {
|
||||||
|
videoFrameProcessor.queueInputBitmap(inputBitmap, inStreamOffsetsUs);
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
@Override
|
@Override
|
||||||
public void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
|
public void setOnInputFrameProcessedListener(OnInputFrameProcessedListener listener) {
|
||||||
videoFrameProcessor.setOnInputFrameProcessedListener(listener);
|
videoFrameProcessor.setOnInputFrameProcessedListener(listener);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user