在 Unity 中从 ShortBuffer 读取时发生 IllegalStateException Android
IllegalStateException when reading from ShortBuffer in Unity Android
我正在 Unity 中开发一款游戏,我需要来自媒体缓冲区的原始音频数据。以下代码在 Unity 中用作 jar 插件。它正在 android 4.x 上正常工作。但是当我尝试在 Android 5.0.1 或 5.1 上 运行 它时,我得到以下异常,但只有当我尝试打开 aac 或 m4a 文件时。有什么建议吗?
这是我读取音频缓冲区的函数:
public short[] ReadNextSamples() {
if (sawOutputEOS) {
return new short[0];
}
int res;
while (true)
{
res = codec.dequeueOutputBuffer(info, kTimeOutUs);
if (res >= 0)
{
if (info.size > 0)
{
break;
}
else
{
codec.releaseOutputBuffer(res, false);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM)!= 0)
{
sawOutputEOS = true;
return new short[0];
}
}
}
}
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
int sampleSize = info.size / 2;
short[] sampleValues = new short[sampleSize];
ShortBuffer shBuf = buf.asShortBuffer();
try {
shBuf.get(sampleValues, 0, sampleSize);
} catch (Exception e) {
//the exception is being thrown here
e.printStackTrace();
}
codec.releaseOutputBuffer(outputBufIndex, false);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
return sampleValues;
}
异常:
06-04 16:18:01.188: W/System.err(20884): java.lang.IllegalStateException: buffer is inaccessible
06-04 16:18:01.188: W/System.err(20884): at java.nio.DirectByteBuffer.checkIsAccessible(DirectByteBuffer.java:551)
06-04 16:18:01.188: W/System.err(20884): at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:155)
06-04 16:18:01.188: W/System.err(20884): at java.nio.ByteBufferAsShortBuffer.get(ByteBufferAsShortBuffer.java:103)
06-04 16:18:01.190: W/System.err(20884): at com.pocketgames.musiverse.MediaDecoder.ReadNextSamples(MediaDecoder.java:112)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.nativeProxyInvoke(Native Method)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.a(Unknown Source)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.invoke(Unknown Source)
06-04 16:18:01.190: W/System.err(20884): at java.lang.reflect.Proxy.invoke(Proxy.java:397)
06-04 16:18:01.190: W/System.err(20884): at $Proxy0.run(Unknown Source)
06-04 16:18:01.191: W/System.err(20884): at java.lang.Thread.run(Thread.java:818)
我在 Android L 遇到了类似的问题,可以通过使用新的 MediaCodec API 获取缓冲区来解决。
而不是
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
你可以应该使用
ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
在我的例子中,这解决了访问输入缓冲区时的问题。
基本上你应该使用 API 级别相关的代码。我想你可能已经想通了。但是为了记录,你应该使用
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
对于 API 级别 < 21
和
ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
对于 API 级别 >= 21。
代码看起来像这样:
final int version = Build.VERSION.SDK_INT;
ByteBuffer buf;
if (version >= 21) {
buf = codec.getOutputBuffer(outputBufIndex);
} else {
buf = codecOutputBuffers[outputBufIndex];
}
如果你查看MediaCodec
class的源代码,getOutputBuffer
的代码是:
@Nullable
public ByteBuffer getOutputBuffer(int index) {
ByteBuffer newBuffer = getBuffer(false /* input */, index);
synchronized(mBufferLock) {
invalidateByteBuffer(mCachedOutputBuffers, index);
mDequeuedOutputBuffers.put(index, newBuffer);
}
return newBuffer;
}
所以,你得到的错误与获取锁 mBufferLock
有关,这可能是 API level >= 21 的 MediaCodec
的实现所必需的,因此你得到与无法访问相关的错误。希望对您有所帮助。
我正在 Unity 中开发一款游戏,我需要来自媒体缓冲区的原始音频数据。以下代码在 Unity 中用作 jar 插件。它正在 android 4.x 上正常工作。但是当我尝试在 Android 5.0.1 或 5.1 上 运行 它时,我得到以下异常,但只有当我尝试打开 aac 或 m4a 文件时。有什么建议吗?
这是我读取音频缓冲区的函数:
public short[] ReadNextSamples() {
if (sawOutputEOS) {
return new short[0];
}
int res;
while (true)
{
res = codec.dequeueOutputBuffer(info, kTimeOutUs);
if (res >= 0)
{
if (info.size > 0)
{
break;
}
else
{
codec.releaseOutputBuffer(res, false);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM)!= 0)
{
sawOutputEOS = true;
return new short[0];
}
}
}
}
int outputBufIndex = res;
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
int sampleSize = info.size / 2;
short[] sampleValues = new short[sampleSize];
ShortBuffer shBuf = buf.asShortBuffer();
try {
shBuf.get(sampleValues, 0, sampleSize);
} catch (Exception e) {
//the exception is being thrown here
e.printStackTrace();
}
codec.releaseOutputBuffer(outputBufIndex, false);
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
sawOutputEOS = true;
}
return sampleValues;
}
异常:
06-04 16:18:01.188: W/System.err(20884): java.lang.IllegalStateException: buffer is inaccessible
06-04 16:18:01.188: W/System.err(20884): at java.nio.DirectByteBuffer.checkIsAccessible(DirectByteBuffer.java:551)
06-04 16:18:01.188: W/System.err(20884): at java.nio.DirectByteBuffer.get(DirectByteBuffer.java:155)
06-04 16:18:01.188: W/System.err(20884): at java.nio.ByteBufferAsShortBuffer.get(ByteBufferAsShortBuffer.java:103)
06-04 16:18:01.190: W/System.err(20884): at com.pocketgames.musiverse.MediaDecoder.ReadNextSamples(MediaDecoder.java:112)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.nativeProxyInvoke(Native Method)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.a(Unknown Source)
06-04 16:18:01.190: W/System.err(20884): at com.unity3d.player.ReflectionHelper.invoke(Unknown Source)
06-04 16:18:01.190: W/System.err(20884): at java.lang.reflect.Proxy.invoke(Proxy.java:397)
06-04 16:18:01.190: W/System.err(20884): at $Proxy0.run(Unknown Source)
06-04 16:18:01.191: W/System.err(20884): at java.lang.Thread.run(Thread.java:818)
我在 Android L 遇到了类似的问题,可以通过使用新的 MediaCodec API 获取缓冲区来解决。
而不是
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
你可以应该使用
ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
在我的例子中,这解决了访问输入缓冲区时的问题。
基本上你应该使用 API 级别相关的代码。我想你可能已经想通了。但是为了记录,你应该使用
ByteBuffer buf = codecOutputBuffers[outputBufIndex];
对于 API 级别 < 21
和
ByteBuffer buf = codec.getOutputBuffer(outputBufIndex);
对于 API 级别 >= 21。
代码看起来像这样:
final int version = Build.VERSION.SDK_INT;
ByteBuffer buf;
if (version >= 21) {
buf = codec.getOutputBuffer(outputBufIndex);
} else {
buf = codecOutputBuffers[outputBufIndex];
}
如果你查看MediaCodec
class的源代码,getOutputBuffer
的代码是:
@Nullable
public ByteBuffer getOutputBuffer(int index) {
ByteBuffer newBuffer = getBuffer(false /* input */, index);
synchronized(mBufferLock) {
invalidateByteBuffer(mCachedOutputBuffers, index);
mDequeuedOutputBuffers.put(index, newBuffer);
}
return newBuffer;
}
所以,你得到的错误与获取锁 mBufferLock
有关,这可能是 API level >= 21 的 MediaCodec
的实现所必需的,因此你得到与无法访问相关的错误。希望对您有所帮助。