本文是在手搓ZLMediaKit实现拉流推流系列1(C++版)基础上调用了瑞芯微(Rockchip 系列)的MPP硬件编解码库,将经过ZLMediakit拉流得到的视频帧数据使用MPP解码库函数进行硬解码得到YUV数据格式后,再通过MPP编码库函数对视频帧数据进行编码后使用ZLMediakit推流给本地RTMP/RTSP接口。
在本文的基础上,后续将推出系列3:在MPP硬解码之后,将YUV数据格式转化为RGB数据格式,并使用YOLO系列模型完成分割,识别等模型的应用。
目录
1.1 Zlmediakit && MPP Context定义与各资源释放函数
1.3 基础配置与拉流控制函数 process_video_rtsp
1.4 播放器player正常播放/播放中断的回调函数 on_mk_play_event_func
1.5 音/视频轨道帧(track frame)输出回调函数 on_track_frame_out
1.6 媒体源注册事件回调函数 on_mk_media_source_regist_func
1.7 推流器pusher正常推流/推流失败回调函数on_mk_push_event_fun
1.8 解码数据回调函数 mpp_decoder_frame_callback(新增,最重要的模块)
1. 函数解释
注:“新增”表示在原本 ZLMediaKit 拉流推流的基础上新增了MPP编解码相关模块
由于涉及到的相关库较多,且使用的MPP编解码库是在官方MPP库的基础上进行修改的,当然官方的也能直接用(就是有点乱),官方的ZLMediaKit和MPP网址贴在了末尾编译处。如果大家有需要我自己整合后的MPP编解码库以及完整项目代码,可以私信我。创作不易,请多多支持!
1.1 Zlmediakit && MPP Context定义与各资源释放函数
// ---------- Zlmediakit && MPP context定义 ----------
typedef struct {
FILE *out_fp; // 新增:输出文件地址
MppDecoder *decoder; // 新增:MPP解码器
MppEncoder *encoder; // 新增:MPP编码器
mk_player player; // 播放器
mk_media media; // 媒体服务
mk_pusher pusher; // 推送器
char push_url[1024]; // 推送地址
uint64_t pts; // 新增:显示时间戳
uint64_t dts; // 新增:解码时间戳
} rknn_app_context_t;
// ---------- 释放媒体资源服务 media 的函数 ----------
void release_media(mk_media *ptr)
{
if (ptr && *ptr)
{
mk_media_release(*ptr);
*ptr = NULL;
}
}
// ---------- 释放播放器 palyer 的函数 ----------
void release_player(mk_player *ptr)
{
if (ptr && *ptr)
{
mk_player_release(*ptr);
*ptr = NULL;
}
}
// ---------- 释放推流器 pusher 的函数 ----------
void release_pusher(mk_pusher *ptr)
{
if (ptr && *ptr)
{
mk_pusher_release(*ptr);
*ptr = NULL;
}
}
1.2 main函数
- MppDecoder函数,Init函数,SetCallback函数,mpp_decoder_frame_callback函数等都是类MppDecoder下的成员函数。
int main()
{
char *stream_url = "rtsp:"; // 填上你自己的rtsp流
char *push_url = "rtmp://localhost/live/stream"; // 在本地启动推流服务
int video_type = 264; // 定义视频流类型,264/265
// ---------- 分配并初始化 Zlmediakit和MPP的 Context ----------
rknn_app_context_t app_ctx; // 创建上下文
memset(&app_ctx, 0, sizeof(rknn_app_context_t)); // 初始化上下文
// ---------- 创建MPP 解码器 ----------
if(app_ctx.decoder == NULL)
{
MppDecoder *decoder = new MppDecoder(); // 创建解码器
decoder->Init(video_type, 30, &app_ctx); // 初始化解码器,参数1:视频类型,参数2:帧率,参数3:mpp上下文指针
decoder->SetCallback(mpp_decoder_frame_callback); // 设置回调函数,用来处理解码后的数据
app_ctx.decoder = decoder; // 将解码器赋值给上下文
}
// ---------- 设置输出文件目录 ----------
if (app_ctx.out_fp == NULL)
{
FILE *fp = fopen(OUT_VIDEO_PATH, "w");
if (fp == NULL)
{
printf("open %s error\n", OUT_VIDEO_PATH);
return -1;
}
app_ctx.out_fp = fp;
}
// ---------- 基本配置 ----------
process_video_rtsp(&app_ctx, stream_url, push_url);
// ---------- 释放资源 ----------
fflush(app_ctx.out_fp);
fclose(app_ctx.out_fp);
if (app_ctx.decoder != nullptr)
{
delete (app_ctx.decoder);
app_ctx.decoder = nullptr;
}
if (app