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:
olly 2016-03-17 05:48:54 -07:00 committed by Oliver Woodman
parent 3c5a509af8
commit ed4f83979e
5 changed files with 454 additions and 0 deletions

View file

@ -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;
}
}

View file

@ -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();
}

View file

@ -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();
}
}

View file

@ -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();
}

View file

@ -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);
}