前文 【ffmpeg学习(17)文件流、网络流的格式解析(使用AVIOContext )】 和 【ffmpeg学习(19)文件流、网络流的格式解析(纯净版av_parser_parse2)】 介绍了使用文件模拟网络流解析并解码的过程。本文使用UDP/TCP socket通信实现真实的网络流通信。
下面是文件关系图:
ImageHandler 包装了一个Image对象,使用互斥锁执行读取、写入。
StreamDecoder 对网络流数据解析、解码,调用用户注册回调返回最新Image对象
NetServer 简单的非阻塞Udp/TCP服务端,当有udp/TCP原始数据到来则调用StreamDecoder解析
StreamApp 应用层,建立服务端,提供简单的回调注册。
![](https://img-blog.csdnimg.cn/img_convert/d43732191bdc4755af13763b464f020e.png)
相关源码见CSDN资源
当前实现的功能:
实时接收用户UDP/TCP数据,目前设计上为H264视频裸流数据
通过注册回调,实时返回接收的H264裸流(一次回调不一定是一个完整的NALU包)
通过注册回调,实时返回当前解码的RGB图像数据
通过轮询,获取当前解码的RGB图像数据
支持客户端切换推送不同视频源数据
当前项目仅解析H264数据并解码为RGB图像,后期可以简单的嵌入其他模块,支持解析RTP数据。另外,还能继续支持解析音频数据。
一个最简单的示例如下
StreamApp app("192.168.3.100", 8000);
app.StartImageStream([](RGBImage img){
cv::Mat mat(img.height, img.width, CV_8UC3, const_cast<uchar *>(img.rawData.data()));
cv::imshow("img", mat);
cv::waitKey(1);
});
getchar();
app.StopImageStream();
1、ImageHandler模板类
ImageHandler
是一个模板类,目前仅包装了一个Image
对象
typedef struct RGBImage {
std::vector<uint8_t> rawData;
int height;
int width;
}RGBImage;
using ImageCallback = std::function<void(RGBImage)>;
using H264Callback = std::function<void(const uint8_t*, int)>;
通过互斥锁保护进行写入、读取操作,提供查询当前持有的Image是否为最新的数据。为避免空闲状态时互斥锁的大量操作,使用了条件变量通知机制,对于可能造成的阻塞允许GetNewImage()
函数超时返回。<