mirror of
https://github.com/samsonjs/media.git
synced 2026-04-10 12:05:47 +00:00
Add extensions package to V2.
- Not doing any renaming for now. It'll be easier to wait until after the extensions themselves are brought across. ------------- Created by MOE: https://github.com/google/moe MOE_MIGRATED_REVID=117438338
This commit is contained in:
parent
3c5a509af8
commit
ed4f83979e
5 changed files with 454 additions and 0 deletions
|
|
@ -0,0 +1,50 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.util.extensions;
|
||||
|
||||
/**
|
||||
* Base class for {@link Decoder} buffers with flags.
|
||||
*/
|
||||
public abstract class Buffer {
|
||||
|
||||
/**
|
||||
* Flag for empty input/output buffers that signal that the end of the stream was reached.
|
||||
*/
|
||||
public static final int FLAG_END_OF_STREAM = 1;
|
||||
/**
|
||||
* Flag for non-empty input buffers which signals that the decoder must be reset before decoding.
|
||||
*/
|
||||
public static final int FLAG_RESET = 2;
|
||||
/**
|
||||
* Flag for non-empty input/output buffers that should only be decoded (not rendered).
|
||||
*/
|
||||
public static final int FLAG_DECODE_ONLY = 4;
|
||||
|
||||
private int flags;
|
||||
|
||||
public void reset() {
|
||||
flags = 0;
|
||||
}
|
||||
|
||||
public final void setFlag(int flag) {
|
||||
flags |= flag;
|
||||
}
|
||||
|
||||
public final boolean getFlag(int flag) {
|
||||
return (flags & flag) == flag;
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,63 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.util.extensions;
|
||||
|
||||
/**
|
||||
* A media decoder.
|
||||
*
|
||||
* @param <I> The type of buffer input to the decoder.
|
||||
* @param <O> The type of buffer output from the decoder.
|
||||
* @param <E> The type of exception thrown from the decoder.
|
||||
*/
|
||||
public interface Decoder<I, O, E extends Exception> {
|
||||
|
||||
/**
|
||||
* Dequeues the next input buffer to be filled and queued to the decoder.
|
||||
*
|
||||
* @return The input buffer, or null if an input buffer isn't available.
|
||||
* @throws E If a decoder error has occurred.
|
||||
*/
|
||||
I dequeueInputBuffer() throws E;
|
||||
|
||||
/**
|
||||
* Queues an input buffer to the decoder.
|
||||
*
|
||||
* @param inputBuffer The input buffer.
|
||||
* @throws E If a decoder error has occurred.
|
||||
*/
|
||||
void queueInputBuffer(I inputBuffer) throws E;
|
||||
|
||||
/**
|
||||
* Dequeues the next output buffer from the decoder.
|
||||
*
|
||||
* @return The output buffer, or null if an output buffer isn't available.
|
||||
* @throws E If a decoder error has occurred.
|
||||
*/
|
||||
O dequeueOutputBuffer() throws E;
|
||||
|
||||
/**
|
||||
* Flushes input/output buffers that have not been dequeued yet and returns ownership of any
|
||||
* dequeued input buffer to the decoder. Flushes any pending output currently in the decoder. The
|
||||
* caller is still responsible for releasing any dequeued output buffers.
|
||||
*/
|
||||
void flush();
|
||||
|
||||
/**
|
||||
* Releases the decoder. Must be called when the decoder is no longer needed.
|
||||
*/
|
||||
void release();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,37 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.util.extensions;
|
||||
|
||||
import com.google.android.exoplayer.SampleHolder;
|
||||
|
||||
/**
|
||||
* Input buffer to be decoded by a {@link Decoder}.
|
||||
*/
|
||||
public class InputBuffer extends Buffer {
|
||||
|
||||
public final SampleHolder sampleHolder;
|
||||
|
||||
public InputBuffer() {
|
||||
sampleHolder = new SampleHolder(SampleHolder.BUFFER_REPLACEMENT_MODE_DIRECT);
|
||||
}
|
||||
|
||||
@Override
|
||||
public void reset() {
|
||||
super.reset();
|
||||
sampleHolder.clearData();
|
||||
}
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,33 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.util.extensions;
|
||||
|
||||
/**
|
||||
* Output buffer decoded by a {@link Decoder}.
|
||||
*/
|
||||
public abstract class OutputBuffer extends Buffer {
|
||||
|
||||
/**
|
||||
* The presentation timestamp for the buffer, in microseconds.
|
||||
*/
|
||||
public long timestampUs;
|
||||
|
||||
/**
|
||||
* Releases the output buffer for reuse. Must be called when the buffer is no longer needed.
|
||||
*/
|
||||
public abstract void release();
|
||||
|
||||
}
|
||||
|
|
@ -0,0 +1,271 @@
|
|||
/*
|
||||
* Copyright (C) 2014 The Android Open Source Project
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
package com.google.android.exoplayer.util.extensions;
|
||||
|
||||
import com.google.android.exoplayer.util.Assertions;
|
||||
|
||||
import java.util.LinkedList;
|
||||
|
||||
/**
|
||||
* Base class for {@link Decoder}s that use their own decode thread.
|
||||
*/
|
||||
public abstract class SimpleDecoder<I extends InputBuffer, O extends OutputBuffer,
|
||||
E extends Exception> extends Thread implements Decoder<I, O, E> {
|
||||
|
||||
/**
|
||||
* Listener for {@link SimpleDecoder} events.
|
||||
*/
|
||||
public interface EventListener<E> {
|
||||
|
||||
/**
|
||||
* Invoked when the decoder encounters an error.
|
||||
*
|
||||
* @param e The corresponding exception.
|
||||
*/
|
||||
void onDecoderError(E e);
|
||||
|
||||
}
|
||||
|
||||
private final Object lock;
|
||||
private final LinkedList<I> queuedInputBuffers;
|
||||
private final LinkedList<O> queuedOutputBuffers;
|
||||
private final I[] availableInputBuffers;
|
||||
private final O[] availableOutputBuffers;
|
||||
|
||||
private int availableInputBufferCount;
|
||||
private int availableOutputBufferCount;
|
||||
private I dequeuedInputBuffer;
|
||||
|
||||
private E exception;
|
||||
private boolean flushDecodedOutputBuffer;
|
||||
private boolean released;
|
||||
|
||||
/**
|
||||
* @param inputBuffers An array of nulls that will be used to store references to input buffers.
|
||||
* @param outputBuffers An array of nulls that will be used to store references to output buffers.
|
||||
*/
|
||||
protected SimpleDecoder(I[] inputBuffers, O[] outputBuffers) {
|
||||
lock = new Object();
|
||||
queuedInputBuffers = new LinkedList<>();
|
||||
queuedOutputBuffers = new LinkedList<>();
|
||||
availableInputBuffers = inputBuffers;
|
||||
availableInputBufferCount = inputBuffers.length;
|
||||
for (int i = 0; i < availableInputBufferCount; i++) {
|
||||
availableInputBuffers[i] = createInputBuffer();
|
||||
}
|
||||
availableOutputBuffers = outputBuffers;
|
||||
availableOutputBufferCount = outputBuffers.length;
|
||||
for (int i = 0; i < availableOutputBufferCount; i++) {
|
||||
availableOutputBuffers[i] = createOutputBuffer();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Sets the initial size of each input buffer.
|
||||
* <p>
|
||||
* This method should only be called before the decoder is used (i.e. before the first call to
|
||||
* {@link #dequeueInputBuffer()}.
|
||||
*
|
||||
* @param size The required input buffer size.
|
||||
*/
|
||||
protected final void setInitialInputBufferSize(int size) {
|
||||
Assertions.checkState(availableInputBufferCount == availableInputBuffers.length);
|
||||
for (int i = 0; i < availableInputBuffers.length; i++) {
|
||||
availableInputBuffers[i].sampleHolder.ensureSpaceForWrite(size);
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final I dequeueInputBuffer() throws E {
|
||||
synchronized (lock) {
|
||||
maybeThrowException();
|
||||
Assertions.checkState(dequeuedInputBuffer == null);
|
||||
if (availableInputBufferCount == 0) {
|
||||
return null;
|
||||
}
|
||||
I inputBuffer = availableInputBuffers[--availableInputBufferCount];
|
||||
inputBuffer.reset();
|
||||
dequeuedInputBuffer = inputBuffer;
|
||||
return inputBuffer;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void queueInputBuffer(I inputBuffer) throws E {
|
||||
synchronized (lock) {
|
||||
maybeThrowException();
|
||||
Assertions.checkArgument(inputBuffer == dequeuedInputBuffer);
|
||||
queuedInputBuffers.addLast(inputBuffer);
|
||||
maybeNotifyDecodeLoop();
|
||||
dequeuedInputBuffer = null;
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final O dequeueOutputBuffer() throws E {
|
||||
synchronized (lock) {
|
||||
maybeThrowException();
|
||||
if (queuedOutputBuffers.isEmpty()) {
|
||||
return null;
|
||||
}
|
||||
return queuedOutputBuffers.removeFirst();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Releases an output buffer back to the decoder.
|
||||
*
|
||||
* @param outputBuffer The output buffer being released.
|
||||
*/
|
||||
protected void releaseOutputBuffer(O outputBuffer) {
|
||||
synchronized (lock) {
|
||||
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
||||
maybeNotifyDecodeLoop();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void flush() {
|
||||
synchronized (lock) {
|
||||
flushDecodedOutputBuffer = true;
|
||||
if (dequeuedInputBuffer != null) {
|
||||
availableInputBuffers[availableInputBufferCount++] = dequeuedInputBuffer;
|
||||
dequeuedInputBuffer = null;
|
||||
}
|
||||
while (!queuedInputBuffers.isEmpty()) {
|
||||
availableInputBuffers[availableInputBufferCount++] = queuedInputBuffers.removeFirst();
|
||||
}
|
||||
while (!queuedOutputBuffers.isEmpty()) {
|
||||
availableOutputBuffers[availableOutputBufferCount++] = queuedOutputBuffers.removeFirst();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public void release() {
|
||||
synchronized (lock) {
|
||||
released = true;
|
||||
lock.notify();
|
||||
}
|
||||
try {
|
||||
join();
|
||||
} catch (InterruptedException e) {
|
||||
Thread.currentThread().interrupt();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Throws a decode exception, if there is one.
|
||||
*
|
||||
* @throws E The decode exception.
|
||||
*/
|
||||
private void maybeThrowException() throws E {
|
||||
if (exception != null) {
|
||||
throw exception;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Notifies the decode loop if there exists a queued input buffer and an available output buffer
|
||||
* to decode into.
|
||||
* <p>
|
||||
* Should only be called whilst synchronized on the lock object.
|
||||
*/
|
||||
private void maybeNotifyDecodeLoop() {
|
||||
if (canDecodeBuffer()) {
|
||||
lock.notify();
|
||||
}
|
||||
}
|
||||
|
||||
@Override
|
||||
public final void run() {
|
||||
try {
|
||||
while (decode()) {
|
||||
// Do nothing.
|
||||
}
|
||||
} catch (InterruptedException e) {
|
||||
// Not expected.
|
||||
throw new IllegalStateException(e);
|
||||
}
|
||||
}
|
||||
|
||||
private boolean decode() throws InterruptedException {
|
||||
I inputBuffer;
|
||||
O outputBuffer;
|
||||
|
||||
// Wait until we have an input buffer to decode, and an output buffer to decode into.
|
||||
synchronized (lock) {
|
||||
while (!released && !canDecodeBuffer()) {
|
||||
lock.wait();
|
||||
}
|
||||
if (released) {
|
||||
return false;
|
||||
}
|
||||
inputBuffer = queuedInputBuffers.removeFirst();
|
||||
outputBuffer = availableOutputBuffers[--availableOutputBufferCount];
|
||||
flushDecodedOutputBuffer = false;
|
||||
}
|
||||
|
||||
exception = decode(inputBuffer, outputBuffer);
|
||||
if (exception != null) {
|
||||
// Memory barrier to ensure that the decoder exception is visible from the playback thread.
|
||||
synchronized (lock) {}
|
||||
return false;
|
||||
}
|
||||
|
||||
boolean decodeOnly = outputBuffer.getFlag(Buffer.FLAG_DECODE_ONLY);
|
||||
synchronized (lock) {
|
||||
if (flushDecodedOutputBuffer || decodeOnly) {
|
||||
// If a flush occurred while decoding or the buffer was only for decoding (not presentation)
|
||||
// then make the output buffer available again rather than queueing it to be consumed.
|
||||
availableOutputBuffers[availableOutputBufferCount++] = outputBuffer;
|
||||
} else {
|
||||
// Queue the decoded output buffer to be consumed.
|
||||
queuedOutputBuffers.addLast(outputBuffer);
|
||||
}
|
||||
// Make the input buffer available again.
|
||||
availableInputBuffers[availableInputBufferCount++] = inputBuffer;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
private boolean canDecodeBuffer() {
|
||||
return !queuedInputBuffers.isEmpty() && availableOutputBufferCount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new input buffer.
|
||||
*/
|
||||
protected abstract I createInputBuffer();
|
||||
|
||||
/**
|
||||
* Creates a new output buffer.
|
||||
*/
|
||||
protected abstract O createOutputBuffer();
|
||||
|
||||
/**
|
||||
* Decodes the {@code inputBuffer} and stores any decoded output in {@code outputBuffer}.
|
||||
*
|
||||
* @param inputBuffer The buffer to decode.
|
||||
* @param outputBuffer The output buffer to store decoded data. If the flag
|
||||
* {@link Buffer#FLAG_DECODE_ONLY} is set after this method returns, any output should not be
|
||||
* presented.
|
||||
* @return A decode exception if an error occurred, or null if the decode was successful.
|
||||
*/
|
||||
protected abstract E decode(I inputBuffer, O outputBuffer);
|
||||
|
||||
}
|
||||
Loading…
Reference in a new issue