如何使用 iOS8 的 VideoToolbox 解码 live555 rtsp 流 (h.264) MediaSink 数据?
How to decode a live555 rtsp stream (h.264) MediaSink data using iOS8's VideoToolbox?
好的,我知道这个问题和 get-rtsp-stream-from-live555-and-decode-with-avfoundation 几乎一样,但是现在 VideoToolbox for iOS8 变成了 public for use 虽然我知道可以使用这个框架,我不知道该怎么做。
我的目标是:
- 使用 rtsp 协议连接 WiFiCamera 并接收流数据(使用 live555 完成)
- 解码数据并转换为 UIImages 以显示在屏幕上(类似 motionJPEG)
- 并将流式数据保存在 .mov 文件中
我使用 ffmpeg 达到了所有这些目标,但不幸的是,由于我公司的政策,我不能使用它。
我知道我也可以使用openGL在屏幕上显示,但这次我必须转换为UIImages。我还尝试使用以下库:
ffmpeg: 由于公司政策,暂时无法使用。 (不要问我为什么)
libVLC:显示延迟约 2 秒,我无法访问流数据以保存到 .mov 文件中...
gstreamer:同上
我相信 live555 + VideoToolbox 可以完成这项工作,只是不知道如何做到这一点...
我做到了。 VideoToolbox 的文档仍然很少,我们没有太多关于视频编程的信息(不使用 ffmpeg)所以我花费的时间比我真正预期的要多。
对于使用 live555 的流,我得到了 SPS 和 PPS 信息来创建 CMVideoFormatDescription
,如下所示:
const uint8_t *props[] = {[spsData bytes], [ppsData bytes]};
size_t sizes[] = {[spsData length], [ppsData length]};
OSStatus result = CMVideoFormatDescriptionCreateFromH264ParameterSets(NULL, 2, props, sizes, 4, &videoFormat);
现在,困难的部分(因为我对视频编程一窍不通):将 NALunit header 替换为描述的 4 字节长度代码 here
int headerEnd = 23; //where the real data starts
uint32_t hSize = (uint32_t)([rawData length] - headerEnd - 4);
uint32_t bigEndianSize = CFSwapInt32HostToBig(hSize);
NSMutableData *videoData = [NSMutableData dataWithBytes:&bigEndianSize length:sizeof(bigEndianSize)];
[videoData appendData:[rawData subdataWithRange:NSMakeRange(headerEnd + 4, [rawData length] - headerEnd - 4)]];
现在我能够使用此原始数据成功创建 CMBlockBuffer
并将缓冲区传递给 VTDecompressionSessionDecodeFrame。从这里很容易将响应 CVImageBufferRef
转换为 UIImage
... 我使用 this stack overflow thread 作为参考。
最后,按照How do I export UIImage array as a movie?
的解释保存UIImage
转换后的流数据
我只是发布了一些我的代码,因为我认为这是重要的部分,或者换句话说,这是我遇到问题的地方。
好的,我知道这个问题和 get-rtsp-stream-from-live555-and-decode-with-avfoundation 几乎一样,但是现在 VideoToolbox for iOS8 变成了 public for use 虽然我知道可以使用这个框架,我不知道该怎么做。
我的目标是:
- 使用 rtsp 协议连接 WiFiCamera 并接收流数据(使用 live555 完成)
- 解码数据并转换为 UIImages 以显示在屏幕上(类似 motionJPEG)
- 并将流式数据保存在 .mov 文件中
我使用 ffmpeg 达到了所有这些目标,但不幸的是,由于我公司的政策,我不能使用它。
我知道我也可以使用openGL在屏幕上显示,但这次我必须转换为UIImages。我还尝试使用以下库:
ffmpeg: 由于公司政策,暂时无法使用。 (不要问我为什么)
libVLC:显示延迟约 2 秒,我无法访问流数据以保存到 .mov 文件中...
gstreamer:同上
我相信 live555 + VideoToolbox 可以完成这项工作,只是不知道如何做到这一点...
我做到了。 VideoToolbox 的文档仍然很少,我们没有太多关于视频编程的信息(不使用 ffmpeg)所以我花费的时间比我真正预期的要多。
对于使用 live555 的流,我得到了 SPS 和 PPS 信息来创建 CMVideoFormatDescription
,如下所示:
const uint8_t *props[] = {[spsData bytes], [ppsData bytes]};
size_t sizes[] = {[spsData length], [ppsData length]};
OSStatus result = CMVideoFormatDescriptionCreateFromH264ParameterSets(NULL, 2, props, sizes, 4, &videoFormat);
现在,困难的部分(因为我对视频编程一窍不通):将 NALunit header 替换为描述的 4 字节长度代码 here
int headerEnd = 23; //where the real data starts
uint32_t hSize = (uint32_t)([rawData length] - headerEnd - 4);
uint32_t bigEndianSize = CFSwapInt32HostToBig(hSize);
NSMutableData *videoData = [NSMutableData dataWithBytes:&bigEndianSize length:sizeof(bigEndianSize)];
[videoData appendData:[rawData subdataWithRange:NSMakeRange(headerEnd + 4, [rawData length] - headerEnd - 4)]];
现在我能够使用此原始数据成功创建 CMBlockBuffer
并将缓冲区传递给 VTDecompressionSessionDecodeFrame。从这里很容易将响应 CVImageBufferRef
转换为 UIImage
... 我使用 this stack overflow thread 作为参考。
最后,按照How do I export UIImage array as a movie?
的解释保存UIImage
转换后的流数据
我只是发布了一些我的代码,因为我认为这是重要的部分,或者换句话说,这是我遇到问题的地方。