简体   繁体   English

在Android中解码Raw H264流?

[英]Decoding Raw H264 stream in android?

I have a project where I have been asked to display a video stream in android, the stream is raw H.264 and I am connecting to a server and will receive a byte stream from the server. 我有一个项目,我被要求在android中显示视频流,流是原始H.264,我连接到服务器,将从服务器接收字节流。

Basically I'm wondering is there a way to send raw bytes to a decoder in android and display it on a surface? 基本上我想知道有没有办法将原始字节发送到android中的解码器并将其显示在表面上?

I have been successful in decoding H264 wrapped in an mp4 container using the new MediaCodec and MediaExtractor API in android 4.1, unfortunately I have not found a way to decode a raw H264 file or stream using these API's. 我使用android 4.1中的新MediaCodec和MediaExtractor API成功解码了包含在mp4容器中的H264,遗憾的是我还没有找到使用这些API解码原始H264文件或流的方法。

I understand that one way is to compile and use FFmpeg but I'd rather use a built in method that can use HW acceleration. 我知道一种方法是编译和使用FFmpeg,但我宁愿使用可以使用硬件加速的内置方法。 I also understand RTSP streaming is supported in android but this is not an option. 我也理解Android中支持RTSP流,但这不是一个选项。 Android version is not an issue. Android版本不是问题。

I can't provide any code for this unfortunately, but I'll do my best to explain it based on how I got it to work. 不幸的是,我不能为此提供任何代码,但我会尽力根据我如何使用它来解释它。

So here is my overview of how I got raw H.264 encoded video to work using the MediaCodec class. 所以这里是我如何使用MediaCodec类获得原始H.264编码视频的概述。

Using the link above there is an example of getting the decoder setup and how to use it, you will need to set it up for decoding H264 AVC. 使用上面的链接有一个获取解码器设置以及如何使用它的示例,您需要将其设置为解码H264 AVC。

The format of H.264 is that it's made up of NAL Units, each starting with a start prefix of three bytes with the values 0x00, 0x00, 0x01 and each unit has a different type depending on the value of the 4th byte right after these 3 starting bytes. H.264的格式是它由NAL单元组成,每个NAL单元的起始前缀为三个字节,值为0x00,0x00,0x01,每个单元的类型不同,具体取决于这些后面的第4个字节的值。 3个起始字节。 One NAL Unit IS NOT one frame in the video, each frame is made up of a number of NAL Units. 一个NAL单元不是视频中的一个帧,每个帧由许多NAL单元组成。

Basically I wrote a method that finds each individual unit and passes it to the decoder (one NAL Unit being the starting prefix and any bytes there after up until the next starting prefix). 基本上我写了一个方法,找到每个单独的单元并将其传递给解码器(一个NAL单元是起始前缀,其后是任何字节,直到下一个起始前缀)。

Now if you have the decoder setup for decoding H.264 AVC and have an InputBuffer from the decoder then you are ready to go. 现在,如果你有解码器设置解码H.264 AVC并从解码器有一个InputBuffer,那么你就准备好了。 You need to fill this InputBuffer with a NAL Unit and pass it back to the decoder and continue doing this for the length of the stream. 您需要使用NAL单元填充此InputBuffer并将其传递回解码器并继续对流的长度执行此操作。 But, to make this work I had to pass the decoder a SPS (Sequence Parameter Set) NAL Unit first. 但是,为了完成这项工作,我必须先将解码器传递给SPS(序列参数集)NAL单元。 This unit has a byte value of 0x67 after the starting prefix (the 4th byte), on some devices the decoder would crash unless it received this Unit first. 在启动前缀(第4个字节)之后,该单元的字节值为0x67,在某些设备上解码器会崩溃,除非它首先接收到该单元。 Basically until you find this unit, ignore all other NAL Units and keep parsing the stream until you get this unit, then you can pass all other units to the decoder. 基本上直到找到这个单元,忽略所有其他NAL单元并继续解析流直到你得到这个单元,然后你可以将所有其他单元传递给解码器。

Some devices didn't need the SPS first and some did, but you are better of passing it in first. 有些设备首先不需要SPS,有些设备确实需要SPS,但最好先将它传递给它。

Now if you had a surface that you passed to the decoder when you configured it then once it gets enough NAL units for a frame it should display it on the surface. 现在,如果你有一个表面,你在配置它时传递给解码器,那么一旦它获得足够的NAL单位的帧,它应该在表面上显示它。

Here are the resources I've found helpful in a similar project: 以下是我在类似项目中发现有用的资源:

  1. This video has been super insightful in understanding how MediaCodec handles raw h.264 streams on a high level. 该视频对于了解MediaCodec如何在高级别处理原始h.264流非常有洞察力。
  2. This thread goes into a bit more detail as to handling the SPS/PPS NALUs specifically. 该线程详细介绍了如何处理SPS / PPS NALU。 As was mentioned above, you need to separate individual NAL Units using the start prefix, and then hand the remaining data to the MediaCodec. 如上所述,您需要使用开始前缀分隔各个NAL单元,然后将剩余数据传递给MediaCodec。
  3. This repo (libstreaming) is a great example of decoding an H264 stream in Android using RTSP/RTP for transmission. 这个repo (libstreaming)是使用RTSP / RTP在Android中解码H264流进行传输的一个很好的例子。

You can download the raw H.264 from the server, then offer it via a local HTTP server running on the phone and then let VLC for Android do playback from that HTTP server. 您可以从服务器下载原始H.264,然后通过手机上运行的本地HTTP服务器提供它,然后让VLC for Android从该HTTP服务器进行播放。 You should use VLC's http/h264:// scheme to force the demuxer to raw H.264 (if you don't force the demuxer VLC may not be able to recognize the stream, even when the MIME type returned by the HTTP server is set correctly). 您应该使用VLC的http / h264://方案强制解复用器使用原始H.264(如果您不强制解复用器VLC可能无法识别流,即使HTTP服务器返回的MIME类型是设置正确)。 See 看到

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

for an example on how to create an Intent that will launch VLC. 有关如何创建将启动VLC的Intent的示例。

Note: raw H.264 apparently has no timing info, so VLC will play as fast as possible. 注意:原始H.264显然没有时序信息,因此VLC将尽可能快地播放。 First embedding it in MPEGTS will be better. 首先将其嵌入MPEGTS会更好。 Haven't found a Android lib that will do that yet. 还没有找到能够做到这一点的Android库。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM