- iOS/Objective-C 元类和类别
- objective-c - -1001 错误,当 NSURLSession 通过 httpproxy 和/etc/hosts
- java - 使用网络类获取 url 地址
- ios - 推送通知中不播放声音
我的目标是使用 Android MediaCodec 对视频流进行解码,然后使用输出图像在 native 代码中进行进一步的图像处理。
平台:ASUS tf700t android 4.1.1。测试码流:H.264 full HD @ 24 frm/s
在内置 Tegra-3 SoC 的情况下,我指望硬件支持视频解码。在功能上,我的应用程序按预期运行:我确实可以访问解码器图像并妥善处理。但是,我遇到了非常高的解码器 CPU 负载。
在接下来的实验中,进程/线程负载是通过 adb shell 中的“top -m 32 -t”测量的。为了从“top”获得可靠的输出,所有 4 个 cpu 内核都通过运行几个线程以最低优先级永远循环来强制激活。这可以通过重复执行“cat/sys/devices/system/cpu/cpu[0-3]/online”来确认。为了简单起见,只有视频解码,没有音频;并且没有时间控制,因此解码器会尽可能快地运行。
第一个实验:运行应用程序,调用 JNI 处理函数,但所有进一步的处理调用都被注释掉了。结果:
似乎解码速度受 CPU 限制(四核 CPU 的 25%)...启用输出处理时,解码的图像是正确的并且应用程序可以运行。唯一的问题:解码的 CPU 负载太高。
经过大量实验后,我考虑为 MediaCodec 提供一个表面来绘制其结果。在所有其他方面,代码是相同的。结果:
确实,视频显示在提供的 Surface 上。由于几乎没有任何 cpu 负载,这必须是硬件加速...
似乎 de MediaCodec 仅在提供 Surface 时才使用硬件加速?
到目前为止,还不错。我已经倾向于使用 Surface 作为解决方法(不是必需的,但在某些情况下甚至是可有可无)。但是,如果提供了表面,我将无法访问输出图像!结果是 native 代码中的访问冲突。
这让我很困惑!我没有看到任何访问限制的概念,或文档中的任何内容 http://developer.android.com/reference/android/media/MediaCodec.html .在谷歌 I/O 演示中也没有提到这个方向 http://www.youtube.com/watch?v=RQws6vsoav8 .
那么:如何使用硬件加速的 Android MediaCodec 解码器并以 native 代码访问图像?如何避免访问冲突?任何帮助表示赞赏!还有任何解释或提示。
我很确定 MediaExtractor 和 MediaCodec 被正确使用,因为应用程序功能正常(只要我不提供 Surface)。它仍然处于试验阶段,好的 API 设计在待办事项列表中;-)
请注意,两个实验之间的唯一区别是变量 mSurface: null 或实际 Surface在“mDecoder.configure(mediaFormat, mSurface, null, 0);”
初始化代码:
mExtractor = new MediaExtractor();
mExtractor.setDataSource(mPath);
// Locate first video stream
for (int i = 0; i < mExtractor.getTrackCount(); i++) {
mediaFormat = mExtractor.getTrackFormat(i);
String mime = mediaFormat.getString(MediaFormat.KEY_MIME);
Log.i(TAG, String.format("Stream %d/%d %s", i, mExtractor.getTrackCount(), mime));
if (streamId == -1 && mime.startsWith("video/")) {
streamId = i;
}
}
if (streamId == -1) {
Log.e(TAG, "Can't find video info in " + mPath);
return;
}
mExtractor.selectTrack(streamId);
mediaFormat = mExtractor.getTrackFormat(streamId);
mDecoder = MediaCodec.createDecoderByType(mediaFormat.getString(MediaFormat.KEY_MIME));
mDecoder.configure(mediaFormat, mSurface, null, 0);
width = mediaFormat.getInteger(MediaFormat.KEY_WIDTH);
height = mediaFormat.getInteger(MediaFormat.KEY_HEIGHT);
Log.i(TAG, String.format("Image size: %dx%d format: %s", width, height, mediaFormat.toString()));
JniGlue.decoutStart(width, height);
解码器循环(在单独的线程中运行):
ByteBuffer[] inputBuffers = mDecoder.getInputBuffers();
ByteBuffer[] outputBuffers = mDecoder.getOutputBuffers();
while (!isEOS && !Thread.interrupted()) {
int inIndex = mDecoder.dequeueInputBuffer(10000);
if (inIndex >= 0) {
// Valid buffer returned
int sampleSize = mExtractor.readSampleData(inputBuffers[inIndex], 0);
if (sampleSize < 0) {
Log.i(TAG, "InputBuffer BUFFER_FLAG_END_OF_STREAM");
mDecoder.queueInputBuffer(inIndex, 0, 0, 0, MediaCodec.BUFFER_FLAG_END_OF_STREAM);
isEOS = true;
} else {
mDecoder.queueInputBuffer(inIndex, 0, sampleSize, mExtractor.getSampleTime(), 0);
mExtractor.advance();
}
}
int outIndex = mDecoder.dequeueOutputBuffer(info, 10000);
if (outIndex >= 0) {
// Valid buffer returned
ByteBuffer buffer = outputBuffers[outIndex];
JniGlue.decoutFrame(buffer, info.offset, info.size);
mDecoder.releaseOutputBuffer(outIndex, true);
} else {
// Some INFO_* value returned
switch (outIndex) {
case MediaCodec.INFO_OUTPUT_BUFFERS_CHANGED:
Log.i(TAG, "RunDecoder: INFO_OUTPUT_BUFFERS_CHANGED");
outputBuffers = mDecoder.getOutputBuffers();
break;
case MediaCodec.INFO_OUTPUT_FORMAT_CHANGED:
Log.i(TAG, "RunDecoder: New format " + mDecoder.getOutputFormat());
break;
case MediaCodec.INFO_TRY_AGAIN_LATER:
// Timeout - simply ignore
break;
default:
// Some other value, simply ignore
break;
}
}
if ((info.flags & MediaCodec.BUFFER_FLAG_END_OF_STREAM) != 0) {
Log.d(TAG, "RunDecoder: OutputBuffer BUFFER_FLAG_END_OF_STREAM");
isEOS = true;
}
}
最佳答案
如果配置输出表面,解码数据将写入可用作 OpenGL ES 纹理(通过“外部纹理”扩展)的图形缓冲区。硬件的各个部分以他们喜欢的格式传递数据,而 CPU 不必复制数据。
如果不配置 Surface,输出将进入 java.nio.ByteBuffer
。至少有一个缓冲区副本用于将数据从 MediaCodec 分配的缓冲区获取到您的 ByteByffer
,并且可能还有另一个副本用于将数据返回到您的 JNI 代码中。我希望您看到的是间接成本,而不是软件解码成本。
您可能可以通过将输出发送到 SurfaceTexture
,渲染到 FBO 或 pbuffer,然后使用 glReadPixels
来改善问题提取数据。如果您读入“直接”ByteBuffer
或从 native 代码调用 glReadPixels
,则可以减少 JNI 开销。这种方法的缺点是您的数据将采用 RGB 而不是 YCbCr。 (OTOH,如果你想要的转换可以在 GLES 2.0 fragment 着色器中表达,你可以让 GPU 代替 CPU 来完成工作。)
如另一个答案所述,不同设备上的解码器以不同格式输出 ByteBuffer
数据,因此如果可移植性对您很重要,则在软件中解释数据可能不可行。
关于android - 使用硬件加速 Android MediaCodec 解码器的 native 代码中的访问冲突,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/15500290/
我刚刚意识到二进制编译器会将源代码转换为目标平台的二进制文件。有点明显...但如果编译器以这种方式工作,那么同一个编译器如何用于不同的系统,如 x86、ARM、MIPS 等? 难道他们不应该“知道”硬
在我的 SDL 游戏中,出于游戏玩法和性能原因,我希望保留固定的游戏区域分辨率。 我想做的是有一个小分辨率(例如 320 * 240),并且在调整窗口大小时/切换到全屏模式时让 SDL/显卡缩放每个像
我正在使用这些方法来激活 SurFaceView 上的触摸焦点 private SurfaceView surfaceiew; private CameraSource camSource; priv
您好,当我从硬件菜单更改设备时,我遇到了这个奇怪的问题,但我想我可能遗漏了一些简单的东西。 我的 View Controller 中有这段代码: - (void)touchesBegan:(NSSet
编写一个名为 weird() 的函数,它将三个字符串作为参数并向后打印最长的一个。 (在平局的情况下,应该选择较早的参数字符串。 函数调用: weird("I", "Love", "Python")
您好,我正在尝试设置 hadoop 环境。简而言之,我要解决的问题涉及数十亿个大小为几 MB 的 XML 文件,使用 HIVE 从中提取相关信息,并对这些信息进行一些分析工作。我知道这在 hadoop
我知道 Phidgets,但是,我正在寻找可以与 C# 接口(interface)的一些其他类型的硬件。 谁有好东西? 最佳答案 查看 Netduino .它基于 Arduino,但使用 .Net
说一个函数(例如模乘法、正弦函数)是在硬件而不是软件中实现是什么意思? 最佳答案 在硬件中实现意味着电路(通过逻辑门等)可以执行操作。 例如,在 ALU 中,处理器在物理上能够将一个字节加到另一个字节
我需要编写一个程序,在可能状态的大空间中执行并行搜索,在此过程中发现了新区域(并开始了他们的探索),并且由于在其他地方获得的中间结果消除了可能性,因此提前终止了对某些区域的探索在其中发现新的有用结果。
我们需要通过带有硬件 token 的 EV 代码对 InstallShield 2013 Express 的安装进行签名,但是无法导出私钥证书文件,因此唯一的方法是使用 DigiCertUtil 工具
关闭。这个问题需要多问focused 。目前不接受答案。 想要改进此问题吗?更新问题,使其仅关注一个问题 editing this post . 已关闭 2 年前。 Improve this ques
我考虑从库中丢弃处理大端情况的代码,如果平台不是小端,则在初始化期间简单地抛出一个异常。如果我们限制为,我无法想象会有任何大端硬件 托管任何网站的典型服务器硬件 服务器根据开放计算项目规范 所有常见的
我知道这可以做到,但找不到交换目标调试设备的地方。我现在正在使用模拟器,但想切换到设备,反之亦然。谁能指出我正确的方向? 谢谢。 最佳答案 像这样.. 右键单击 PROJECT--->Run As--
我正在尝试创建一个监听音量键事件的服务。 每当按下音量键时,服务应向号码发送短信,但我无法检测到音量键事件。 最佳答案 您可以使用 OnKeyListener可以检测按键事件(包括音量键)。您可以找到
谁能解释一下中断如何从最低层(硬件)传递到应用程序。 所以在下图中我知道处理器之后发生了什么。 但是我想要从键盘按下到处理器的中断过程在硬件中发生了什么,例如它如何传递扫描代码,中断 Controll
我的任务是构建一个应用程序,其中业务用户将定义一些数据操作和处理规则(例如,取一个数值并将其平均分配给根据中指定的条件选择的多个记录)规则)。 每月必须运行一个批处理应用程序,以便根据定义的规则处理大
所以这是我的愚蠢问题: PGP/GPGP可以用来对文本进行签名,其他的使用公钥来验证。 比方说,非对称密码算法处理空间。 有没有什么算法可以处理时间? 例如在 2011-10-10 10:10:10
使用 nvcc 编译 CUDA 程序是否需要安装支持 CUDA 的显卡(在 Linux 中)?或者可以在任何地方编译程序并且只能在这样的系统上运行? 最佳答案 不,编译不需要显卡。 您甚至不需要一个来
关闭。这个问题不符合Stack Overflow guidelines .它目前不接受答案。 这个问题似乎不是关于 a specific programming problem, a softwar
我有一个奇怪的问题,但我对这个话题很感兴趣。 是否有可能直接访问当前基于 x64 的计算机的硬件,而无需使用某种 HAL(硬件抽象层)或其他操作系统(udev、upower 等)的附属物?我不是在谈论
我是一名优秀的程序员,十分优秀!