35

我有一个项目,我被要求在 android 中显示视频流,该流是原始 H.264,我正在连接到服务器并将接收来自服务器的字节流。

基本上我想知道有没有办法将原始字节发送到android中的解码器并将其显示在表面上?

我已经成功地使用 android 4.1 中的新 MediaCodec 和 MediaExtractor API 解码包装在 mp4 容器中的 H264,不幸的是我还没有找到使用这些 API 解码原始 H264 文件或流的方法。

我知道一种方法是编译和使用 FFmpeg,但我宁愿使用可以使用硬件加速的内置方法。我也了解 android 支持 RTSP 流,但这不是一个选项。安卓版本不是问题。

4

3 回答 3

31

不幸的是,我无法为此提供任何代码,但我会尽力根据我如何让它工作来解释它。

所以这里是我如何使用MediaCodec类获得原始 H.264 编码视频的概述。

使用上面的链接有一个获取解码器设置以及如何使用它的示例,您需要设置它以解码 H264 AVC。

H.264 的格式是它由 NAL 单元组成,每个单元都以三个字节的起始前缀开头,值为 0x00、0x00、0x01,每个单元都有不同的类型,具体取决于这些之后的第 4 个字节的值3 个起始字节。一个 NAL 单元不是视频中的一帧,每一帧由多个 NAL 单元组成。

基本上,我编写了一个方法来查找每个单独的单元并将其传递给解码器(一个 NAL 单元作为起始前缀,之后的任何字节直到下一个起始前缀)。

现在,如果您设置了用于解码 H.264 AVC 的解码器,并且有来自解码器的 InputBuffer,那么您就可以开始了。您需要使用 NAL 单元填充此 InputBuffer 并将其传递回解码器并继续为流的长度执行此操作。但是,为了完成这项工作,我必须首先向解码器传递一个 SPS(序列参数集)NAL 单元。该单元在起始前缀(第 4 个字节)之后的字节值为 0x67,在某些设备上,除非首先收到此单元,否则解码器会崩溃。基本上直到你找到这个单元,忽略所有其他 NAL 单元并继续解析流直到你得到这个单元,然后你可以将所有其他单元传递给解码器。

有些设备首先不需要 SPS,有些则需要,但您最好先传递它。

现在,如果您有一个在配置时传递给解码器的表面,那么一旦它为一帧获得足够的 NAL 单元,它应该在表面上显示它。

于 2013-09-05T13:55:23.937 回答
0

您可以从服务器下载原始 H.264,然后通过手机上运行的本地 HTTP 服务器提供它,然后让 VLC for Android 从该 HTTP 服务器进行播放。您应该使用 VLC 的 http/h264:// 方案强制解复用器为原始 H.264(如果您不强制解复用器 VLC 可能无法识别流,即使 HTTP 服务器返回的 MIME 类型是设置正确)。看

https://github.com/rauljim/tgs-android/blob/integrate_record/src/com/tudelft/triblerdroid/first/VideoPlayerActivity.java#L211

有关如何创建将启动 VLC 的 Intent 的示例。

注意:原始 H.264 显然没有时间信息,因此 VLC 将尽可能快地播放。首先将其嵌入MPEGTS会更好。还没有找到可以做到这一点的 Android 库。

于 2012-11-29T14:48:52.443 回答
0

以下是我在类似项目中发现的有用资源:

  1. 该视频在理解 MediaCodec 如何处理高级别原始 h.264 流方面非常有见地。
  2. 该线程更详细地介绍了具体处理 SPS/PPS NALU。如上所述,您需要使用起始前缀分隔各个 NAL 单元,然后将剩余数据交给 MediaCodec。
  3. 这个 repo (libstreaming) 是在 Android 中使用 RTSP/RTP 解码 H264 流进行传输的一个很好的例子。
于 2017-09-13T18:49:23.743 回答