peertube-live-streaming/encoder/src/main/java/com/pedro/encoder/BaseEncoder.java

126 lines
4.0 KiB
Java

package com.pedro.encoder;
import android.media.MediaCodec;
import android.media.MediaCodecInfo;
import android.media.MediaFormat;
import android.os.Build;
import androidx.annotation.NonNull;
import com.pedro.encoder.utils.CodecUtil;
import java.nio.ByteBuffer;
/**
* Created by pedro on 18/09/19.
*/
public abstract class BaseEncoder implements EncoderCallback {
private static final String TAG = "BaseEncoder";
private MediaCodec.BufferInfo bufferInfo = new MediaCodec.BufferInfo();
protected MediaCodec codec;
protected long presentTimeUs;
protected volatile boolean running = false;
protected boolean isBufferMode = true;
protected CodecUtil.Force force = CodecUtil.Force.FIRST_COMPATIBLE_FOUND;
public void start() {
start(true);
}
public abstract void start(boolean resetTs);
protected abstract void stopImp();
public void stop() {
running = false;
stopImp();
try {
codec.stop();
codec.release();
codec = null;
} catch (IllegalStateException | NullPointerException e) {
codec = null;
}
}
protected abstract MediaCodecInfo chooseEncoder(String mime);
protected void getDataFromEncoder(Frame frame) throws IllegalStateException {
if (isBufferMode) {
int inBufferIndex = codec.dequeueInputBuffer(0);
if (inBufferIndex >= 0) {
inputAvailable(codec, inBufferIndex, frame);
}
}
for (; running; ) {
int outBufferIndex = codec.dequeueOutputBuffer(bufferInfo, 0);
if (outBufferIndex == MediaCodec.INFO_OUTPUT_FORMAT_CHANGED) {
MediaFormat mediaFormat = codec.getOutputFormat();
formatChanged(codec, mediaFormat);
} else if (outBufferIndex >= 0) {
outputAvailable(codec, outBufferIndex, bufferInfo);
} else {
break;
}
}
}
protected abstract Frame getInputFrame() throws InterruptedException;
private void processInput(@NonNull ByteBuffer byteBuffer, @NonNull MediaCodec mediaCodec,
int inBufferIndex, Frame frame) throws IllegalStateException {
try {
if (frame == null) frame = getInputFrame();
byteBuffer.clear();
byteBuffer.put(frame.getBuffer(), frame.getOffset(), frame.getSize());
long pts = System.nanoTime() / 1000 - presentTimeUs;
mediaCodec.queueInputBuffer(inBufferIndex, 0, frame.getSize(), pts, 0);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
}
}
protected abstract void checkBuffer(@NonNull ByteBuffer byteBuffer,
@NonNull MediaCodec.BufferInfo bufferInfo);
protected abstract void sendBuffer(@NonNull ByteBuffer byteBuffer,
@NonNull MediaCodec.BufferInfo bufferInfo);
private void processOutput(@NonNull ByteBuffer byteBuffer, @NonNull MediaCodec mediaCodec,
int outBufferIndex, @NonNull MediaCodec.BufferInfo bufferInfo) throws IllegalStateException {
checkBuffer(byteBuffer, bufferInfo);
sendBuffer(byteBuffer, bufferInfo);
mediaCodec.releaseOutputBuffer(outBufferIndex, false);
}
public void setForce(CodecUtil.Force force) {
this.force = force;
}
public boolean isRunning() {
return running;
}
@Override
public void inputAvailable(@NonNull MediaCodec mediaCodec, int inBufferIndex, Frame frame)
throws IllegalStateException {
ByteBuffer byteBuffer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
byteBuffer = mediaCodec.getInputBuffer(inBufferIndex);
} else {
byteBuffer = mediaCodec.getInputBuffers()[inBufferIndex];
}
processInput(byteBuffer, mediaCodec, inBufferIndex, frame);
}
@Override
public void outputAvailable(@NonNull MediaCodec mediaCodec, int outBufferIndex,
@NonNull MediaCodec.BufferInfo bufferInfo) throws IllegalStateException {
ByteBuffer byteBuffer;
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
byteBuffer = mediaCodec.getOutputBuffer(outBufferIndex);
} else {
byteBuffer = mediaCodec.getOutputBuffers()[outBufferIndex];
}
processOutput(byteBuffer, mediaCodec, outBufferIndex, bufferInfo);
}
}