.h264 .h265 压缩率的直观感受

1.资源文件  

https://download.csdn.net/download/twicave/89579327


上面是.264 .265和原始的YUV420文件,各自的大小。

2.转换工具:

2.1 .h264 .h265互转

可以使用ffmpeg工具:Builds - CODEX FFMPEG @ gyan.dev

命令行参数:

ffmpeg -i Tennis1080p.h264 -c:v libx265 -preset medium -crf 28 Tennis1080p.h265 

2.2 .h264 转 yuv

我因为要测试rk3588上一个硬件解码器,使用的是一个.c代码:

mpp-test: Rockchip MPP的简单案例

2.3 yuv file reader

 这个可以使用python直接处理,2.2代码里存储的YUV420SP格式我没有完全解出来,色彩不正:

import cv2
import numpy as npyuv_frame_pack_file = "Tennis1080p.yuv"def yuv420sp_to_rgb(yuv420sp_frame, width, height, format='NV21'):y_size = width * heightuv_size = (width * height) // 2# 分离 Y 分量y = yuv420sp_frame[:y_size].reshape((height, width))# 分离 UV 分量uv = yuv420sp_frame[y_size:y_size + uv_size]uv = uv.reshape((height // 2, width))  # UV 分量的宽度为原图的宽度,但高度为一半if format == 'NV12':u = uv[0::2, :]  # U分量v = uv[1::2, :]  # V分量elif format == 'NV21':v = uv[0::2, :]  # V分量u = uv[1::2, :]  # U分量else:raise ValueError("Unsupported format. Use 'NV12' or 'NV21'.")# 将U和V分量上采样到Y的分辨率u_upscaled = cv2.resize(u, (width, height), interpolation=cv2.INTER_LINEAR)v_upscaled = cv2.resize(v, (width, height), interpolation=cv2.INTER_LINEAR)# 合并Y, U, V分量为一个3通道的图像yuv_image = np.zeros((height + height // 2, width), dtype=np.uint8)yuv_image[:height, :] = yyuv_image[height:height + height // 4, :] = u_upscaled[:height // 4, :]yuv_image[height + height // 4:, :] = v_upscaled[:height // 4, :]# 转换到RGBrgb_image = cv2.cvtColor(yuv_image, cv2.COLOR_YUV2RGB_I420)return rgb_image# 设置图像的宽度和高度
width, height = 1920, 1080# 设置图像的宽度和高度
width, height = 1920, 1080# 读取一帧YUV420数据
cnt = 23  #控制跳过几帧。视频总帧数可以按照通过文件尺寸测算,YUV420系列一帧是1920*1080*1.5 Bytes.
with open(yuv_frame_pack_file , 'rb') as file:while(cnt>0):cnt -=1yuv420_frame = file.read(width * height * 3 // 2)  # YUV420格式,每帧大小为width * height * 3 / 2continueyuv420_frame = file.read(width * height * 3 // 2)  # YUV420格式,每帧大小为width * height * 3 / 2yuv420_frame = np.frombuffer(yuv420_frame, dtype=np.uint8)rgb_frame = yuv420sp_to_rgb(yuv420_frame, width, height)cv2.imshow('RGB Image', rgb_frame)cv2.waitKey(0)cv2.destroyAllWindows()

2.3.1解码效果

 

附录A h.265=>yuv frames file转换工具 

实际测试过程中,您可能需要对.h264, .h265的转换速度做比对,这里给出.h265转储为yuv frames file的C代码,相较2.2的原始c代码修改很少:

我只改了mpp_init,和需要处理的.h265文件名。

/*** 1. make* 2. ./mpp-dec-h264-to-yuv-file* 3. gst-launch-1.0 filesrc location=Tennis1080p.yuv ! videoparse width=1920 height=1080 format=nv12 ! videoconvert ! xvimagesink* 4. gst-launch-1.0 filesrc location=Tennis1080p.h264 ! h264parse ! mppvideodec ! xvimagesink*/
#include <unistd.h>
#include <stdio.h>
#include <rockchip/rk_mpi.h>#define __IN_FILE__ ("Tennis1080p.h265")
#define __OUT_FILE__ ("Tennis1080p.yuv")void dump_frame(MppFrame frame, FILE *out_fp)
{printf("dump_frame_to_file\n");RK_U32 width    = 0;RK_U32 height   = 0;RK_U32 h_stride = 0;RK_U32 v_stride = 0;MppFrameFormat fmt  = MPP_FMT_YUV420SP;MppBuffer buffer    = NULL;RK_U8 *base = NULL;width    = mpp_frame_get_width(frame);height   = mpp_frame_get_height(frame);h_stride = mpp_frame_get_hor_stride(frame);v_stride = mpp_frame_get_ver_stride(frame);fmt      = mpp_frame_get_fmt(frame);buffer   = mpp_frame_get_buffer(frame);RK_U32 buf_size = mpp_frame_get_buf_size(frame);printf("w x h: %dx%d hor_stride:%d ver_stride:%d buf_size:%d\n",width, height, h_stride, v_stride, buf_size);if (NULL == buffer) {printf("buffer is null\n");return ;}base = (RK_U8 *)mpp_buffer_get_ptr(buffer);// MPP_FMT_YUV420SPif (fmt != MPP_FMT_YUV420SP) {printf("fmt %d not supported\n", fmt);return;}RK_U32 i;RK_U8 *base_y = base;RK_U8 *base_c = base + h_stride * v_stride;for (i = 0; i < height; i++, base_y += h_stride) {fwrite(base_y, 1, width, out_fp);}for (i = 0; i < height / 2; i++, base_c += h_stride) {fwrite(base_c, 1, width, out_fp);}
}void dump_frame_to_file(MppCtx ctx, MppApi *mpi, MppFrame frame, FILE *out_fp)
{printf("decode_and_dump_to_file\n");MPP_RET ret;if (mpp_frame_get_info_change(frame)) {printf("mpp_frame_get_info_change\n");/*** 第一次解码会到这个分支,需要为解码器设置缓冲区.* 解码器缓冲区支持3种模式。参考【图像内存分配以及交互模式】Rockchip_Developer_Guide_MPP_CN.pdf* 这里使用纯内部模式。*/ret = mpi->control(ctx, MPP_DEC_SET_INFO_CHANGE_READY, NULL);if (ret) {printf("mpp_frame_get_info_change mpi->control error""MPP_DEC_SET_INFO_CHANGE_READY %d\n", ret);}return;}RK_U32 err_info = mpp_frame_get_errinfo(frame);RK_U32 discard = mpp_frame_get_discard(frame);    printf("err_info: %u discard: %u\n", err_info, discard);if (err_info) {return;}// savedump_frame(frame, out_fp);return;
}int main(void)
{printf("---------- mpp start ----------\n");// 1. 打开输入文件FILE *in_fp = fopen(__IN_FILE__, "rb");if (!in_fp) {printf("fopen error\n");return -1;}// 2. 打开输出文件FILE *out_fp = fopen(__OUT_FILE__, "wb+");if (!out_fp) {printf("fopen error\n");return -1;}// 3. 初始化解码器上下文,MppCtx MppApiMppCtx ctx = NULL;MppApi *mpi = NULL;MPP_RET ret = mpp_create(&ctx, &mpi);if (MPP_OK != ret) {printf("mpp_create error\n");return -1;}/*** 4. 配置解器*      - 解码文件需要 split 模式*      - 设置非阻塞模式,0非阻塞(默认),-1阻塞,+val 超时(ms)*/RK_U32 need_split = -1;ret = mpi->control(ctx, MPP_DEC_SET_PARSER_SPLIT_MODE, (MppParam*)&need_split);if (MPP_OK != ret) {printf("mpi->control error MPP_DEC_SET_PARSER_SPLIT_MODE\n");return -1;}ret = mpp_init(ctx, MPP_CTX_DEC, MPP_VIDEO_CodingHEVC);  // 固定为H265 https://blog.csdn.net/weixin_38807927/article/details/135760601if (MPP_OK != ret) {printf("mpp_init error\n");return -1;}// 5. 初始化包,MppPacketint buf_size = 5 * 1024 * 1024;char *buf = (char*)malloc(buf_size);if (!buf) {printf("malloc error\n");return -1;}MppPacket pkt = NULL;ret = mpp_packet_init(&pkt, buf, buf_size);if (MPP_OK != ret) {printf("mpp_packet_init error\n");return -1;}// 6. 循环读取文件,输入解码器,解码,保存结果int over = 0;while (!over) {printf("decode...\n");int len = fread(buf, 1, buf_size, in_fp);printf("read file length:%d\n", len);if (0 < len) {mpp_packet_write(pkt, 0, buf, len);mpp_packet_set_pos(pkt, buf);mpp_packet_set_length(pkt, len);if (feof(in_fp) || len < buf_size) {  // 文件读完,设置结束标志位mpp_packet_set_eos(pkt);printf("mpp_packet_set_eos\n");}}/*** decode_put_packet返回失败,意味着内部缓冲区已满。* 非阻塞模式,使用pkt_is_send判断当前读取的数据包(buf)是否成功发送。*/int pkt_is_send = 0;while (!pkt_is_send && !over) {if (0 < len) {printf("pkt remain:%d\n", mpp_packet_get_length(pkt));ret = mpi->decode_put_packet(ctx, pkt);if (MPP_OK == ret) {printf("pkt send success remain:%d\n", mpp_packet_get_length(pkt));pkt_is_send = 1;}}MppFrame frame;MPP_RET ret;ret = mpi->decode_get_frame(ctx, &frame);if (MPP_OK != ret || !frame) {printf("decode_get_frame falied ret:%d\n", ret);usleep(2000);  // 等待一下2ms,通常1080p解码时间2mscontinue;}printf("decode_get_frame success\n");dump_frame_to_file(ctx, mpi, frame, out_fp);if (mpp_frame_get_eos(frame)) {printf("mpp_frame_get_eos\n");mpp_frame_deinit(&frame);over = 1;continue;}mpp_frame_deinit(&frame);}}// 7. 释放资源fclose(in_fp);fclose(out_fp);mpi->reset(ctx);mpp_packet_deinit(&pkt);mpp_destroy(ctx);free(buf);printf("---------- mpp over ----------\n");return 0;
}

A.1相应的make file :

将文件放置在.c文件的同级目录,命名为:makefile

app: mpp-dec-h264-to-yuv-file.c mpp-multi-thread-demo.c mpp-dec-h265-to-yuv-file.cgcc mpp-dec-h264-to-yuv-file.c -o mpp-dec-h264-to-yuv-file -lrockchip_mppgcc mpp-dec-h265-to-yuv-file.c -o mpp-dec-h265-to-yuv-file -lrockchip_mppgcc mpp-multi-thread-demo.c -o mpp-multi-thread-demo -lrockchip_mpp -lpthread -I/usr/include/glib-2.0 -I/usr/lib/aarch64-linux-gnu/glib-2.0/include -lglib-2.0

需要编译时:执行

make

即可。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://xiahunao.cn/news/3266127.html

如若内容造成侵权/违法违规/事实不符,请联系瞎胡闹网进行投诉反馈,一经查实,立即删除!

相关文章

渗透测试——prime1靶场实战演练{常用工具}端口转发

文章目录 概要信息搜集 概要 靶机地址&#xff1a;https://www.vulnhub.com/entry/prime-1,358 信息搜集 nmap 扫网段存活ip及端口 找到除了网关外的ip&#xff0c;开放了80端口&#xff0c;登上去看看 是一个网站&#xff0c;直接上科技扫一扫目录 python dirsearch.py -u …

{Spring Boot 原理篇} Spring Boot自动装配原理

SpringBootApplication 1&#xff0c;Spring Boot 应用启动&#xff0c;SpringBootApplication标注的类就是启动类&#xff0c;它去实现配置类中的Bean的自动装配 SpringBootApplication public class SpringbootRedis01Application {public static void main(String[] args)…

GRE VPN和MGRE VPN综合练习

GRE VPN和MGRE VPN综合练习 实验拓扑 实验要求 1、R5为ISP&#xff0c;只能进行IP地址配置&#xff0c;其所有地址均配为公有IP地址; 2、R1和R5间使用PPP的PAP认证&#xff0c;R5为主认证方; R2与R5之间使用ppp的CHAP认证&#xff0c;R5为主认证方; R3与R5之间使用HDLC封装;…

【JavaScript】深入理解 `let`、`var` 和 `const`

文章目录 一、var 的声明与特点二、let 的声明与特点三、const 的声明与特点四、let、var 和 const 的对比五、实战示例六、最佳实践 在 JavaScript 中&#xff0c;变量声明是编程的基础&#xff0c;而 let、var 和 const 是三种常用的变量声明方式。本文将详细介绍这三种变量声…

做一个能和你互动玩耍的智能机器人之一

2024年被很多人称为AI元年&#xff0c;其实AI元年的叫法由来以久&#xff0c;近年来每一次AI技术的进步&#xff0c;都有很多圈内人大呼AI元年&#xff0c;但不仅一直风声不大&#xff0c;雨点也偏小&#xff0c;都是小范围交流。 得益于软硬件的进步&#xff0c;AI今年开始侵…

秋招突击——7/23——百度提前批面试准备和正式面试

文章目录 引言一面准备面试预演一1、讲一下hashcode()和equals()关系2、equals()和有什么区别3、讲一下重载和重写的区别4、讲一下深拷贝、浅拷贝的区别5、讲一下Java异常的基类&#xff0c;运行时异常举几个例子&#xff0c;什么情况下会出现&#xff1f;6、讲一下Java中线程的…

pytorch前馈神经网络--手写数字识别

前言 具体内容就是&#xff1a; 输入一个图像&#xff0c;经过神经网络后&#xff0c;识别为一个数字。从而实现图像的分类。 资源&#xff1a; https://download.csdn.net/download/fengzhongye51460/89578965 思路&#xff1a; 确定输入的图像&#xff1a;会单通道灰度的…

基于dcm4chee搭建的PACS系统讲解(三)服务端使用Rest API获取study等数据

文章目录 DICOMWeb Support模块主要数据结构ER查询信息基本信息metadata信息统计信息 实践查询API及参数解析API返回的json数组定义VRObjectNodeObjectMapper解析显示指定tag并解析 后记 前期预研的PACS系统&#xff0c;近期要在项目中上线了。因为PACS系统采用无权限认证&…

【初阶数据结构】8.二叉树(3)

文章目录 4.实现链式结构二叉树4.1 前中后序遍历4.1.1 遍历规则4.1.2 代码实现 4.2 结点个数以及高度等4.3 层序遍历4.4 判断是否为完全二叉树4.5层序遍历和判断是否为完全二叉树完整代码 4.实现链式结构二叉树 用链表来表示一棵二叉树&#xff0c;即用链来指示元素的逻辑关系…

减轻幻觉新SOTA,7B模型自迭代训练效果超越GPT-4,上海AI lab发布

LLMs在回答各种复杂问题时&#xff0c;有时会“胡言乱语”&#xff0c;产生所谓的幻觉。解决这一问题的初始步骤就是创建高质量幻觉数据集训练模型以帮助检测、缓解幻觉。 但现有的幻觉标注数据集&#xff0c;因为领域窄、数量少&#xff0c;加上制作成本高、标注人员水平不一…

php反序列化--前置知识

&#x1f3bc;个人主页&#xff1a;金灰 &#x1f60e;作者简介:一名简单的大一学生;易编橙终身成长社群的嘉宾.✨ 专注网络空间安全服务,期待与您的交流分享~ 感谢您的点赞、关注、评论、收藏、是对我最大的认可和支持&#xff01;❤️ &#x1f34a;易编橙终身成长社群&#…

文件共享功能无法使用提示错误代码0x80004005【笔记】

环境情况&#xff1a; 其他电脑可以正常访问共享端&#xff0c;但有一台电脑访问提示错误代码0x80004005。 处理检查&#xff1a; 搜索里输入“启用或关闭Windows功能”按回车键&#xff0c;在“启用或关闭Windows功能”里将“SMB 1.0/CIFS文件共享支持”勾选后&#xff08;故…

不同行情下算法的具体使用!

上一篇我们说到了不同公司算法交易的区分&#xff0c;有朋友提出了不同的行情下的算法交易应该怎么使用&#xff0c;小编今天就带大家了解下&#xff01;当然具体实际状况百出&#xff0c;这种可以实际为准&#xff08;韭菜修养全拼实际探讨交流&#xff09;&#xff01; 我们在…

qt做的分页控件

介绍 qt做的分页控件 如何使用 创建 Pagination必须基于一个QWidget创建&#xff0c;否则会引发错误。 Pagination* pa new Pagination(QWidget*);设置总页数 Pagination需要设置一个总的页数&#xff0c;来初始化页码。 pa->SetTotalItem(count);设置可选的每页数量…

Java 每日一题: for 与 foreach 的区别 ?

for 循环&#xff1a;是最基本的循环结构&#xff0c;可以通过初始化语句、循环条件和迭代语句来控制循环的执行。 foreach 循环&#xff08;也称为增强型 for 循环&#xff09;&#xff1a;用于遍历集合或数组中的元素&#xff0c;简化了遍历过程&#xff0c;没有显式地控制索…

[STM32]HAL库实现自己的BootLoader-BootLoader与OTA-STM32CUBEMX

目录 一、前言 二、BootLoader 三、BootLoader的实现 四、APP程序 五、效果展示 六、拓展 一、前言 听到BootLoader大家一定很熟悉&#xff0c;在很多常见的系统中都会存在BootLoader。本文将介绍BootLoader的含义和简易实现&#xff0c;建议大家学习前掌握些原理基础。 …

全链路追踪 性能监控,GO 应用可观测全面升级

作者&#xff1a;古琦 01 介绍 随着 Kubernetes 和容器化技术的普及&#xff0c;Go 语言不仅在云原生基础组件领域广泛应用&#xff0c;也在各类业务场景中占据了重要地位。如今&#xff0c;越来越多的新兴业务选择 Golang 作为首选编程语言。得益于丰富的 RPC 框架&#xff…

编程类精品GPTs

文章目录 编程类精品GPTs前言种类ChatGPT - GrimoireProfessional-coder-auto-programming 总结 编程类精品GPTs 前言 代码类的AI, 主要看以下要点: 面对含糊不清的需求是否能引导出完整的需求面对完整的需求是否能分步编写代码完成需求编写的代码是否具有可读性和可扩展性 …

力扣算法题:矩阵(玄幻不变量法),链表(虚拟头节点,递归法)

20240725 一、矩阵54.螺旋矩阵(循环不变量) 二、链表1 移除链表元素1.1 原链表删除元素&#xff1a;1.2 虚拟头节点&#xff08;&#xff01;&#xff01;&#xff01;&#xff09; 2. 设计链表206. 反转链表(双向指针和递归)双指针递归 交换链表中的元素虚拟头节点法递归法 删…

如何解决 Nginx 与边缘计算节点的集成问题?

&#x1f345;关注博主&#x1f397;️ 带你畅游技术世界&#xff0c;不错过每一次成长机会&#xff01; 文章目录 如何解决 Nginx 与边缘计算节点的集成问题&#xff1f;一、理解集成的需求和目标二、解决网络配置问题三、优化 Nginx 配置四、处理安全与认证问题五、监控与调试…