Я пытаюсь создать асинхронный декодер, который считывает кадры из очереди, которая записывается экстрактором мультимедиа, который заполняет ее пакетами, считанными из файла MP4.
public class AsynchronousDecoder {
private static String TAG = "AsynchronousDecoder";
public final int MAX_FRAMES = 30;
final Queue<Frame> inputFrames = new LinkedList<>();
private MediaFormat mediaFormat;
private String mime;
private MediaFormat mOutputFormat;
MediaCodec codec;
MediaCodec.BufferInfo info;
void setFormat(MediaFormat mediaFormat) {
this.mediaFormat = mediaFormat;
}
void setMime(String mime) {
this.mime = mime;
}
void begin() throws IOException {
MediaCodecList mediaCodecList = new MediaCodecList(MediaCodecList.ALL_CODECS);
String name = mediaCodecList.findDecoderForFormat(this.mediaFormat);
codec = MediaCodec.createByCodecName(name);
info = new MediaCodec.BufferInfo();
codec.setCallback(new MediaCodec.Callback() {
@Override
public void onInputBufferAvailable(MediaCodec mediaCodec, int inputBufferId) {
ByteBuffer inputBuffer = mediaCodec.getInputBuffer(inputBufferId);
// fill inputBuffer with valid data
Frame frame = null;
synchronized (inputFrames) {
if (inputFrames.size()>0) {
frame = inputFrames.element();
}
}
if (frame != null) {
assert inputBuffer != null;
int offset = 0;
int flags = BUFFER_FLAG_KEY_FRAME;
try {
inputBuffer.clear();
inputBuffer.put(frame.byteBuffer);
Log.d(TAG, "gonna queue frame of capacity " + frame.byteBuffer.capacity());
Log.d(TAG, "inputBuffer has capacity " + inputBuffer.capacity());
Log.d(TAG, "gonna queue input buffer of id " + inputBufferId);
codec.queueInputBuffer(inputBufferId,
offset,
frame.byteBuffer.capacity(),
frame.presentationTimeUs,
flags);
} catch (Exception e) {
e.printStackTrace();
}
}
}
@Override
public void onOutputBufferAvailable(MediaCodec mediaCodec, int outputBufferId, MediaCodec.BufferInfo info) {
ByteBuffer outputBuffer = codec.getOutputBuffer(outputBufferId);
MediaFormat bufferFormat = codec.getOutputFormat(outputBufferId); // option A
// bufferFormat is equivalent to mOutputFormat
// outputBuffer is ready to be processed or rendered.
Log.d(TAG, "onOutputBufferAvailable!, bufferFormat: " + bufferFormat);
//false means do not send to surface
codec.releaseOutputBuffer(outputBufferId, false);
}
@Override
public void onOutputFormatChanged(MediaCodec mediaCodec, MediaFormat mediaFormat) {
// Subsequent data will conform to new format.
// Can ignore if using getOutputFormat(outputBufferId)
Log.d(TAG, "onOutputFormatChanged: " + mediaFormat);
mOutputFormat = mediaFormat; // option B
}
@Override
public void onError(MediaCodec mc, MediaCodec.CodecException codecException) {
Log.d(TAG, codecException.toString());
}
});
if (mediaFormat!=null) {
Log.d(TAG, "configuring with mediaFormat " + mediaFormat.toString());
codec.configure(mediaFormat, null, null, 0);
} else {
Log.d(TAG, "EXCEPTION: mediaFormat is null");
//throw Exception("")
}
mOutputFormat = codec.getOutputFormat(); // option B
codec.start();
Log.d(TAG, "codec started");
// wait for processing to complete
try
{
//TODO: make it wait for EOF
Thread.sleep(1000000);
}
catch(InterruptedException ex)
{
Thread.currentThread().interrupt();
}
codec.stop();
codec.release();
}
}
Вот что я получение:
2020-07-10 22:18:00.878 28876-28876/com.something.mediacodecdecoderexample D/AsynchronousDecoder: gonna queue frame of capacity 100000
2020-07-10 22:18:00.878 28876-28876/com.something.mediacodecdecoderexample D/AsynchronousDecoder: inputBuffer has capacity 8192
2020-07-10 22:18:00.878 28876-28876/com.something.mediacodecdecoderexample D/AsynchronousDecoder: gonna queue input buffer of id 3
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: java.lang.IllegalArgumentException
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.media.MediaCodec.native_queueInputBuffer(Native Method)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.media.MediaCodec.queueInputBuffer(MediaCodec.java:2342)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at com.something.mediacodecdecoderexample.AsynchronousDecoder$1.onInputBufferAvailable(AsynchronousDecoder.java:62)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.media.MediaCodec$EventHandler.handleCallback(MediaCodec.java:1668)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.media.MediaCodec$EventHandler.handleMessage(MediaCodec.java:1626)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.os.Handler.dispatchMessage(Handler.java:105)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.os.Looper.loop(Looper.java:164)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at android.app.ActivityThread.main(ActivityThread.java:6617)
2020-07-10 22:18:00.879 28876-28876/com.something.mediacodecdecoderexample W/System.err: at java.lang.reflect.Method.invoke(Native Method)
2020-07-10 22:18:00.880 28876-28876/com.something.mediacodecdecoderexample W/System.err: at com.android.internal.os.Zygote$MethodAndArgsCaller.run(Zygote.java:240)
2020-07-10 22:18:00.880 28876-28876/com.something.mediacodecdecoderexample W/System.err: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:769)
Я не понимаю, что делаю не так. Я думал, что это связано с тем, что я использовал codec
вместо mediaCodec
, переданного в обратный вызов, но я просто звоню, как Google показывает в документации MediaCode c. Я изменился, и это не помогло.