一套rk3588 rtsp服务器推流的 github 方案及记录 -02
整体方案参考上一篇博文
https://blog.csdn.net/qq_31764341/article/details/134810566
本篇博文主要介绍基于RK3588进行硬解码
还是之前的套路,我不生产代码,我只是代码的搬运工,今天我们搬运瑞芯微的官方代码,并记录下来整个调试历程。两篇文章下来,我们3588上面的流肯定能出来
代码贴的特别详细。。。 希望不要取关 谢谢 然后后面再出一个 硬件解码的ffmpeg 编译以及opencv拉流示例代码
mpp库文件
rk3588 编码有自己的demo 这个demo一般存在于下面的这坨东西里
4. you can get demo about mpp applied to linux and android.Liunx : https://github.com/WainDing/mpp_linux_cpphttps://github.com/MUZLATAN/ffmpeg_rtsp_mppAndroid : https://github.com/c-xh/RKMediaCodecDemo
5. offical github: https://github.com/rockchip-linux/mppdevelop github: https://github.com/HermanChen/mppdevelop gitee : https://gitee.com/hermanchen82/mpp
6. Commit message format should base on https://keepachangelog.com/en/1.0.0/More document can be found at http://opensource.rock-chips.com/wiki_Mpp
一般我们把这个链接的东西down下来,然后传到板子上,在mpp路径下执行
make
make install
https://github.com/rockchip-linux/mpp
就能够在test路径下面拿到测试的app程序了,大概是这样的
xxx@orangepi5plus:~/xxx/mpp-develop/test$ ls
CMakeFiles mpi_dec_mt_test mpi_dec_test mpi_rc2_test mpp_info_test.c vpu_api_test
cmake_install.cmake mpi_dec_mt_test.c mpi_dec_test.c mpi_rc2_test.c mpp_parse_cfg.c vpu_api_test.c
CMakeLists.txt mpi_dec_multi_test mpi_enc_mt_test mpi_rc.cfg mpp_parse_cfg.h
dec.yuv mpi_dec_multi_test.c mpi_enc_mt_test.cpp mpp_event_trigger.c output.h264
gastest.o mpi_dec_nt_test mpi_enc_test mpp_event_trigger.h output.yuv
Makefile mpi_dec_nt_test.c mpi_enc_test.c mpp_info_test README.md
编码
这篇先说264编码,为了蹭一口流量卷,拆开两篇文章说
编码 encode ,这个路径下的encode的两个都是编码例程,一个多线程,一个单线程,对应的程序文件也在同路径下面
自己的工程使用他的编解码
如果是要把他的文件放在其他路径下面用,CmakeLists.txt需要按照下面的写就可以了
cmake_minimum_required(VERSION 3.5)
project(rtspserver)
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# -g 开启调试
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DSOCKLEN_T=socklen_t -g ")#find_package(OpenCV 4.8.0 REQUIRED)
#find_package(OpenSSL REQUIRED)# MPP
set(MPP_PATH /home/orangepi/XXX/mpp-develop/inc)
set(MPP_LIBS /home/orangepi/XXX/mpp-develop/mpp/librockchip_mpp.so)
include_directories(${MPP_PATH})# OSAL
set(OSAL_PATH /home/orangepi/XXX/mpp-develop/osal/inc/ /home/orangepi/XXX/mpp-develop/utils)
set(OSAL_LIBS /home/orangepi/XXX/mpp-develop/osal/libosal.a /home/orangepi/XXX/mpp-develop/utils/libutils.a)
include_directories(${OSAL_PATH})# RGA RGA库 放到同文件夹下面的/3rdparty/rga/RK3588 这个地方
set(RGA_PATH ${CMAKE_SOURCE_DIR}/3rdparty/rga/RK3588)
set(RGA_LIB ${RGA_PATH}/lib/Linux/aarch64/librga.so)
include_directories(${RGA_PATH}/include)# 写你的main.cpp 文件 rtsp是生成的二进制可执行文件名
add_executable(rtsp
example/rtsp_server.cpp
)
# 这里一定要把库链接进来
target_link_libraries(rtsp ${MPP_LIBS} ${OSAL_LIBS} ${OpenCV_LIBS} ${RGA_LIB} OpenSSL::SSL OpenSSL::Crypto )
Encoder程序拆解
他支持三种方式,这个地方要看他的官方文档支持,路径一般是:Rk3588-linux-v002\linux\docs\Linux\Multimedia\Rockchip_Developer_Guide_MPP_CN.pdf,(如果有人需要Rk3588-linux-v002下面的东西。。。 可以私聊我 售价30,或者在其他地方找一找)
他是说我们使用编码器/解码器的三种方式,第二章从接口角度介绍,第三章从应用角度介绍,前两种方式使用MppPacket 与 MppFrame这对结构,第三种高级模式是使用MppTask。前两种一种是无脑往里塞,一种是告诉分配空间大小和格式往里塞,第三种是自己定义task ,只研究了linux demo里面的最简单的方式,带mt的那个是多线程,也没研究多线。主打的一个先能用
mpi_enc_test.c
粗解析一下 后面贴我整理后的底层
这里推荐一个方法可以快速的开发,在他的Cmakelist.txt 的C/Cpp 编译flags 里面加"-g",然后重新生成,再配合我前面的有一篇vscode远程debug 配置,直接可以逐行运行,然后确定他最后运行的配置。
main
先看main
RK_S32 ret = MPP_NOK;
// MpiEncTestArgs 初始化 判断是否开多线程
MpiEncTestArgs* cmd = mpi_enc_test_cmd_get();// parse the cmd option 使用argc argv解析,给cmd赋值
ret = mpi_enc_test_cmd_update_by_args(cmd, argc, argv);
if (ret)goto DONE;//
mpi_enc_test_cmd_show_opt(cmd);// 打印 解析到的输入参数信息ret = enc_test_multi(cmd, argv[0]);// 按照输入参数执行
enc_test_multi
重点就是下面这句创建了线程,然后就是判断frame是否全部处理完或者键盘输入回车,二者有一个,就开始中断线程。
ret = pthread_create(&ctxs[i].thd, NULL, enc_test, &ctxs[i]);
他这里很多参数都是配置用于计时的,自己用可以适当删减。
enc_test
mpp_buffer_get 是获取参数的,他的例程配置了很多,有的就没有任何变化,拿了一个原始数据,然后再给配置上,目的应该是为了给演示操作。这个自己看需求应该可以删一部分,不过我没试。
下面是核心语句
ret = test_ctx_init(info);// ctx 初始化
// 拿到内部Buffer group的类型
ret = mpp_buffer_group_get_internal(&p->buf_grp, MPP_BUFFER_TYPE_DRM);
// 拿取Buffer 到 p->frm_buf指针
ret = mpp_buffer_get(p->buf_grp, &p->frm_buf, p->frame_size + p->header_size);
ret = mpp_buffer_get(p->buf_grp, &p->pkt_buf, p->frame_size);
ret = mpp_buffer_get(p->buf_grp, &p->md_info, p->mdinfo_size);ret = mpp_create(&p->ctx, &p->mpi);// 创建mpp实例
p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);// 设置超时时间
mpp_init(p->ctx, MPP_CTX_ENC, p->type);//mpp初始化
mpp_enc_cfg_init(&p->cfg);// 编码器初始化
p->mpi->control(p->ctx, MPP_ENC_GET_CFG, p->cfg);
test_mpp_enc_cfg_setup(info);// 大批量初始化参数
ret = test_mpp_run(info);// 处理一帧
test_mpp_run
这个函数就是完整的处理一帧数据
这玩意总体上干的事情就是 你通过buf 填充一帧数据给frame,然后调用put语句把frame送入编码器,再通过get 语句拿到
while (!p->pkt_eos)// 判断这个packet是否放入结束
// 下面这句 是把fp_input的数据读到初始化的buf里面,buf是在前面初始化的时候从mpp里面拿过来的地址,使用这个拿的指针mpp_buffer_get_ptr,当指针用就行ret = read_image(buf, p->fp_input, p->width, p->height,p->hor_stride, p->ver_stride, p->fmt);
// 另一个判断是要去从相机里面拿数据,使用的是v4l2的库拿的 没认真看
ret = mpp_frame_init(&frame);
// 初始化 设定frame格式 也就是编码输入
mpp_frame_set_width(frame, p->width);
mpp_frame_set_height(frame, p->height);
mpp_frame_set_hor_stride(frame, p->hor_stride);
mpp_frame_set_ver_stride(frame, p->ver_stride);
mpp_frame_set_fmt(frame, p->fmt);
mpp_frame_set_eos(frame, p->frm_eos);
mpp_frame_set_buffer(frame, p->frm_buf);
// 初始化 packet 也就是编码结果的格式
meta = mpp_frame_get_meta(frame);
mpp_packet_init_with_buffer(&packet, p->pkt_buf);
/* NOTE: It is important to clear output packet length!! */
mpp_packet_set_length(packet, 0);
mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet);
mpp_meta_set_buffer(meta, KEY_MOTION_INFO, p->md_info);
// 中间是可选项 osd userdata roi啥的
// 扔进去一帧图像
ret = mpi->encode_put_frame(ctx, frame);
// 拿回来一个packet 一次不一定能拿完 没拿完再do循环里 拿完就跳出来了
ret = mpi->encode_get_packet(ctx, &packet);
// 把结果写入文件
fwrite(ptr, 1, len, p->fp_output);
我的底层
使用PostAframe 操作一帧
encoder.cpp,我这里是能用的…
#include "encoder.h"
#include <opencv2/opencv.hpp>
//#include "videoThread.h"
// #include <liveMedia.hh>
// #include <GroupsockHelper.hh>
// #include <BasicUsageEnvironment.hh>
// #include <H264VideoRTPSource.hh>
#include <unistd.h>
/* 创建有名管道,写数据 */
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
// #include <QDebug>
// 用于初始化。
MPP_RET test_ctx_init(MpiEncMultiCtxInfo *info)
{MpiEncTestData *p = &info->ctx;MPP_RET ret = MPP_OK;// get paramter from cmdp->width = 1280;p->height = 720;p->hor_stride = (MPP_ALIGN(p->width, 16)*3);p->ver_stride = (MPP_ALIGN(p->height, 16));p->fmt = MPP_FMT_RGB888;p->type = MPP_VIDEO_CodingAVC;p->bps = 0;p->bps_min = 0;p->bps_max = 0;p->rc_mode = MPP_ENC_RC_MODE_VBR;p->frame_num = 1;p->gop_mode = 0;p->gop_len = 5;p->vi_len = 0;p->fps_in_flex = 0;p->fps_in_den = 0;p->fps_in_num = 0;p->fps_out_flex = 0;p->fps_out_den = 0;p->fps_out_num = 0;p->scene_mode = 0;p->mdinfo_size = (MPP_VIDEO_CodingHEVC == p->type) ?(MPP_ALIGN(p->hor_stride, 32) >> 5) *(MPP_ALIGN(p->ver_stride, 32) >> 5) * 16 :(MPP_ALIGN(p->hor_stride, 64) >> 6) *(MPP_ALIGN(p->ver_stride, 16) >> 4) * 16;// p->fp_input = fopen("/home/orangepi/code/mpp-develop/test/dog_bike_car_448x448.bgr", "rb");// if (NULL == p->fp_input) {// mpp_err("failed to open input file %s\n", "/home/orangepi/code/mpp-develop/test/dog_bike_car_448x448.bgr");// mpp_err("create default yuv image for test\n");// }// }// } 有个指针没有初始化 是数据输入指针 p->fp_input// 测试 264 输出p->fp_output = fopen("./1.h264", "w+b");if (NULL == p->fp_output) {mpp_err("failed to open output file %s\n", p->fp_output);ret = MPP_ERR_OPEN_FILE;}// }// update resource parameterswitch (p->fmt & MPP_FRAME_FMT_MASK) {case MPP_FMT_YUV420SP:case MPP_FMT_YUV420P: {p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 3 / 2;} break;case MPP_FMT_YUV422_YUYV :case MPP_FMT_YUV422_YVYU :case MPP_FMT_YUV422_UYVY :case MPP_FMT_YUV422_VYUY :case MPP_FMT_YUV422P :case MPP_FMT_YUV422SP : {p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 2;} break;case MPP_FMT_RGB444 :case MPP_FMT_BGR444 :case MPP_FMT_RGB555 :case MPP_FMT_BGR555 :case MPP_FMT_RGB565 :case MPP_FMT_BGR565 :case MPP_FMT_RGB888 :case MPP_FMT_BGR888 :case MPP_FMT_RGB101010 :case MPP_FMT_BGR101010 :case MPP_FMT_ARGB8888 :case MPP_FMT_ABGR8888 :case MPP_FMT_BGRA8888 :case MPP_FMT_RGBA8888 : {p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64);} break;default: {p->frame_size = MPP_ALIGN(p->hor_stride, 64) * MPP_ALIGN(p->ver_stride, 64) * 4;} break;}if (MPP_FRAME_FMT_IS_FBC(p->fmt)) {if ((p->fmt & MPP_FRAME_FBC_MASK) == MPP_FRAME_FBC_AFBC_V1)p->header_size = MPP_ALIGN(MPP_ALIGN(p->width, 16) * MPP_ALIGN(p->height, 16) / 16, SZ_4K);elsep->header_size = MPP_ALIGN(p->width, 16) * MPP_ALIGN(p->height, 16) / 16;} else {p->header_size = 0;}return ret;
}MPP_RET test_mpp_enc_cfg_setup(MpiEncMultiCtxInfo *info)
{MpiEncTestData *p = &info->ctx;MppApi *mpi = p->mpi;MppCtx ctx = p->ctx;MppEncCfg cfg = p->cfg;RK_U32 quiet = 0;MPP_RET ret;RK_U32 rotation;RK_U32 mirroring;RK_U32 flip;RK_U32 gop_mode = p->gop_mode;MppEncRefCfg ref = NULL;/* setup default parameter */if (p->fps_in_den == 0)p->fps_in_den = 1;if (p->fps_in_num == 0)p->fps_in_num = 15;if (p->fps_out_den == 0)p->fps_out_den = 1;if (p->fps_out_num == 0)p->fps_out_num = 15;if (!p->bps)p->bps = p->width * p->height / 8 * (p->fps_out_num / p->fps_out_den);mpp_enc_cfg_set_s32(cfg, "tune:scene_mode", p->scene_mode);mpp_enc_cfg_set_s32(cfg, "prep:width", p->width);mpp_enc_cfg_set_s32(cfg, "prep:height", p->height);mpp_enc_cfg_set_s32(cfg, "prep:hor_stride", p->hor_stride);mpp_enc_cfg_set_s32(cfg, "prep:ver_stride", p->ver_stride);mpp_enc_cfg_set_s32(cfg, "prep:format", p->fmt);mpp_enc_cfg_set_s32(cfg, "rc:mode", p->rc_mode);/* fix input / output frame rate */mpp_enc_cfg_set_s32(cfg, "rc:fps_in_flex", p->fps_in_flex);mpp_enc_cfg_set_s32(cfg, "rc:fps_in_num", p->fps_in_num);mpp_enc_cfg_set_s32(cfg, "rc:fps_in_denorm", p->fps_in_den);mpp_enc_cfg_set_s32(cfg, "rc:fps_out_flex", p->fps_out_flex);mpp_enc_cfg_set_s32(cfg, "rc:fps_out_num", p->fps_out_num);mpp_enc_cfg_set_s32(cfg, "rc:fps_out_denorm", p->fps_out_den);/* drop frame or not when bitrate overflow */mpp_enc_cfg_set_u32(cfg, "rc:drop_mode", MPP_ENC_RC_DROP_FRM_DISABLED);mpp_enc_cfg_set_u32(cfg, "rc:drop_thd", 20); /* 20% of max bps */mpp_enc_cfg_set_u32(cfg, "rc:drop_gap", 1); /* Do not continuous drop frame *//* setup bitrate for different rc_mode */mpp_enc_cfg_set_s32(cfg, "rc:bps_target", p->bps);switch (p->rc_mode) {case MPP_ENC_RC_MODE_FIXQP : {/* do not setup bitrate on FIXQP mode */} break;case MPP_ENC_RC_MODE_CBR : {/* CBR mode has narrow bound */mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);} break;case MPP_ENC_RC_MODE_VBR :case MPP_ENC_RC_MODE_AVBR : {/* VBR mode has wide bound */mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 1 / 16);} break;default : {/* default use CBR mode */mpp_enc_cfg_set_s32(cfg, "rc:bps_max", p->bps_max ? p->bps_max : p->bps * 17 / 16);mpp_enc_cfg_set_s32(cfg, "rc:bps_min", p->bps_min ? p->bps_min : p->bps * 15 / 16);} break;}/* setup qp for different codec and rc_mode */switch (p->type) {case MPP_VIDEO_CodingAVC :case MPP_VIDEO_CodingHEVC : {switch (p->rc_mode) {case MPP_ENC_RC_MODE_FIXQP : {RK_S32 fix_qp = 0;mpp_enc_cfg_set_s32(cfg, "rc:qp_init", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:qp_max", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:qp_min", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 0);mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", fix_qp);mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p", fix_qp);} break;case MPP_ENC_RC_MODE_CBR :case MPP_ENC_RC_MODE_VBR :case MPP_ENC_RC_MODE_AVBR : {mpp_enc_cfg_set_s32(cfg, "rc:qp_init", -1);mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 51);mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 10);mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i", 51);mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 10);mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 2);mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_i", 10);mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_i", 51);mpp_enc_cfg_set_s32(cfg, "rc:fqp_min_p", 10);mpp_enc_cfg_set_s32(cfg, "rc:fqp_max_p", 51);} break;default : {mpp_err_f("unsupport encoder rc mode %d\n", p->rc_mode);} break;}} break;case MPP_VIDEO_CodingVP8 : {/* vp8 only setup base qp range */mpp_enc_cfg_set_s32(cfg, "rc:qp_init", 40);mpp_enc_cfg_set_s32(cfg, "rc:qp_max", 127);mpp_enc_cfg_set_s32(cfg, "rc:qp_min", 0);mpp_enc_cfg_set_s32(cfg, "rc:qp_max_i",127);mpp_enc_cfg_set_s32(cfg, "rc:qp_min_i", 0);mpp_enc_cfg_set_s32(cfg, "rc:qp_ip", 6);} break;case MPP_VIDEO_CodingMJPEG : {/* jpeg use special codec config to control qtable */mpp_enc_cfg_set_s32(cfg, "jpeg:q_factor", 80);mpp_enc_cfg_set_s32(cfg, "jpeg:qf_max", 99);mpp_enc_cfg_set_s32(cfg, "jpeg:qf_min", 1);} break;default : {} break;}/* setup codec */mpp_enc_cfg_set_s32(cfg, "codec:type", p->type);switch (p->type) {case MPP_VIDEO_CodingAVC : {RK_U32 constraint_set;/** H.264 profile_idc parameter* 66 - Baseline profile* 77 - Main profile* 100 - High profile*/mpp_enc_cfg_set_s32(cfg, "h264:profile", 100);/** H.264 level_idc parameter* 10 / 11 / 12 / 13 - qcif@15fps / cif@7.5fps / cif@15fps / cif@30fps* 20 / 21 / 22 - cif@30fps / half-D1@@25fps / D1@12.5fps* 30 / 31 / 32 - D1@25fps / 720p@30fps / 720p@60fps* 40 / 41 / 42 - 1080p@30fps / 1080p@30fps / 1080p@60fps* 50 / 51 / 52 - 4K@30fps*/mpp_enc_cfg_set_s32(cfg, "h264:level", 40);mpp_enc_cfg_set_s32(cfg, "h264:cabac_en", 1);mpp_enc_cfg_set_s32(cfg, "h264:cabac_idc", 0);mpp_enc_cfg_set_s32(cfg, "h264:trans8x8", 1);mpp_env_get_u32("constraint_set", &constraint_set, 0);if (constraint_set & 0x3f0000)mpp_enc_cfg_set_s32(cfg, "h264:constraint_set", constraint_set);} break;case MPP_VIDEO_CodingHEVC :case MPP_VIDEO_CodingMJPEG :case MPP_VIDEO_CodingVP8 : {} break;default : {mpp_err_f("unsupport encoder coding type %d\n", p->type);} break;}p->split_mode = 0;p->split_arg = 0;p->split_out = 0;mpp_env_get_u32("split_mode", &p->split_mode, MPP_ENC_SPLIT_NONE);mpp_env_get_u32("split_arg", &p->split_arg, 0);mpp_env_get_u32("split_out", &p->split_out, 0);if (p->split_mode) {mpp_log_q(quiet, "%p split mode %d arg %d out %d\n", ctx,p->split_mode, p->split_arg, p->split_out);mpp_enc_cfg_set_s32(cfg, "split:mode", p->split_mode);mpp_enc_cfg_set_s32(cfg, "split:arg", p->split_arg);mpp_enc_cfg_set_s32(cfg, "split:out", p->split_out);}mpp_env_get_u32("mirroring", &mirroring, 0);mpp_env_get_u32("rotation", &rotation, 0);mpp_env_get_u32("flip", &flip, 0);mpp_enc_cfg_set_s32(cfg, "prep:mirroring", mirroring);mpp_enc_cfg_set_s32(cfg, "prep:rotation", rotation);mpp_enc_cfg_set_s32(cfg, "prep:flip", flip);// config gop_len and ref cfgmpp_enc_cfg_set_s32(cfg, "rc:gop", p->gop_len ? p->gop_len : p->fps_out_num * 2);mpp_env_get_u32("gop_mode", &gop_mode, gop_mode);if (gop_mode) {mpp_enc_ref_cfg_init(&ref);if (p->gop_mode < 4)mpi_enc_gen_ref_cfg(ref, gop_mode);elsempi_enc_gen_smart_gop_ref_cfg(ref, p->gop_len, p->vi_len);mpp_enc_cfg_set_ptr(cfg, "rc:ref_cfg", ref);}ret = mpi->control(ctx, MPP_ENC_SET_CFG, cfg);if (ret) {mpp_err("mpi control enc set cfg failed ret %d\n", ret);goto RET;}if (ref)mpp_enc_ref_cfg_deinit(&ref);/* optional */{RK_U32 sei_mode;mpp_env_get_u32("sei_mode", &sei_mode, MPP_ENC_SEI_MODE_ONE_FRAME);p->sei_mode = (MppEncSeiMode)sei_mode;ret = mpi->control(ctx, MPP_ENC_SET_SEI_CFG, &p->sei_mode);if (ret) {mpp_err("mpi control enc set sei cfg failed ret %d\n", ret);goto RET;}}if (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {p->header_mode = MPP_ENC_HEADER_MODE_EACH_IDR;ret = mpi->control(ctx, MPP_ENC_SET_HEADER_MODE, &p->header_mode);if (ret) {mpp_err("mpi control enc set header mode failed ret %d\n", ret);goto RET;}}/* setup test mode by env */mpp_env_get_u32("osd_enable", &p->osd_enable, 0);mpp_env_get_u32("osd_mode", &p->osd_mode, MPP_ENC_OSD_PLT_TYPE_DEFAULT);mpp_env_get_u32("roi_enable", &p->roi_enable, 0);mpp_env_get_u32("user_data_enable", &p->user_data_enable, 0);if (p->roi_enable) {mpp_enc_roi_init(&p->roi_ctx, p->width, p->height, p->type, 4);mpp_assert(p->roi_ctx);}RET:return ret;
}
MPP_RET test_ctx_deinit(MpiEncTestData *p)
{if (p) {
// if (p->cam_ctx) {
// camera_source_deinit(p->cam_ctx);
// p->cam_ctx = NULL;
// }if (p->fp_input) {fclose(p->fp_input);p->fp_input = NULL;}if (p->fp_output) {fclose(p->fp_output);p->fp_output = NULL;}if (p->fp_verify) {fclose(p->fp_verify);p->fp_verify = NULL;}}return MPP_OK;
}
// using namespace std;
// int isOpen = false;
// const char * fifo_name = "/home/orangepi/code/live/testProgs/pipe.264";
// int pipe_fd;
// int mpp_packet_write_to_fifo(void *ptr, size_t len)
// {
// int ret = 0;
// if(!isOpen)
// {
// qDebug()<<"start open the fifo file\n";
// pipe_fd = open(fifo_name, O_WRONLY); //阻塞至读端打开
// if(pipe_fd != -1)
// {
// qDebug()<<("open fifo success\n");
// // qDebug()<<("thread mpp_packet_write_to_fifo, pipe_fd = %d\n", pipe_fd);
// isOpen = true;
// //return pipe_fd;
// }
// else
// {
// qDebug()<<("pipe file open error %s\n", strerror(errno));
// return -1;
// // pthread_exit(NULL);
// }
// }
// ret = write(pipe_fd, ptr, len);
// if(ret != len)
// {
// printf("=======Write fifo Err======\n");
// return -1;
// }
// return 0;
// }
MPP_RET test_mpp_run(MpiEncMultiCtxInfo *info,cv::Mat pic,char* &fs,int & length)
{// MpiEncTestArgs *cmd = info->cmd;MpiEncTestData *p = &info->ctx;MppApi *mpi = p->mpi;MppCtx ctx = p->ctx;RK_U32 quiet = 0;RK_S32 chn = info->chn;RK_U32 cap_num = 0;DataCrc checkcrc;MPP_RET ret = MPP_OK;p->frame_count = 0;// 初始化 crc校验数据结构memset(&checkcrc, 0, sizeof(checkcrc));checkcrc.sum = mpp_malloc(RK_ULONG, 512);// 一次完整的调用 包括帧初始化 de初始化 还有填充 获取while (!p->pkt_eos) {MppMeta meta = NULL;MppFrame frame = NULL;MppPacket packet = NULL;void *buf = mpp_buffer_get_ptr(p->frm_buf);RK_S32 cam_frm_idx = -1;MppBuffer cam_buf = NULL;RK_U32 eoi = 1;// 数据实际输入int width = pic.rows;int height = pic.cols;int totalBytes = width * height * 3; // 3个通道(BGR)每个通道占一个字节memcpy(buf, pic.data, totalBytes);// if (p->fp_input) {// 测试图像 2 // int width = 1920;// int height = 1080;// // 创建一个空白图像,全黑// cv::Mat colorBar = cv::Mat::zeros(height, width, CV_8UC3);// // 设置彩条的宽度// int barWidth = width / 8; // 8个彩条,你可以根据需要调整// // 生成彩条// for (int i = 0; i < 8; ++i) {// // 计算彩条的起始和结束位置// int startX = i * barWidth;// int endX = (i + 1) * barWidth;// // 设置彩条颜色(BGR格式)// cv::Vec3b color;// if (i % 2 == 0) {// color = cv::Vec3b(255, 0, 0); // 蓝色// } else {// color = cv::Vec3b(0, 255, 0); // 绿色// }// // 在图像上画出彩条// colorBar(cv::Rect(startX, 0, barWidth, height)) = color;// }// int totalBytes = width * height * 3; // 3个通道(BGR)每个通道占一个字节// memcpy(buf, colorBar.data, totalBytes);// 测试图像// ret = read_image((RK_U8*)buf, p->fp_input, p->width, p->height,// p->hor_stride, p->ver_stride, p->fmt);// buf 存储图片数据 ,fp_input 应该是一个文件的fp 明天再开if (ret == MPP_NOK ) {p->frm_eos = 1;// 判定是否满足结束标志 满足则加一个eos帧if (p->frame_num < 0 || p->frame_count < p->frame_num) {clearerr(p->fp_input);rewind(p->fp_input);p->frm_eos = 0;mpp_log_q(quiet, "chn %d loop times %d\n", chn, ++p->loop_times);continue;}mpp_log_q(quiet, "chn %d found last frame. feof %d\n", chn, feof(p->fp_input));} else if (ret == MPP_ERR_VALUE)goto RET;// } ret = mpp_frame_init(&frame);if (ret) {mpp_err_f("mpp_frame_init failed\n");goto RET;}mpp_frame_set_width(frame, p->width);mpp_frame_set_height(frame, p->height);mpp_frame_set_hor_stride(frame, p->hor_stride);mpp_frame_set_ver_stride(frame, p->ver_stride);mpp_frame_set_fmt(frame, p->fmt);mpp_frame_set_eos(frame, p->frm_eos);// 使用我的分配内存的frm_buf指针 填充Frame mpp_frame_set_buffer(frame, p->frm_buf);meta = mpp_frame_get_meta(frame);mpp_packet_init_with_buffer(&packet, p->pkt_buf);/* NOTE: It is important to clear output packet length!! */mpp_packet_set_length(packet, 0);mpp_meta_set_packet(meta, KEY_OUTPUT_PACKET, packet);mpp_meta_set_buffer(meta, KEY_MOTION_INFO, p->md_info);// if (p->osd_enable || p->user_data_enable || p->roi_enable) {// if (p->user_data_enable) {// MppEncUserData user_data;// char *str = "this is user data\n";// if ((p->frame_count & 10) == 0) {// user_data.pdata = str;// user_data.len = strlen(str) + 1;// mpp_meta_set_ptr(meta, KEY_USER_DATA, &user_data);// }// static RK_U8 uuid_debug_info[16] = {// 0x57, 0x68, 0x97, 0x80, 0xe7, 0x0c, 0x4b, 0x65,// 0xa9, 0x06, 0xae, 0x29, 0x94, 0x11, 0xcd, 0x9a// };// MppEncUserDataSet data_group;// MppEncUserDataFull datas[2];// char *str1 = "this is user data 1\n";// char *str2 = "this is user data 2\n";// data_group.count = 2;// datas[0].len = strlen(str1) + 1;// datas[0].pdata = str1;// datas[0].uuid = uuid_debug_info;// datas[1].len = strlen(str2) + 1;// datas[1].pdata = str2;// datas[1].uuid = uuid_debug_info;// data_group.datas = datas;// mpp_meta_set_ptr(meta, KEY_USER_DATAS, &data_group);// }// if (p->osd_enable) {// /* gen and cfg osd plt */// mpi_enc_gen_osd_plt(&p->osd_plt, p->frame_count);// p->osd_plt_cfg.change = MPP_ENC_OSD_PLT_CFG_CHANGE_ALL;// p->osd_plt_cfg.type = MPP_ENC_OSD_PLT_TYPE_USERDEF;// p->osd_plt_cfg.plt = &p->osd_plt;// ret = mpi->control(ctx, MPP_ENC_SET_OSD_PLT_CFG, &p->osd_plt_cfg);// if (ret) {// mpp_err("mpi control enc set osd plt failed ret %d\n", ret);// goto RET;// }// /* gen and cfg osd plt */// mpi_enc_gen_osd_data(&p->osd_data, p->buf_grp, p->width,// p->height, p->frame_count);// mpp_meta_set_ptr(meta, KEY_OSD_DATA, (void*)&p->osd_data);// }// if (p->roi_enable) {// RoiRegionCfg *region = &p->roi_region;// /* calculated in pixels */// region->x = MPP_ALIGN(p->width / 8, 16);// region->y = MPP_ALIGN(p->height / 8, 16);// region->w = 128;// region->h = 256;// region->force_intra = 0;// region->qp_mode = 1;// region->qp_val = 24;// mpp_enc_roi_add_region(p->roi_ctx, region);// region->x = MPP_ALIGN(p->width / 2, 16);// region->y = MPP_ALIGN(p->height / 4, 16);// region->w = 256;// region->h = 128;// region->force_intra = 1;// region->qp_mode = 1;// region->qp_val = 10;// mpp_enc_roi_add_region(p->roi_ctx, region);// /* send roi info by metadata */// mpp_enc_roi_setup_meta(p->roi_ctx, meta);// }// }if (!p->first_frm)p->first_frm = mpp_time();/** NOTE: in non-block mode the frame can be resent.* The default input timeout mode is block.** User should release the input frame to meet the requirements of* resource creator must be the resource destroyer.*/ret = mpi->encode_put_frame(ctx, frame);if (ret) {mpp_err("chn %d encode put frame failed\n", chn);mpp_frame_deinit(&frame);goto RET;}mpp_frame_deinit(&frame);do {ret = mpi->encode_get_packet(ctx, &packet);if (ret) {mpp_err("chn %d encode get packet failed\n", chn);goto RET;}mpp_assert(packet);if (packet) {// write packet to file herevoid *ptr = mpp_packet_get_pos(packet);size_t len = mpp_packet_get_length(packet);char log_buf[256];RK_S32 log_size = sizeof(log_buf) - 1;RK_S32 log_len = 0;if (!p->first_pkt)p->first_pkt = mpp_time();p->pkt_eos = mpp_packet_get_eos(packet);if (p->fp_output){// fwrite(ptr, 1, len, p->fp_output);fs = (char*)malloc(len*sizeof(char));memcpy(fs, ptr, len);length = len;// fs = (char*)cpy;//pipe close
// if(mpp_packet_write_to_fifo(cpy, len) < 0)//阻塞
// {
// // goto RET;
// printf(" mpp_packet_write_to_fifo err \n");
// }// timeval ref;// gettimeofday(&ref, NULL);// fs->postFrame((char*)cpy,len,ref);}if (p->fp_verify && !p->pkt_eos) {calc_data_crc((RK_U8 *)ptr, (RK_U32)len, &checkcrc);mpp_log("p->frame_count=%d, len=%d\n", p->frame_count, len);write_data_crc(p->fp_verify, &checkcrc);}log_len += snprintf(log_buf + log_len, log_size - log_len,"encoded frame %-4d", p->frame_count);/* for low delay partition encoding */if (mpp_packet_is_partition(packet)) {eoi = mpp_packet_is_eoi(packet);log_len += snprintf(log_buf + log_len, log_size - log_len," pkt %d", p->frm_pkt_cnt);p->frm_pkt_cnt = (eoi) ? (0) : (p->frm_pkt_cnt + 1);}log_len += snprintf(log_buf + log_len, log_size - log_len," size %-7zu", len);if (mpp_packet_has_meta(packet)) {meta = mpp_packet_get_meta(packet);RK_S32 temporal_id = 0;RK_S32 lt_idx = -1;RK_S32 avg_qp = -1;if (MPP_OK == mpp_meta_get_s32(meta, KEY_TEMPORAL_ID, &temporal_id))log_len += snprintf(log_buf + log_len, log_size - log_len," tid %d", temporal_id);if (MPP_OK == mpp_meta_get_s32(meta, KEY_LONG_REF_IDX, <_idx))log_len += snprintf(log_buf + log_len, log_size - log_len," lt %d", lt_idx);if (MPP_OK == mpp_meta_get_s32(meta, KEY_ENC_AVERAGE_QP, &avg_qp))log_len += snprintf(log_buf + log_len, log_size - log_len," qp %d", avg_qp);}// mpp_log_q(quiet, "chn %d %s\n", chn, log_buf);mpp_packet_deinit(&packet);// fps_calc_inc(p->fps_out_num);p->stream_size += len;p->frame_count += eoi;if (p->pkt_eos) {mpp_log_q(quiet, "chn %d found last packet\n", chn);mpp_assert(p->frm_eos);}}} while (!eoi);if (p->frame_num > 0 && p->frame_count >= p->frame_num)break;if (p->frm_eos && p->pkt_eos)break;}
RET:MPP_FREE(checkcrc.sum);return ret;
}encoder::encoder()
{}int encoder::init(char * &fs,int &size)
{ memset(this->info,0,sizeof(MpiEncMultiCtxInfo));MpiEncTestData *p = &info->ctx;MpiEncMultiCtxRet *enc_ret = &info->ret;MppApi *mpi = p->mpi;MppCtx ctx = p->ctx;MppPollType timeout = MPP_POLL_BLOCK;MPP_RET ret = MPP_OK;RK_S64 t_s = 0;RK_S64 t_e = 0;RK_U32 quiet ;ret = test_ctx_init(info);if (ret) {mpp_err_f("test data init failed ret %d\n", ret);goto MPP_TEST_OUT;}ret = mpp_buffer_group_get_internal(&p->buf_grp, MPP_BUFFER_TYPE_DRM);if (ret) {mpp_err_f("failed to get mpp buffer group ret %d\n", ret);goto MPP_TEST_OUT;}ret = mpp_buffer_get(p->buf_grp, &p->frm_buf, p->frame_size + p->header_size);if (ret) {mpp_err_f("failed to get buffer for input frame ret %d\n", ret);goto MPP_TEST_OUT;}ret = mpp_buffer_get(p->buf_grp, &p->pkt_buf, p->frame_size);if (ret) {mpp_err_f("failed to get buffer for output packet ret %d\n", ret);goto MPP_TEST_OUT;}ret = mpp_buffer_get(p->buf_grp, &p->md_info, p->mdinfo_size);if (ret) {mpp_err_f("failed to get buffer for motion info output packet ret %d\n", ret);goto MPP_TEST_OUT;}// encoder demoret = mpp_create(&p->ctx, &p->mpi);if (ret) {mpp_err("mpp_create failed ret %d\n", ret);goto MPP_TEST_OUT;}mpp_log_q(quiet, "%p encoder test start w %d h %d type %d\n",p->ctx, p->width, p->height, p->type);ret = p->mpi->control(p->ctx, MPP_SET_OUTPUT_TIMEOUT, &timeout);if (MPP_OK != ret) {mpp_err("mpi control set output timeout %d ret %d\n", timeout, ret);goto MPP_TEST_OUT;}ret = mpp_init(p->ctx, MPP_CTX_ENC, p->type);if (ret) {mpp_err("mpp_init failed ret %d\n", ret);goto MPP_TEST_OUT;}ret = mpp_enc_cfg_init(&p->cfg);if (ret) {mpp_err_f("mpp_enc_cfg_init failed ret %d\n", ret);goto MPP_TEST_OUT;}ret = p->mpi->control(p->ctx, MPP_ENC_GET_CFG, p->cfg);if (ret) {mpp_err_f("get enc cfg failed ret %d\n", ret);goto MPP_TEST_OUT;}ret = test_mpp_enc_cfg_setup(info);if (ret) {mpp_err_f("test mpp setup failed ret %d\n", ret);goto MPP_TEST_OUT;}p->pkt_eos = 0;// prepare a frame headif (p->type == MPP_VIDEO_CodingAVC || p->type == MPP_VIDEO_CodingHEVC) {MppPacket packet = NULL;/** Can use packet with normal malloc buffer as input not pkt_buf.* Please refer to vpu_api_legacy.cpp for normal buffer case.* Using pkt_buf buffer here is just for simplifing demo.*/mpp_packet_init_with_buffer(&packet, p->pkt_buf);/* NOTE: It is important to clear output packet length!! */mpp_packet_set_length(packet, 0);ret = p->mpi->control(p->ctx, MPP_ENC_GET_HDR_SYNC, packet);if (ret) {mpp_err("mpi control enc get extra info failed\n");// goto RET;} else {/* get and write sps/pps for H.264 */void *ptr = mpp_packet_get_pos(packet);size_t len = mpp_packet_get_length(packet);if (p->fp_output)fs = (char*)malloc(len*sizeof(char));memcpy(fs, ptr, len);size = len;// fwrite(ptr, 1, len, p->fp_output);}mpp_packet_deinit(&packet);return 1;}MPP_TEST_OUT:if (p->ctx) {mpp_destroy(p->ctx);p->ctx = NULL;}if (p->cfg) {mpp_enc_cfg_deinit(p->cfg);p->cfg = NULL;}if (p->frm_buf) {mpp_buffer_put(p->frm_buf);p->frm_buf = NULL;}if (p->pkt_buf) {mpp_buffer_put(p->pkt_buf);p->pkt_buf = NULL;}if (p->md_info) {mpp_buffer_put(p->md_info);p->md_info = NULL;}if (p->osd_data.buf) {mpp_buffer_put(p->osd_data.buf);p->osd_data.buf = NULL;}if (p->buf_grp) {mpp_buffer_group_put(p->buf_grp);p->buf_grp = NULL;}if (p->roi_ctx) {mpp_enc_roi_deinit(p->roi_ctx);p->roi_ctx = NULL;}test_ctx_deinit(p);return 0;
}
MPP_RET encoder::postAframe(cv::Mat pic,char* &fs,int & length ){MPP_RET ret = MPP_NOK;MpiEncTestData *p = &info->ctx;ret = test_mpp_run(info,pic,fs,length);POST_OUT:return ret;}
int encoder::deinit(MPP_RET ret = MPP_OK){MpiEncTestData *p = &info->ctx;if (ret) {mpp_err_f("test mpp run failed ret %d\n", ret);goto POST_OUT;}ret = p->mpi->reset(p->ctx);if (ret) {mpp_err("mpi->reset failed\n");goto POST_OUT;}POST_OUT:// return ret;
if (p->ctx) {mpp_destroy(p->ctx);p->ctx = NULL;}if (p->cfg) {mpp_enc_cfg_deinit(p->cfg);p->cfg = NULL;}if (p->frm_buf) {mpp_buffer_put(p->frm_buf);p->frm_buf = NULL;}if (p->pkt_buf) {mpp_buffer_put(p->pkt_buf);p->pkt_buf = NULL;}if (p->md_info) {mpp_buffer_put(p->md_info);p->md_info = NULL;}if (p->osd_data.buf) {mpp_buffer_put(p->osd_data.buf);p->osd_data.buf = NULL;}if (p->buf_grp) {mpp_buffer_group_put(p->buf_grp);p->buf_grp = NULL;}if (p->roi_ctx) {mpp_enc_roi_deinit(p->roi_ctx);p->roi_ctx = NULL;}test_ctx_deinit(p);return 0;}
encoder::~encoder(){}
.h文件:
#ifndef ENCODER_H
#define ENCODER_H#include <string.h>
#include "rk_mpi.h"#include "mpp_env.h"
#include "mpp_mem.h"
#include "mpp_time.h"
#include "mpp_debug.h"
#include "mpp_common.h"#include "utils.h"
#include "mpi_enc_utils.h"
//#include "camera_source.h"
#include "mpp_enc_roi_utils.h"
#include "mpp_rc_api.h"
#include <opencv2/opencv.hpp>
// #include "H264_V4l2DeviceSource.h"typedef struct {// base flow contextMppCtx ctx;MppApi *mpi;RK_S32 chn;// global flow control flagRK_U32 frm_eos;RK_U32 pkt_eos;RK_U32 frm_pkt_cnt;RK_S32 frame_num;RK_S32 frame_count;RK_U64 stream_size;/* end of encoding flag when set quit the loop */volatile RK_U32 loop_end;// src and dstFILE *fp_input;FILE *fp_output;FILE *fp_verify;/* encoder config set */MppEncCfg cfg;MppEncPrepCfg prep_cfg;MppEncRcCfg rc_cfg;MppEncCodecCfg codec_cfg;MppEncSliceSplit split_cfg;MppEncOSDPltCfg osd_plt_cfg;MppEncOSDPlt osd_plt;MppEncOSDData osd_data;RoiRegionCfg roi_region;MppEncROICfg roi_cfg;// input / outputMppBufferGroup buf_grp;MppBuffer frm_buf;MppBuffer pkt_buf;MppBuffer md_info;MppEncSeiMode sei_mode;MppEncHeaderMode header_mode;// paramter for resource mallocRK_U32 width;RK_U32 height;RK_U32 hor_stride;RK_U32 ver_stride;MppFrameFormat fmt;MppCodingType type;RK_S32 loop_times;
// CamSource *cam_ctx;MppEncRoiCtx roi_ctx;// resourcessize_t header_size;size_t frame_size;size_t mdinfo_size;/* NOTE: packet buffer may overflow */size_t packet_size;RK_U32 osd_enable;RK_U32 osd_mode;RK_U32 split_mode;RK_U32 split_arg;RK_U32 split_out;RK_U32 user_data_enable;RK_U32 roi_enable;// rate control runtime parameterRK_S32 fps_in_flex;RK_S32 fps_in_den;RK_S32 fps_in_num;RK_S32 fps_out_flex;RK_S32 fps_out_den;RK_S32 fps_out_num;RK_S32 bps;RK_S32 bps_max;RK_S32 bps_min;RK_S32 rc_mode;RK_S32 gop_mode;RK_S32 gop_len;RK_S32 vi_len;RK_S32 scene_mode;RK_S64 first_frm;RK_S64 first_pkt;
} MpiEncTestData;/* For each instance thread return value */
typedef struct {float frame_rate;RK_U64 bit_rate;RK_S64 elapsed_time;RK_S32 frame_count;RK_S64 stream_size;RK_S64 delay;
} MpiEncMultiCtxRet;typedef struct {MpiEncTestArgs *cmd; // pointer to global command line infoconst char *name;RK_S32 chn;pthread_t thd; // thread for for each instanceMpiEncTestData ctx; // context of encoderMpiEncMultiCtxRet ret; // return of encoder
} MpiEncMultiCtxInfo;
class encoder
{
public:encoder();~encoder();int init(char * &fs,int &size);int deinit(MPP_RET ret );MPP_RET postAframe(cv::Mat pic,char* &fs,int & length );// void run();// void defaultInit();
private:MpiEncMultiCtxInfo *info = new MpiEncMultiCtxInfo ;};#endif // VIDEOTHREAD_H
main.cpp
#include "encoder.h"
#include "decoder.h"
#include "iostream"
#include <opencv2/opencv.hpp>
#include <opencv2/core/core.hpp>
#include <opencv2/highgui/highgui.hpp>
#include <fstream>
#include <sstream>
void writeCharPointerToFile(const char* data, std::size_t size, const std::string& filename) {// 打开文件std::ofstream file(filename, std::ios::binary);// 检查文件是否成功打开if (!file.is_open()) {std::cerr << "无法打开文件: " << filename << std::endl;return;}// 写入数据file.write(data, size);// 关闭文件file.close();
}
using namespace std;
using namespace cv;
int main(){std::string filename = "output.txt";int width = 1280;int height = 720;// 创建一个空白图像,全黑cv::Mat colorBar = cv::Mat::zeros(height, width, CV_8UC3);// 设置彩条的宽度int barWidth = width / 8; // 8个彩条,你可以根据需要调整// 生成彩条for (int i = 0; i < 8; ++i) {// 计算彩条的起始和结束位置int startX = i * barWidth;int endX = (i + 1) * barWidth;// 设置彩条颜色(BGR格式)cv::Vec3b color;if (i % 2 == 0) {color = cv::Vec3b(255, 0, 0); // 蓝色} else {color = cv::Vec3b(0, 255, 0); // 绿色}// 在图像上画出彩条colorBar(cv::Rect(startX, 0, barWidth, height)) = color;}int totalBytes = width * height * 3; // 3个通道(BGR)每个通道占一个字节// memcpy(buf, colorBar.data, totalBytes);imwrite("1.jpg",colorBar);encoder e;decoder d;char* frame;int len;e.init(frame,len);d.init();for(int i =0 ;i<1000;i++){e.postAframe(colorBar,frame,len);usleep(30*1000);writeCharPointerToFile(frame, len, filename);d.poststream(frame,len);}e.deinit(MPP_OK);return 0;
}
调试建议
一个是前面说的 -g,debug 看配置,再有就是上一篇编码gop设小一点,如果是实时流的话
然后就是看你输出的东西对不对劲了,这个我推荐一个软件HxD hex editor 看二进制,可以在他的读入文件那里用一个jpg图像或者用opencv保存一个bgr的彩条图像,然后直接使用图像编码模式编码出来一个264文件测试,逐帧保存结果。看和他的结果是否一样,如果完全一致就对了,不一致的话需要找找原因。
相关文章:
一套rk3588 rtsp服务器推流的 github 方案及记录 -02
整体方案参考上一篇博文 https://blog.csdn.net/qq_31764341/article/details/134810566 本篇博文主要介绍基于RK3588进行硬解码 还是之前的套路,我不生产代码,我只是代码的搬运工,今天我们搬运瑞芯微的官方代码,并记录下来整个调…...
docker运行java程序的Dockerfile
1,docker运行java程序的Dockerfile # 使用基础镜像 FROM alpine:latest # 暴露容器的端口 不会自动将容器的端口映射到宿主机上 docker run -d -p <宿主机端口>:7080 <镜像名称> EXPOSE 9202 EXPOSE 19202 #下载jdk8 RUN apk update && apk a…...
docker数据卷数据卷容器
前言 今天调休在家,随便玩玩,简单做下学习记录 1. 数据卷特点 数据卷在容器启动时初始化,如果容器使用的镜像在挂载点包含了数据,这些数据会被拷贝到新初始化的数据卷中数据卷可以在容器之间共享和重用可以对数据卷里的内容直接…...
使用HTTP协议有哪些风险?HTTP与HTTPS的区别是什么
作为两种常见的网络协议,HTTP和HTTPS都是用于在浏览器和服务器之间传输数据的。然而在保障数据安全性方面,HTTPS远远优于HTTP。在网络安全愈发重要的当下,HTTP协议的不安全性使得其逐渐被淘汰弃用。那么使用HTTP协议有哪些风险呢?…...
【jvm从入门到实战】(十) 实战篇-内存调优
内存溢出和内存泄漏:在Java中如果不再使用一个对象,但是该对象依然在GC ROOT的引用链上,这个对象就不会被垃圾回收器回收,这种情况就称之为内存泄漏。内存泄漏绝大多数情况都是由堆内存泄漏引起的。少量的内存泄漏可以容忍&#x…...
设计模式分类
不同设计模式的复杂程度、 细节层次以及在整个系统中的应用范围等方面各不相同。 我喜欢将其类比于道路的建造: 如果你希望让十字路口更加安全, 那么可以安装一些交通信号灯, 或者修建包含行人地下通道在内的多层互通式立交桥。 最基础的、 底…...
【前缀和】【单调栈】LeetCode2281:巫师的总力量和
作者推荐 map|动态规划|单调栈|LeetCode975:奇偶跳 涉及知识点 单调栈 C算法:前缀和、前缀乘积、前缀异或的原理、源码及测试用例 包括课程视频 题目 作为国王的统治者,你有一支巫师军队听你指挥。 给你一个下标从 0 开始的整数数组 strength &…...
力扣面试经典题之二叉树
104. 二叉树的最大深度 简单 给定一个二叉树 root ,返回其最大深度。 二叉树的 最大深度 是指从根节点到最远叶子节点的最长路径上的节点数。 示例 1: 输入:root [3,9,20,null,null,15,7] 输出:3示例 2: 输入…...
图灵日记之java奇妙历险记--数据类型与变量运算符
目录 数据类型与变量字面常量数据类型变量语法格式整型变量浮点型变量字符型变量希尔型变量类型转换自动类型转换(隐式)强制类型转换(显式) 类型提升不同数据类型的运算小于4字节数据类型的运算 字符串类型 运算符算术运算符关系运算符逻辑运算符逻辑与&&逻辑或||逻辑非…...
PhysX——源码编译
从git下载源码 git主页 https://github.com/NVIDIA-Omniverse/PhysXclone地址 https://github.com/NVIDIA-Omniverse/PhysX.git源码编译 运行PhysX需要两个编译器的支持,CMake 3.12 或以上版本以及Python 2.7.6 版本 进入工程的 physx 目录,运行generate…...
小鹅通基于 TSE 云原生 API 网关的落地实践
导语 2023腾讯全球数字生态大会已于9月7-8日完美落幕,40专场活动展示了腾讯最新的前沿技术、核心产品、解决方案。 微服务与消息队列专场,我们邀请到了小鹅通的基础架构组负责人黄徐震为我们带来了《小鹅通基于 TSE 云原生网关的落地实践》的精彩演讲。…...
Postgresql处理JSON类型中替换某个属性值问题
一、问题描述 使用postgresql对json的特性使用sql批量处理json中某个属性的值 结构如下: {"id": 1,"parentId": 123,"globalParameters": [{"value": "date","boardId": 123,"canReName":…...
@德人合科技——天锐绿盾 | 图纸加密软件有哪些功能呢?
德人合科技 | 天锐绿盾加密软件是一款全面保障企业电脑数据和安全使用的加密软件 PC端访问地址:www.drhchina.com 它的功能包括但不限于: 实时操作日志:可以实时详细地记录所有终端的操作日志,包括终端上窗口标题的变换、程序的…...
android 使用GSON 序列化对象出现字段被优化问题解决方案
一、问题描述 有以下结构: public class NativeParam<T> {private T data;public NativeParam(T data) {this.data data;}public T getData() {return data;}public void setData(T data) {this.data data;} };NativeParam<String> data "1.0…...
进入不了Bios?进入Bios的方法都在这了,肯定能进!
前言 有些小伙伴可能在重装系统的第一步就卡住了,接着就放弃了。哇哈哈哈啊,先让小白笑会~ 根据小白十二年的装机经验,不同主板进入Bios的时候有不同的姿势。也许要蹲着大喊Bios才能进入呢?要不试试? 好了…...
手把手教你基于 FastGPT 搭建个人知识库
前言 大家好,我是潇潇雨声。我发现在使用 GPT 时,尽管它能够生成一些小红书文案和日志,但内容常常显得空洞缺乏深度。今天我想分享一个解决这个问题的方法,那就是基于开源项目 FastGPT[1]。 我们可以通过向 GPT 提供一些有针对性的…...
gitee 怎么添加SSH密钥
要在Gitee上添加SSH密钥,请按照以下步骤操作: 登录到Gitee账户并导航到您要添加SSH密钥的存储库页面。点击页面右上方的“设置”按钮。在设置页面中,选择“SSH公钥”选项卡。点击“添加密钥”按钮。在弹出的对话框中,输入密钥标题…...
万界星空开源MES/注塑MES/开源注塑MES/免费MES/MES源码
一、系统概述: 万界星空科技免费MES、开源MES、商业开源MES、市面上最好的开源MES、MES源代码、适合二开的开源MES、好看的数据大屏、功能齐全开源mes. 1.万界星空开源MES制造执行系统的Java开源版本。 开源mes系统包括系统管理,车间基础数据管理&…...
macOS 开发 - MASShortcut
文章目录 关于 MASShortcut项目结构 快速使用源码学习检测是否有热键冲突处理 Event macOS 开发交流 秋秋群:644096295,V : ez-code 关于 MASShortcut MASShortcut 是一款快捷键管理工具,替代和兼容 ShortcutRecorder github : https://git…...
【大数据面试】Flink面试题附答案
目录 ✅Flink介绍、特点、应用场景 ✅Flink与Spark Streaming的区别 ✅Flink有哪些部署模式 ✅Flink架构 ✅怎么设置并行度? ✅什么是算子链? ✅什么是任务槽(Task Slots)? ✅任务槽和并行度的关系 ✅Flink作…...
Cursor实现用excel数据填充word模版的方法
cursor主页:https://www.cursor.com/ 任务目标:把excel格式的数据里的单元格,按照某一个固定模版填充到word中 文章目录 注意事项逐步生成程序1. 确定格式2. 调试程序 注意事项 直接给一个excel文件和最终呈现的word文件的示例,…...
模型参数、模型存储精度、参数与显存
模型参数量衡量单位 M:百万(Million) B:十亿(Billion) 1 B 1000 M 1B 1000M 1B1000M 参数存储精度 模型参数是固定的,但是一个参数所表示多少字节不一定,需要看这个参数以什么…...
微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
tree 树组件大数据卡顿问题优化
问题背景 项目中有用到树组件用来做文件目录,但是由于这个树组件的节点越来越多,导致页面在滚动这个树组件的时候浏览器就很容易卡死。这种问题基本上都是因为dom节点太多,导致的浏览器卡顿,这里很明显就需要用到虚拟列表的技术&…...
【Linux】Linux安装并配置RabbitMQ
目录 1. 安装 Erlang 2. 安装 RabbitMQ 2.1.添加 RabbitMQ 仓库 2.2.安装 RabbitMQ 3.配置 3.1.启动和管理服务 4. 访问管理界面 5.安装问题 6.修改密码 7.修改端口 7.1.找到文件 7.2.修改文件 1. 安装 Erlang 由于 RabbitMQ 是用 Erlang 编写的,需要先安…...
Pydantic + Function Calling的结合
1、Pydantic Pydantic 是一个 Python 库,用于数据验证和设置管理,通过 Python 类型注解强制执行数据类型。它广泛用于 API 开发(如 FastAPI)、配置管理和数据解析,核心功能包括: 数据验证:通过…...
webpack面试题
面试题:webpack介绍和简单使用 一、webpack(模块化打包工具)1. webpack是把项目当作一个整体,通过给定的一个主文件,webpack将从这个主文件开始找到你项目当中的所有依赖文件,使用loaders来处理它们&#x…...
Python环境安装与虚拟环境配置详解
本文档旨在为Python开发者提供一站式的环境安装与虚拟环境配置指南,适用于Windows、macOS和Linux系统。无论你是初学者还是有经验的开发者,都能在此找到适合自己的环境搭建方法和常见问题的解决方案。 快速开始 一分钟快速安装与虚拟环境配置 # macOS/…...
JavaScript 标签加载
目录 JavaScript 标签加载script 标签的 async 和 defer 属性,分别代表什么,有什么区别1. 普通 script 标签2. async 属性3. defer 属性4. type"module"5. 各种加载方式的对比6. 使用建议 JavaScript 标签加载 script 标签的 async 和 defer …...
Linux入门(十五)安装java安装tomcat安装dotnet安装mysql
安装java yum install java-17-openjdk-devel查找安装地址 update-alternatives --config java设置环境变量 vi /etc/profile #在文档后面追加 JAVA_HOME"通过查找安装地址命令显示的路径" #注意一定要加$PATH不然路径就只剩下新加的路径了,系统很多命…...
