我尝试在Android上使用MediaConfig解码简单的H.264视频流。它只是在第一个数据包上抛出一个例外,对于我的生命,我无法理解为什么。
这是最小的代码。它所做的只是获取编解码器,启动解码器,获取输入缓冲区,填充并提交。但是在调试设备上,我得到了UnsupportedOperationException(也在下面)。
这一直在推动我吃香蕉,在认识到它根本没有进行任何视频解码之前,花了一天时间在模拟器上没有帮助。
代码(除问题外几乎除外):
package com.AndroidH264VideoTest;
import android.app.Activity;
import android.os.Bundle;
import android.media.MediaCodec;
import android.media.MediaFormat;
import java.nio.ByteBuffer;
public class AndroidH264VideoTest extends Activity
{
private static final int SHORT_TIMEOUT = 1; // Provide some timeout to getting a buffer
private MediaCodec m_decoder = null;
private ByteBuffer[] m_decoderInputBuffers;
@Override
public void onCreate(Bundle savedInstanceState)
{
super.onCreate(savedInstanceState);
String MIME_TYPE = "video/avc"; // This is the type for H.264
int TEST_WIDTH = 8; // Our test image is 8x8 pixels
int TEST_HEIGHT = 8;
m_decoder = MediaCodec.createDecoderByType(MIME_TYPE);
MediaFormat decoderFormat = MediaFormat.createVideoFormat(MIME_TYPE, TEST_WIDTH, TEST_HEIGHT);
m_decoder.configure(decoderFormat, null, null, 0); // bytebuffer input/output
m_decoder.start();
m_decoderInputBuffers = m_decoder.getInputBuffers();
}
@Override
public void onResume()
{
byte SPS_PACKET[] =
{
(byte)0x00, (byte)0x00, (byte)0x00, (byte)0x01, // NAL header identifier
(byte)0x67, // NAL info - (byte)0x67 = 0 11 00111 = type 7 = SPS (1st packet)
(byte)0x42, // SPS profile_idc = (byte)0x42/66 - Baseline. Should be decodable by anything
(byte)0xC0, // Constrained - should be even more decodable.
(byte)0x0A, // SPS level_idc = (byte)0x0a/10
(byte)0xDA, (byte)0x7E, (byte)0x59, (byte)0x66, (byte)0xA0, (byte)0xC0, (byte)0x20,
(byte)0xC8, (byte)0x00, (byte)0x00, (byte)0x03, (byte)0x00, (byte)0x08, (byte)0x00, (byte)0x00,
(byte)0x03, (byte)0x03, (byte)0xc4, (byte)0x78, (byte)0x91, (byte)0x35,
};
super.onResume(); // Always call the superclass method first
// Take ownership of buffer
int inputBufferId = m_decoder.dequeueInputBuffer(SHORT_TIMEOUT);
if (inputBufferId < 0)
{
// No buffer available error
return;
}
// Copy data to buffer
m_decoderInputBuffers[inputBufferId] = ByteBuffer.wrap(SPS_PACKET);
// Submit buffer for processing
m_decoder.queueInputBuffer(inputBufferId, 0, SPS_PACKET.length, 0, MediaCodec.BUFFER_FLAG_SYNC_FRAME);
}
}
所以,这应该是无害的。不会做任何事情,因为我只通过了一个NAL数据包,但它不应该抱怨。
但是,在我的Marshmallow测试设备上会发生这种情况:
8-21 16:21:45.295 21871 21871 V ActivityThread: Performing resume of ActivityRecord{fa15f01 token=android.os.BinderProxy@e6df1a6 {com.AndroidH264VideoTest.AndroidH264VideoTest/com.AndroidH264VideoTest.AndroidH264VideoTest}}
08-21 16:21:45.296 21871 21871 D AndroidRuntime: Shutting down VM
--------- beginning of crash
08-21 16:21:45.297 21871 21871 E AndroidRuntime: FATAL EXCEPTION: main
08-21 16:21:45.297 21871 21871 E AndroidRuntime: Process: com.AndroidH264VideoTest.AndroidH264VideoTest, PID: 21871
08-21 16:21:45.297 21871 21871 E AndroidRuntime: java.lang.RuntimeException: Unable to resume activity {com.AndroidH264VideoTest.AndroidH264VideoTest/com.AndroidH264VideoTest.AndroidH264VideoTest}: java.lang.UnsupportedOperationException
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3325)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.handleResumeActivity(ActivityThread.java:3356)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2670)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.-wrap11(ActivityThread.java)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1499)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.os.Handler.dispatchMessage(Handler.java:111)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.os.Looper.loop(Looper.java:207)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.main(ActivityThread.java:5765)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at java.lang.reflect.Method.invoke(Native Method)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:789)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:679)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: Caused by: java.lang.UnsupportedOperationException
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at java.nio.ByteBuffer.setAccessible(ByteBuffer.java:636)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.media.MediaCodec.invalidateByteBuffer(MediaCodec.java:2646)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.media.MediaCodec.queueInputBuffer(MediaCodec.java:2174)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at com.AndroidH264VideoTest.AndroidH264VideoTest.onResume(AndroidH264VideoTest.java:68)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.Instrumentation.callActivityOnResume(Instrumentation.java:1268)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.Activity.performResume(Activity.java:6392)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: at android.app.ActivityThread.performResumeActivity(ActivityThread.java:3310)
08-21 16:21:45.297 21871 21871 E AndroidRuntime: ... 10 more
那么,为什么queueInputBuffer()中的不支持操作?
更新:奇怪的是在另一台设备上(Android 4.4.4 KitKat,S4 mini)我收到了不同的错误消息,但它仍然爆炸:
E/AndroidRuntime(25080): FATAL EXCEPTION: main
E/AndroidRuntime(25080): Process: com.AndroidH264VideoTest.AndroidH264VideoTest, PID: 25080
E/AndroidRuntime(25080): java.lang.RuntimeException: Unable to start activity ComponentInfo{com.AndroidH264VideoTest.AndroidH264VideoTest/com.AndroidH264VideoTest.AndroidH264VideoTest}: java.lang.IllegalStateException
E/AndroidRuntime(25080): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2548)
E/AndroidRuntime(25080): at android.app.ActivityThread.handleLaunchActivity(ActivityThread.java:2607)
E/AndroidRuntime(25080): at android.app.ActivityThread.access$900(ActivityThread.java:174)
E/AndroidRuntime(25080): at android.app.ActivityThread$H.handleMessage(ActivityThread.java:1325)
E/AndroidRuntime(25080): at android.os.Handler.dispatchMessage(Handler.java:102)
E/AndroidRuntime(25080): at android.os.Looper.loop(Looper.java:146)
E/AndroidRuntime(25080): at android.app.ActivityThread.main(ActivityThread.java:5756)
E/AndroidRuntime(25080): at java.lang.reflect.Method.invokeNative(Native Method)
E/AndroidRuntime(25080): at java.lang.reflect.Method.invoke(Method.java:515)
E/AndroidRuntime(25080): at com.android.internal.os.ZygoteInit$MethodAndArgsCaller.run(ZygoteInit.java:1291)
E/AndroidRuntime(25080): at com.android.internal.os.ZygoteInit.main(ZygoteInit.java:1107)
E/AndroidRuntime(25080): at dalvik.system.NativeStart.main(Native Method)
E/AndroidRuntime(25080): Caused by: java.lang.IllegalStateException
E/AndroidRuntime(25080): at android.media.MediaCodec.native_configure(Native Method)
E/AndroidRuntime(25080): at android.media.MediaCodec.configure(MediaCodec.java:262)
E/AndroidRuntime(25080): at com.AndroidH264VideoTest.AndroidH264VideoTest.onCreate(AndroidH264VideoTest.java:33)
E/AndroidRuntime(25080): at android.app.Activity.performCreate(Activity.java:5619)
E/AndroidRuntime(25080): at android.app.Instrumentation.callActivityOnCreate(Instrumentation.java:1093)
E/AndroidRuntime(25080): at android.app.ActivityThread.performLaunchActivity(ActivityThread.java:2512)
E/AndroidRuntime(25080): ... 11 more
答案 0 :(得分:1)
我想说你的问题就在这里:
// Copy data to buffer
m_decoderInputBuffers[inputBufferId] = ByteBuffer.wrap(SPS_PACKET);
这只是用另一个ByteBuffer引用替换本地数组中的缓冲区 - 但解码器本身仍然尝试读取m_decoder.getInputBuffers()[inputBufferId]
。因此,您需要将输入字节复制到解码器提供的ByteBuffer中。
答案 1 :(得分:1)
4.4.4上的问题是试图解码8x8图像,这对于它的小脑来说太小了。 如果我用320x240或160x160甚至67x71替换8x8,只要它是64x64或更大,它就会很高兴。
我必须看看这个任意大小限制是否也适用于Marshmallow设备。