61
- 收藏
- 点赞
- 分享
- 举报
自己手动创建venc通道后,通过ss_mpi_vb_get_blk获取vb将yuv填充之后进行编码,请问什么时候进行vb blk的释放?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <pthread.h>
#include <signal.h>
#include "sample_comm.h"
#include "ot_common.h"
#include "ot_common_video.h"
#include "ot_common_venc.h"
#include "ss_mpi_venc.h"
#include "ss_mpi_vb.h"
#include "ss_mpi_sys.h" // 添加系统映射相关头文件
static td_bool g_sample_venc_exit = TD_FALSE;
/* 信号处理 */
static td_void sample_venc_handle_sig(td_s32 signo)
{
if (signo == SIGINT || signo == SIGTERM) {
g_sample_venc_exit = TD_TRUE;
}
}
/* 创建VENC通道 */
static td_s32 sample_venc_create_chn_direct(ot_venc_chn venc_chn, ot_size *size,
ot_payload_type type)
{
td_s32 ret;
ot_venc_chn_attr chn_attr = {0};
// 1. 配置编码属性
chn_attr.venc_attr.type = type;
chn_attr.venc_attr.max_pic_width = size->width;
chn_attr.venc_attr.max_pic_height = size->height;
chn_attr.venc_attr.buf_size = size->width * size->height * 3 / 2;
chn_attr.venc_attr.pic_width = size->width;
chn_attr.venc_attr.pic_height = size->height;
chn_attr.venc_attr.is_by_frame = TD_TRUE;
if (type == OT_PT_H264) {
chn_attr.venc_attr.profile = 0; // Baseline Profile
// H.264 特定属性
chn_attr.venc_attr.h264_attr.rcn_ref_share_buf_en = TD_FALSE;
chn_attr.venc_attr.h264_attr.frame_buf_ratio = 70;
} else if (type == OT_PT_H265) {
chn_attr.venc_attr.profile = 0; // Main Profile
// H.265 特定属性
chn_attr.venc_attr.h265_attr.rcn_ref_share_buf_en = TD_FALSE;
chn_attr.venc_attr.h265_attr.frame_buf_ratio = 70;
}
// 2. 配置码率控制(CBR模式)
chn_attr.rc_attr.rc_mode = OT_VENC_RC_MODE_H264_CBR; // 修正:使用通用的CBR模式
// 配置CBR参数
if (type == OT_PT_H264) {
chn_attr.rc_attr.h264_cbr.gop = 30;
chn_attr.rc_attr.h264_cbr.stats_time = 1;
chn_attr.rc_attr.h264_cbr.src_frame_rate = 30;
chn_attr.rc_attr.h264_cbr.dst_frame_rate = 30;
chn_attr.rc_attr.h264_cbr.bit_rate = 2000; // 2Mbps
} else if (type == OT_PT_H265) {
chn_attr.rc_attr.h265_cbr.gop = 30;
chn_attr.rc_attr.h265_cbr.stats_time = 1;
chn_attr.rc_attr.h265_cbr.src_frame_rate = 30;
chn_attr.rc_attr.h265_cbr.dst_frame_rate = 30;
chn_attr.rc_attr.h265_cbr.bit_rate = 2000; // 2Mbps
}
// 3. 配置GOP属性(使用正常P帧模式)
chn_attr.gop_attr.gop_mode = OT_VENC_GOP_MODE_NORMAL_P;
chn_attr.gop_attr.normal_p.ip_qp_delta = 0;
// 4. 创建通道
ret = ss_mpi_venc_create_chn(venc_chn, &chn_attr);
if (ret != TD_SUCCESS) {
printf("Create venc chn failed! ret = 0x%x\n", ret);
return ret;
}
ot_venc_start_param start_param;
/* step 2: start recv venc pictures */
start_param.recv_pic_num = -1;
if ((ret = ss_mpi_venc_start_chn(venc_chn, &start_param)) != TD_SUCCESS) {
ss_mpi_venc_destroy_chn(venc_chn);
sample_print("ss_mpi_venc_start_recv_pic failed with%#x! \n", ret);
return TD_FAILURE;
}
return TD_SUCCESS;
}
/* 使用VB块送帧 - 改进版本 */
static td_s32 sample_venc_send_yuv_with_vb(ot_venc_chn venc_chn,
td_u8 *yuv_data,
ot_size *size,
td_u64 pts)
{
td_s32 ret = TD_FAILURE;
ot_video_frame_info frame_info = {0};
ot_video_frame *vframe = &frame_info.video_frame;
ot_vb_blk vb_blk = OT_VB_INVALID_HANDLE;
td_u32 stride = OT_ALIGN_UP(size->width, 16);
td_u32 aligned_height = OT_ALIGN_UP(size->height, 2);
td_u32 aligned_frame_size = stride * aligned_height * 3 / 2;
td_void *virt_addr = TD_NULL;
td_phys_addr_t phys_addr = 0;
// 检查输入参数
if (yuv_data == TD_NULL || size == TD_NULL) {
printf("Invalid input parameters!\n");
return TD_FAILURE;
}
if (size->width == 0 || size->height == 0) {
printf("Invalid size: %dx%d\n", size->width, size->height);
return TD_FAILURE;
}
// 1. 申请VB块
vb_blk = ss_mpi_vb_get_blk(OT_VB_INVALID_POOL_ID, aligned_frame_size, TD_NULL);
if (vb_blk == OT_VB_INVALID_HANDLE) {
printf("Get vb block failed! requested size=%u\n", aligned_frame_size);
return TD_FAILURE;
}
// 2. 获取物理地址
phys_addr = ss_mpi_vb_handle_to_phys_addr(vb_blk);
if (phys_addr == 0) {
printf("Get phys addr failed!\n");
goto cleanup;
}
// 3. 映射虚拟地址
virt_addr = ss_mpi_sys_mmap(phys_addr, aligned_frame_size);
if (virt_addr == TD_NULL) {
printf("ss_mpi_sys_mmap failed!\n");
goto cleanup;
}
// 4. 配置帧信息
vframe->width = size->width;
vframe->height = size->height;
vframe->pixel_format = OT_PIXEL_FORMAT_YVU_SEMIPLANAR_420;
vframe->video_format = OT_VIDEO_FORMAT_LINEAR;
vframe->compress_mode = OT_COMPRESS_MODE_NONE;
vframe->dynamic_range = OT_DYNAMIC_RANGE_SDR8;
vframe->color_gamut = OT_COLOR_GAMUT_BT601;
vframe->field = OT_VIDEO_FIELD_FRAME;
// 5. 设置地址
vframe->phys_addr[0] = phys_addr;
vframe->phys_addr[1] = phys_addr + stride * aligned_height;
vframe->virt_addr[0] = virt_addr;
vframe->virt_addr[1] = (td_u8 *)virt_addr + stride * aligned_height;
// 6. 设置跨步
vframe->stride[0] = stride;
vframe->stride[1] = stride;
vframe->pts = pts;
vframe->time_ref = pts;
vframe->frame_flag = 0;
// 7. 拷贝数据
td_u8 *src_y = yuv_data;
td_u8 *src_uv = yuv_data + size->width * size->height;
td_u8 *dst_y = (td_u8 *)vframe->virt_addr[0];
td_u8 *dst_uv = (td_u8 *)vframe->virt_addr[1];
td_u32 y_plane_size = size->width * size->height;
td_u32 uv_plane_size = size->width * size->height / 2;
// 直接拷贝整个平面(假设数据已经是连续的)
if (memcpy_s(dst_y, y_plane_size, src_y, y_plane_size) != EOK ||
memcpy_s(dst_uv, uv_plane_size, src_uv, uv_plane_size) != EOK) {
printf("Copy yuv data failed!\n");
goto cleanup;
}
ss_mpi_sys_munmap(virt_addr, aligned_frame_size);
virt_addr = TD_NULL;
// 8. 设置frame_info的其他成员
frame_info.pool_id = 0;
frame_info.mod_id = OT_ID_VENC;
// 9. 送帧
ret = ss_mpi_venc_send_frame(venc_chn, &frame_info, 100);
if (ret != TD_SUCCESS) {
printf("Send frame to venc chn %d failed! ret=0x%x\n", venc_chn, ret);
}
// VB块由VENC管理,不需要在这里释放
return ret;
cleanup:
if (virt_addr != TD_NULL) {
ss_mpi_sys_munmap(virt_addr, aligned_frame_size);
}
if (vb_blk != OT_VB_INVALID_HANDLE) {
ss_mpi_vb_release_blk(vb_blk);
}
return TD_FAILURE;
}
/* 简化的送帧函数(测试用) */
static td_s32 sample_venc_send_test_frame(ot_venc_chn venc_chn, ot_size *size)
{
td_s32 ret;
static td_u64 frame_count = 0;
// 创建测试YUV数据(纯色帧)
static td_u8 yuv_data[1920 * 1080 * 3 / 2];
static td_bool initialized = TD_FALSE;
// 初始化YUV数据
if (!initialized) {
// Y分量
td_u32 y_size = size->width * size->height;
for (td_u32 i = 0; i < y_size; i++) {
yuv_data[i] = 0x80; // 灰色
}
// UV分量
td_u32 uv_size = y_size / 2;
for (td_u32 i = 0; i < uv_size; i++) {
yuv_data[y_size + i] = 0x80;
}
initialized = TD_TRUE;
}
// 使用VB块发送
ret = sample_venc_send_yuv_with_vb(venc_chn, yuv_data, size, frame_count * 30000);
//ret = sample_venc_send_yuv_user(venc_chn, yuv_data, size, frame_count * 30000);
if (ret == TD_SUCCESS) {
frame_count++;
}
return ret;
}
/* 码流获取线程 */
static td_void* sample_venc_get_stream_thread(td_void *args)
{
ot_venc_chn venc_chn = *(ot_venc_chn*)args;
ot_venc_stream stream = {0};
td_s32 ret;
FILE *fp = fopen("output.h264", "wb");
td_u32 frame_count = 0;
if (!fp) {
printf("Open output file failed!\n");
return TD_NULL;
}
printf("Start stream thread for chn %d\n", venc_chn);
// 分配pack数组
ot_venc_pack pack_array[10] = {0};
stream.pack = pack_array;
stream.pack_cnt = 10;
while (!g_sample_venc_exit) {
// 获取码流
ret = ss_mpi_venc_get_stream(venc_chn, &stream, 1000);
if (ret == TD_SUCCESS) {
// 保存码流
for (td_u32 i = 0; i < stream.pack_cnt; i++) {
if (pack_array[i].addr != TD_NULL && pack_array[i].len > 0) {
fwrite(pack_array[i].addr, 1, pack_array[i].len, fp);
fflush(fp);
}
}
// 检查帧类型
if (stream.pack_cnt > 0) {
ot_venc_data_type *data_type = &pack_array[0].data_type;
if (data_type->h264_type == OT_VENC_H264_NALU_IDR_SLICE ||
data_type->h264_type == OT_VENC_H264_NALU_I_SLICE) {
printf("I/IDR frame: size=%u, pts=%llu\n",
pack_array[0].len, pack_array[0].pts);
}
}
frame_count++;
if (frame_count % 30 == 0) {
printf("Encoded %d frames\n", frame_count);
}
// 释放码流
ss_mpi_venc_release_stream(venc_chn, &stream);
} else if (ret == OT_ERR_VENC_BUF_EMPTY) {
usleep(10000);
} else {
printf("Get stream failed! ret = 0x%x\n", ret);
break;
}
}
fclose(fp);
printf("Stream thread exit, total frames: %d\n", frame_count);
return TD_NULL;
}
/* 主函数 */
td_s32 sample_venc_direct_encode_test(td_void)
{
td_s32 ret;
ot_venc_chn venc_chn = 0;
ot_size enc_size = {1920, 1080};
pthread_t stream_thread;
td_u32 i;
printf("=== Direct YUV to H.264 Encoding Test ===\n");
ss_mpi_sys_exit();
ss_mpi_vb_exit();
// 0. 信号处理
signal(SIGINT, sample_venc_handle_sig);
// 1. 系统初始化
ot_vb_cfg vb_cfg = {0};
vb_cfg.max_pool_cnt = 1;
vb_cfg.common_pool[0].blk_size = enc_size.width * enc_size.height * 3 / 2;
vb_cfg.common_pool[0].blk_cnt = 200;
vb_cfg.common_pool[0].remap_mode = OT_VB_REMAP_MODE_NONE;
ret = ss_mpi_vb_set_cfg(&vb_cfg);
if (ret != TD_SUCCESS) {
printf("Set vb cfg failed! ret = 0x%x\n", ret);
return ret;
}
ret = ss_mpi_vb_init();
if (ret != TD_SUCCESS) {
printf("VB init failed! ret = 0x%x\n", ret);
return ret;
}
printf("Step 2: Initialize SYS...\n");
ret = ss_mpi_sys_init();
if (ret != TD_SUCCESS) {
printf("SYS Init failed: 0x%x\n", ret);
ss_mpi_vb_exit();
return ret;
}
// 2. VENC初始化 - 修正:通常不需要显式初始化VENC
// 直接创建通道即可,系统会自动初始化VENC模块
// 3. 创建编码通道
printf("Creating VENC channel...\n");
ret = sample_venc_create_chn_direct(venc_chn, &enc_size, OT_PT_H264);
if (ret != TD_SUCCESS) {
printf("Create VENC channel failed!\n");
goto EXIT_VB;
}
// 4. 启动码流获取线程
printf("Starting stream thread...\n");
if (pthread_create(&stream_thread, NULL, sample_venc_get_stream_thread, &venc_chn) != 0) {
printf("Create thread failed!\n");
goto EXIT_DESTROY_CHN;
}
// 5. 编码循环
printf("Start encoding... (Press Ctrl+C to stop)\n");
for (i = 0; i < 300 && !g_sample_venc_exit; i++) {
ret = sample_venc_send_test_frame(venc_chn, &enc_size);
if (ret != TD_SUCCESS) {
printf("Send frame %d failed! ret = 0x%x\n", i, ret);
exit(-1);
}
usleep(33333); // 30fps
if (i % 30 == 0) {
printf("Sent %d frames\n", i);
}
}
printf("Encoding finished\n");
// 6. 发送结束帧
ot_video_frame_info end_frame = {0};
end_frame.video_frame.frame_flag = OT_FRAME_FLAG_SNAP_END;
ss_mpi_venc_send_frame(venc_chn, &end_frame, 1000);
// 7. 等待线程结束
g_sample_venc_exit = TD_TRUE;
sleep(2);
pthread_join(stream_thread, NULL);
EXIT_DESTROY_CHN:
// 8. 清理资源
printf("Cleaning up...\n");
ss_mpi_venc_destroy_chn(venc_chn);
// 注意:没有 ss_mpi_venc_exit() 函数,只需要销毁通道即可
EXIT_VB:
ss_mpi_sys_exit();
ss_mpi_vb_exit();
printf("Test completed!\n");
return TD_SUCCESS;
}
/* 简单的主函数 */
#ifdef __LITEOS__
td_s32 app_main(td_s32 argc, td_char *argv[])
#else
td_s32 main(td_s32 argc, td_char *argv[])
#endif
{
td_s32 ret;
signal(SIGINT, sample_venc_handle_sig);
ret = sample_venc_direct_encode_test();
if (ret == TD_SUCCESS) {
printf("Program exit normally!\n");
} else {
printf("Program exit with error!\n");
}
return ret;
}
我来回答
回答3个
时间排序
认可量排序
认可2
或将文件直接拖到这里
悬赏:
E币
网盘
* 网盘链接:
* 提取码:
悬赏:
E币
Markdown 语法
- 加粗**内容**
- 斜体*内容*
- 删除线~~内容~~
- 引用> 引用内容
- 代码`代码`
- 代码块```编程语言↵代码```
- 链接[链接标题](url)
- 无序列表- 内容
- 有序列表1. 内容
- 缩进内容
- 图片
相关问答
-
2023-10-26 21:06:31
-
2025-03-10 09:38:39
-
2026-01-16 19:29:07
-
2020-03-30 21:55:00
-
102018-12-17 20:42:40
-
2019-12-07 10:44:11
-
2025-09-22 23:54:23
-
2017-08-25 14:40:08
-
2024-12-20 17:42:35
-
2017-08-02 10:13:29
-
2021-02-21 11:02:22
-
2017-04-26 09:22:30
-
2019-07-12 18:29:38
-
2018-09-15 15:25:08
-
2017-03-28 11:30:23
-
2015-10-28 16:55:58
-
2024-03-13 09:12:48
-
2019-12-31 10:37:13
-
2017-05-10 11:51:32
无更多相似问答 去提问
点击登录
-- 积分
-- E币
提问
—
收益
—
被采纳
—
我要提问
切换马甲
上一页
下一页
悬赏问答
-
10hi35169dv500平台使用http协议推拉流UVC摄像头,帧率问题
-
10hi3516cv610关于YOLO优化和调优问题
-
10hi_mpi_vpss_get_chn_frame err:0xa0078016报错
-
5gk7205v200(hisi3516ev200)如何接入b656?
-
30pipe管道创建失败
-
10atc转换模型失败
-
20拍摄静止画面显示正常,拍摄运动的画面出现马赛克显示
-
100hi3516cv610 通过易百纳官方SDK中编译出的uboot env kernel,移植到自己的工程中,MPP初始化时出现内核拷贝数据到用户端时出现错误导致内核进入pain模式进而时内核重启
-
5hisi3519 gs2972 bt1120 转sdi 无法正常显示问题
-
5hisi3516cv610 + gc4336p 夜晚很模糊
举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
提醒
你的问题还没有最佳答案,是否结题,结题后将扣除20%的悬赏金
取消
确认
提醒
你的问题还没有最佳答案,是否结题,结题后将根据回答情况扣除相应悬赏金(1回答=1E币)
取消
确认

微信扫码分享
QQ好友