瑞芯微平台H.265 真实视频分辨率获取例程 - in python

news2024/9/9 4:58:07

1.直接下载封装后的python模块

如果你并不关心内部的技术细节,可以直接下载封装好的python模块:

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

2.源码和原理说明

下面包含了所有的代码, 你可以自行组装:

2.0 目录结构:

4.0K    ./sub/fetch_from_stream.py
4.0K    ./sub/get_h265_resolution_of_stream.sh
3.6M    ./sub/frame_by_soft_decode_of_h265file.bin
4.0K    ./sub/get_h265_resolution_of_file.sh
500K    ./sub/01.h265
16K     ./sub/get_h265_resolution
8.0K    ./sub/get_h265_resolution.c
4.0K    ./sub/makefile
4.2M    ./sub
4.0K    ./gp_get_h265_resolution.py ...............................需要调用的模块
2.6M    ./Tennis1080p.h265 .............................................一个.h265文件示例
6.7M    .

2.1 外层py invoker代码:

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 获取当前脚本文件所在目录的父目录,并构建相对路径
import os
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
project_path = os.path.join(current_dir, '..')
sys.path.append(project_path)
sys.path.append(current_dir)
import subprocess

def gp_h265_get_real_solution_of_file(file_path):
    # 运行 .sh 脚本并获取输出
    result = subprocess.run(['bash', 'sub/get_h265_resolution_of_file.sh', file_path], capture_output=True, text=True)
    
    # 获取标准输出
    output = result.stdout.strip()
    
    print(output)
    # 分割输出字符串,并转换为数字
    numbers = [int(num) for num in output.split(',')]
    return numbers

def gp_h265_get_real_solution_of_stream(rtsp_path):
    # 运行 .sh 脚本并获取输出
    result = subprocess.run(['bash', 'sub/get_h265_resolution_of_stream.sh', rtsp_path], capture_output=True, text=True)
    
    # 获取标准输出
    output = result.stdout.strip()
    
    # 分割输出字符串,并转换为数字
    numbers = [int(num) for num in output.split(',')]
    return numbers


#usage:
if __name__ == "__main__":
    file_path = "./Tennis1080p.h265"
    print(gp_h265_get_real_solution_of_file(file_path))
    rtsp_path = "rtsp://admin:a1234567@192.168.0.6:554/h265/ch1/main/av_stream"
    print(gp_h265_get_real_solution_of_stream(file_path))

2.2 sh代码 

两个.sh文件原本接口不同,后来修改时代码统一了。

基本逻辑:

  1. 先截取1帧 =>得到视在分辨率width, height
  2. 将该帧转为.h265
  3. 得到.h265的内部缓冲分辨率 =>输出[disp_width, disp_height, real_width, real_height]四元组
#!/bin/bash
# 获取脚本所在的目录
SCRIPT_DIR=$(dirname "$(realpath "$0")")
# 切换到脚本所在的目录
cd "$SCRIPT_DIR" || exit
file_of_h265=$1

# 运行程序并捕获输出
output=$(python3 ./fetch_from_stream.py "$file_of_h265")
# 解析输出结果,假设输出格式为 "1920,1080"
IFS=',' read -r width height <<< "$output"
mpi_enc_test -i frame_by_soft_decode_of_h265file.bin -w $width -h $height -t 16777220 -o 01.h265 -n 20
./get_h265_resolution ./01.h265
#!/bin/bash
# 获取脚本所在的目录
SCRIPT_DIR=$(dirname "$(realpath "$0")")
# 切换到脚本所在的目录
cd "$SCRIPT_DIR" || exit
rtsp_addr=$1

# 运行程序并捕获输出
output=$(python3 ./fetch_from_stream.py "$rtsp_addr")
# 解析输出结果,假设输出格式为 "1920,1080"
IFS=',' read -r width height <<< "$output"
mpi_enc_test -i frame_by_soft_decode_of_h265file.bin -w $width -h $height -t 16777220 -o 01.h265 -n 20
./get_h265_resolution ./01.h265

2.3 从rtsp源截取一帧图像的代码

#!/usr/bin/env python3
# -*- coding: utf-8 -*-
# 获取当前脚本文件所在目录的父目录,并构建相对路径
import os
import sys
current_dir = os.path.dirname(os.path.abspath(__file__))
project_path = os.path.join(current_dir, '..')
sys.path.append(project_path)
sys.path.append(current_dir)
import gi
import cv2
import threading
import time
import warnings
import queue
import sys
gi.require_version('Gst', '1.0')
from gi.repository import Gst, GLib

def on_new_sample(sink):
    sample = sink.emit('pull-sample')
    buffer = sample.get_buffer()
    
    # 检查 buffer 是否有效
    if buffer:
        caps = sample.get_caps()
        structure = caps.get_structure(0)
        width = structure.get_int('width')[1]
        height = structure.get_int('height')[1]
        
        print(f"{width}, {height}\n")
        '''        
        print(f'{structure}')
        '''
    
        # 创建一个 mapinfo 对象以映射数据
        success, mapinfo = buffer.map(Gst.MapFlags.READ)
        if success:
            # 获取映射的字节数据
            data = mapinfo.data
            #print(f'frame len ={len(data)}')
            # 文件路径
            file_path = 'frame_by_soft_decode_of_h265file.bin'
            # 打开文件并写入数据
            with open(file_path, 'wb') as file:
                file.write(data)
            
            # 取消映射
            buffer.unmap(mapinfo)    
    sys.exit(0)
    return Gst.FlowReturn.OK


def fetch_a_frame_from_file(filepath):
    Gst.init(None)
    
    pipeline = Gst.parse_launch(f'filesrc location={filepath} ! h265parse ! mppvideodec ! videoconvert ! appsink emit-signals=True max-buffers=1 drop=True sync=False')
    appsink = pipeline.get_by_name('appsink0')
    appsink.connect('new-sample', on_new_sample)
    
    pipeline.set_state(Gst.State.PLAYING)
    GLib.MainLoop().run()
    
def fetch_a_frame_from_stream(rtsp_addr):
    Gst.init(None)
    
    pipeline = Gst.parse_launch(f'rtspsrc location={rtsp_addr} latency=200 ! rtph265depay ! h265parse ! mppvideodec ! videoconvert ! appsink emit-signals=True max-buffers=1 drop=True sync=False')    
    appsink = pipeline.get_by_name('appsink0')
    appsink.connect('new-sample', on_new_sample)
    
    pipeline.set_state(Gst.State.PLAYING)
    GLib.MainLoop().run()

def is_rtsp_url(url):
    return url.startswith('rtsp://')

def main():
    # 打印所有传递的命令行参数
    #print("脚本名:", sys.argv[0])
    #print("参数数量:", len(sys.argv) - 1)
    #for i, arg in enumerate(sys.argv[1:], start=1):
    #    print(f"参数 {i}: {arg}")
    if(is_rtsp_url(sys.argv[1])):
        fetch_a_frame_from_stream(sys.argv[1])
    else:
        fetch_a_frame_from_file(sys.argv[1])

if __name__ == "__main__":
    main()

2.4 获取真实分辨率的c代码

/**
 * 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 <stdlib.h>
#include <rockchip/rk_mpi.h>

#define __IN_FILE__ ("01.h265")
#define __OUT_FILE__ ("01.yuv")

int dump_frame(MppFrame frame, int *width, int *height, int *h_stride, int *v_stride)
{
    //printf("dump_frame_to_file\n");

    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 -1;
    }

    base = (RK_U8 *)mpp_buffer_get_ptr(buffer);

    // MPP_FMT_YUV420SP
    if (fmt != MPP_FMT_YUV420SP) {
        //printf("fmt %d not supported\n", fmt);
        return -1;
    }
    
    return 0;
}

int main(int argc, char *argv[])
{
    //printf("---------- mpp start ----------\n");
    if(argc != 2)
    {
        printf("usage:%s <.h265 file>\n", argv[0]);
        printf("return <width>, <height>, <h_stride>, <v_stride>\n");
    }

    // 1. 打开输入文件
    FILE *in_fp = fopen(argv[1], "rb");
    if (!in_fp) {
        //printf("fopen error\n");
        return -1;
    }

    // 3. 初始化解码器上下文,MppCtx MppApi
    MppCtx 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/135760601
    if (MPP_OK != ret) {
        //printf("mpp_init error\n");
        return -1;
    }

    // 5. 初始化包,MppPacket
    int 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 failed ret:%d\n", ret);
                usleep(2000);  // 等待一下2ms,通常1080p解码时间2ms
                continue;
            }

            //printf("decode_get_frame success\n");
            int width, height, h_stride, v_stride;
            dump_frame(frame, &width, &height, &h_stride, &v_stride);
            printf("%d, %d, %d, %d\n", width, height, h_stride, v_stride);
            exit(0);

            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);
    mpi->reset(ctx);
    mpp_packet_deinit(&pkt);
    mpp_destroy(ctx);
    free(buf);
    
    //printf("---------- mpp over ----------\n");
    return 0;
}

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

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

相关文章

探索局域网传输新境界 | 闪电藤 v2.2.7

在这个数字化时代&#xff0c;文件的快速、安全传输是我们日常工作中不可或缺的一部分。今天&#xff0c;电脑天空向大家介绍一款革命性的局域网文件传输工具——闪电藤&#xff0c;它将彻底改变你的文件传输体验。 &#x1f3a8; 界面设计 —— 极简之美 闪电藤采用极简的设…

【自动化测试必学语言】python:语言基础

目录 Python 介绍 语言的分类 注释 单行注释 多行注释 变量 定义变量 使用变量 变量名的命名规范 数据类型 数字类型 非数字类型 type() 函数 input输入 print输出 格式化输出 快捷键(小操作) 运算符 算术运算符 比较运算符 Python 介绍 作者&#xff1a; 吉…

【Java】字符串String类(011)

目录 ♦️API和API帮助文档 ♦️创建String &#x1f38f;直接赋值类 &#x1f38f;new类 &#x1f421;空参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;有参类 构造方法&#xff1a; 举例代码&#xff1a; &#x1f421;字符数组类 构造方法&…

如何借助逻辑数据编织平台实现“数据优先堆栈( DFS )”

一、什么是面向“数据优先”的数据研发平台&#xff1f; 企业在数字化转型的浪潮中&#xff0c;愈发认知到数据作为核心战略资产的重要性。然而&#xff0c;要充分利用数据的价值并非易事。一方面&#xff0c;企业需要投入大量资源来建设和维护复杂的数据基础设施&#xff1b;另…

ref函数

Vue2 中的ref 首先我们回顾一下 Vue2 中的 ref。 ref 被用来给元素或子组件注册引用信息。引用信息将会注册在父组件的 $refs 对象上。如果在普通的 DOM 元素上使用&#xff0c;引用指向的就是 DOM 元素&#xff1b;如果用在子组件上&#xff0c;引用就指向组件实例&#xff1…

计算机基础(day1)

1.什么是内存泄漏&#xff1f;什么是内存溢出&#xff1f;二者有什么区别&#xff1f; 2.了解的操作系统有哪些&#xff1f; Windows&#xff0c;Unix&#xff0c;Linux&#xff0c;Mac 3. 什么是局域网&#xff0c;广域网&#xff1f; 4.10M 兆宽带是什么意思&#xff1f;理论…

【2024最新华为OD-C/D卷试题汇总】[支持在线评测] 整数数组按个位数字排序(100分) - 三语言AC题解(Python/Java/Cpp)

🍭 大家好这里是清隆Coding ,一枚热爱算法的程序员 ✨ 本系列打算持续跟新华为OD-C/D卷的三语言AC题解 👏 感谢大家的订阅➕ 和 喜欢💗 🍿 最新华为OD机试D卷目录,全、新、准,题目覆盖率达 95% 以上,支持题目在线评测,专栏文章质量平均 93 分 最新华为OD机试目录…

使用大型语言模型进行文档解析

动机 多年来&#xff0c;正则表达式一直是我解析文档的首选工具&#xff0c;我相信对于许多技术人员和行业也是如此。尽管正则表达式在某些情况下非常强大&#xff0c;但它们常常在面对真实世界文档的复杂性和多样性时缺少灵活性。 另一方面&#xff0c;大型语言模型提供了一…

Mysql输出今年1月至当前月份日期序列

#今日2024-07-29SELECTDATE_FORMAT( DATE_ADD( NOW(), INTERVAL -(CAST( help_topic_id AS SIGNED INTEGER )) MONTH ), %Y-%m ) monthsFROMmysql.help_topicWHEREhelp_topic_id < TIMESTAMPDIFF(MONTH, CONCAT(DATE_FORMAT(CURDATE(), "%Y-01-01")),CONCAT(STR_…

《动手做科研 》| 03. 如何阅读人工智能研究论文

地址链接:《动手做科研》03. 如何阅读人工智能研究论文 导读: 在刚迈入科研时&#xff0c;人人都说读论文很重要&#xff0c;但是很少有人能完整地教你应该如何读论文。论文不仅揭示了行业的最新进展和趋势&#xff0c;而且为我们提供了改进技术和解决复杂问题的思路。然而&…

你知道缓存的这个问题到底把多少程序员坑惨了吗?

在现代系统中&#xff0c;缓存可以极大地提升性能&#xff0c;减少数据库的压力。 然而&#xff0c;一旦缓存和数据库的数据不一致&#xff0c;就会引发各种诡异的问题。 我们来看看几种常见的解决缓存与数据库不一致的方案&#xff0c;每种方案都有各自的优缺点 先更新缓存&…

探索NSL-KDD数据集:入侵检测的起点

引言 在信息安全的世界里&#xff0c;数据集是我们最宝贵的资源。就像厨师离不开食材&#xff0c;数据科学家也离不开数据集。对于入侵检测系统&#xff08;IDS&#xff09;而言&#xff0c;NSL-KDD数据集无疑是一个经典的选择。今天&#xff0c;我们将深入探讨这个数据集&…

Python数据分析案例56——灰色预测、指数平滑预测人口数量,死亡率,出生率等

案例背景 时间序列的预测现在都是用神经网络&#xff0c;但是对于100条以内的小数据集&#xff0c;神经网络&#xff0c;机器学习这种方法效果表现不太好。 所以还是需要用上一些传统的统计学方法来进行预测&#xff0c;本次就使用灰色预测&#xff0c;指数平滑两大方法来分别…

MySQL学习(16):视图

视图是一种虚拟临时表&#xff0c;并不真正存储数据&#xff0c;它的作用就是方便用户查看实际表的内容或者部分内容 1.视图的使用语法 &#xff08;1&#xff09;创建 create view 视图名称 as select语句; #视图形成的虚拟表就来自于select语句所查询的实际表&#xff0c;…

突破•指针四

听说这是目录哦 函数指针数组&#x1fae7;用途&#xff1a;转移表 回调函数&#x1fae7;能量站&#x1f61a; 函数指针数组&#x1fae7; 函数指针数组是存放函数地址的数组&#xff0c;例如int (*parr[5])()中parr先和[]结合&#xff0c;说明parr是可以存放5个函数地址【元…

IT运维必备神器!PsShutdown,定时关机重启一键搞定!

嘿&#xff0c;各位技术小能手们&#xff0c;小江湖今天要给大家安利一个宝贝——PsShutdown&#xff01;这可不是一般的关机小工具哦&#xff1b;当你坐在电脑前&#xff0c;手指轻轻敲几下键盘&#xff0c;就能实现定时任务&#xff0c;无论是关机、重启&#xff0c;还是注销…

Python 爬虫入门(四):使用 pandas 处理和分析数据 「详细介绍」

Python 爬虫入门&#xff08;四&#xff09;&#xff1a;使用 pandas 处理和分析数据 「详细介绍」 前言1. pandas简介1.1 什么是pandas?1.2 为什么要使用pandas?1.3 安装 Pandas 2. pandas的核心概念2.1 Series2.2 DataFrame2.3 索引 3. 数据导入和导出3.1 从CSV文件读取数据…

uniapp app跳小程序详细配置

应用场景 app跳微信小程序&#xff0c;支付等 前提配置 1.1微信开放平台申请移动应用 1.2关键&#xff1a;开放平台的移动应用的app的包名和签名必须和uniapp app的包名一致 1.3查看unaipp app的包的签名 下载工具&#xff1a;GenSignature&#xff0c;模拟器安装工具 ht…

iframe嵌套项目后,接口跳出登入页面(会出现画中画的场景)

iframe嵌套项目后&#xff0c;接口跳出登入页面&#xff08;会出现画中画的场景&#xff09; JavaScript 跳出iframe框架 window.top top 属性返回最顶层的先辈窗口。该属性返回对一个顶级窗口的只读引用。如果窗口本身就是一个顶级窗口&#xff0c;top 属性存放对窗口自身的…

使用DTW算法简单实现曲线的相似度计算

相对接近产品交付形态的实现&#xff1a;基于DTW距离的KNN算法实现股票高相似筛选案例-CSDN博客 一、问题背景和思路 问题背景&#xff1a;如果你有历史股票的K线图&#xff0c;怎么从众多股票K线图中提取出TopN相似的几支股票&#xff0c;用来提供给投资者或专家做分析、决策…