记一次gstreamer解码存图绿线问题排查

news2024/11/18 7:44:16

背景

业务需求需要将某些解码后的视频帧保存为图片,大部分情况下图片都是正常的,更换了某些视频流后,在保存的图片顶部就会出现一条绿线,现记录下解决过程。
在这里插入图片描述

部分代码如下

解码回调如下,完整代码可参考之前的文章Gstreamer 硬解码Rtsp流及代码实现:

最终排查结果是:

有些相机本身推的视频帧的大小与gstreame解码出来的 width 和 height不匹配导致的。如:gstreamer实际解出来的width = 1920, height = 1080, 但实际上一帧的数据是:1920 * 1088,多出来了8个字节。如果用获取到的width 和 height去计算拷贝帧的大小,在相机推送不标准的情况下就会出现该问题。
在这里插入图片描述

采用opencv保存图片,先将YUV转成NV12,再调用cv::imwrite() 。以19201080为例:
修复前,使用 解码得到的width 和 height计算帧大小:预期帧大小为:1920
1080*3 / 2 = 3,110,400

{
	......
	cv::Mat img;
	// 创建并初始化原始YUV Mat对象
	yuvNV12.create(height * 3 / 2, width, CV_8UC1);
	memcpy(yuvNV12.data, map.data, width * height * 3 / 2);
	
	// yuv to img Mat
	cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);
	......
}

实际帧大小 map.size = 3,133,440:

{
	......
	cv::Mat img;
	// 创建并初始化原始YUV Mat对象
	yuvNV12.create((map.size / width), width, CV_8UC1);
	memcpy(yuvNV12.data, map.data, map.size);
	// yuv to img Mat
	cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);
            
}
GstFlowReturn ReadvideoFrame_callback(GstElement *sink, gpointer user_data)
{
    CustomData *data = (CustomData *)user_data;

    char video_format[32] = {0};
    int framerate[2] = {0};
    unsigned long long ts = 0;
    GstSample *sample;
    GstBuffer *buffer;
    GstCaps *caps;
    GstStructure *s;
    gint width, height; // 图片的尺寸

    // 使用pull-sample拉取视频帧,并映射到map变量,通过map拷贝出frame数据
    g_signal_emit_by_name(sink, "pull-sample", &sample);
    // g_print("new_sample succeeded (type '%d').\n", sample);

    if (sample)
    {
        caps = gst_sample_get_caps(sample);
        if (!caps)
        {
            g_print("gst_sample_get_caps fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }
        s = gst_caps_get_structure(caps, 0);
        gboolean res;
        res = gst_structure_get_int(s, "width", &width); // 获取图片的宽
        // g_print("width: %d,  ", width);
        res |= gst_structure_get_int(s, "height", &height); // 获取图片的高
        // g_print("height: %d \n", height);
        if (!res)
        {
            g_print("gst_structure_get_int fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }

        const char *format = gst_structure_get_string(s, "format");
        strcpy(video_format, format);
        gst_structure_get_fraction(s, "framerate", &framerate[0], &framerate[1]);

        // 获取视频的一帧buffer,注意,这个buffer是无法直接用的,它不是char类型
        buffer = gst_sample_get_buffer(sample);
        if (!buffer)
        {
            g_print("gst_sample_get_buffer fail\n");
            gst_sample_unref(sample);
            return GST_FLOW_ERROR;
        }

        GstMapInfo map;
        // 把buffer映射到map,这样我们就可以通过map.data取到buffer的数据
        auto rett = gst_buffer_map(buffer, &map, GST_MAP_READ);
        if (rett)
        {
            cv::Mat yuvNV12;
            cv::Mat img;
            // 创建并初始化原始YUV Mat对象
            // 有问题代码如下:
            // yuvNV12.create(height * 3 / 2, width, CV_8UC1);
            // memcpy(yuvNV12.data, map.data, width * height * 3 / 2);

            //修复如下:
            yuvNV12.create((map.size / width), width, CV_8UC1);
            memcpy(yuvNV12.data, map.data, map.size);
            // yuv to img Mat
            cv::cvtColor(yuvNV12, img, cv::COLOR_YUV2BGR_NV12);

            gst_buffer_unmap(buffer, &map); // 解除映射
        }
        else
        {
            g_print("gst_buffer_map failed!, %d\n", rett);
        }

        // release sample reference
        gst_sample_unref(sample);
    }
    else
    {
        g_print("sample is null...\n");
    }

    return GST_FLOW_OK;
}

推荐一个零声学院免费教程,个人觉得老师讲得不错,
分享给大家:[Linux,Nginx,ZeroMQ,MySQL,Redis,
fastdfs,MongoDB,ZK,流媒体,CDN,P2P,K8S,Docker,
TCP/IP,协程,DPDK等技术内容,点击立即学习:

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

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

相关文章

JVM零基础到高级实战之内存区域分布与概述

JVM零基础到高级实战之内存区域分布与概述 JVM零基础到高级实战之内存区域分布与概述 文章目录 JVM零基础到高级实战之内存区域分布与概述前言Java语言为甚么优势巨大?总结 前言 JVM零基础到高级实战之内存区域分布与概述 Java语言为甚么优势巨大? 一处…

FMCW 雷达室内多目标人员MATLAB仿真

分享一则代码,主要用于FMCW雷达室内多目标MATLAB仿真,涉及到的内容和算法模块有如下: 1、目标参数设置 2、雷达参数设置 3、目标运动状态设置 4、雷达信号建模(IQ信号) 5、雷达近场收发几何位置偏差校正 6、距离维FFT…

速刷剑指offer

链接:No5、 用两个栈来实现一个队列 | 阿秀的学习笔记 第五题跳过。栈和队列等着代码随想录二刷补上。 JZ11 旋转数组的最小数字 链接:旋转数组的最小数字_牛客题霸_牛客网 代码: 这个二分法是左闭右开的,就真的不好理解。 class …

Vue - 第五天 动态组件 插槽 自定义指令

动态组件& 插槽& 自定义指令 一、动态组件1.什么是动态组件2.如何实现动态组件渲染3.使用 keep-alive 保持状态4. keep-alive 对应的生命周期函数5. keep-alive 的 include 属性6.动态展示左右组件7.例子 二、插槽1.什么是插槽2.体验插槽的基础用法2.1 没有预留插槽的内…

VGGNet

论文信息 论文名称:Very Deep Convolutional Networks For Large-Scale Image Recognition 论文地址:https://arxiv.org/pdf/1409.1556.pdf 发表期刊: ICLR 发表年份: 2015 论文详情:VGGNet是2014年ILSVRC&#xff08…

【并发篇】04-05 线程池核心参数代码演示

B站 黑马程序员 java八股的视频笔记 自留备忘 如有错误请多多指教。 (一)理论知识 这道题其实就是在问java中线程池的实现类ThreadPoolExecutor,这个类参数最多的构造方法有7个参数。 线程池本质上就是管理一组线程,用来执行提交…

python:消除已安装库在import导入时出现红线问题

问题 在pycharm中,对于已经安装的库文件,在进行import导入时出现红线,不影响运行, 简单有效的消除红线的方法。 解决办法 在工程目录中的程序可以采用Mark directory - Source Root方法。 对于安装的第三方库文件环境不在本工程…

springboot实现后端防重复提交(AOP+redis分布式锁)单机情况下

文章目录 0、依赖1、自定义接口2、实现redis分布式锁3、自定义AOP4、测试 为什么要实现这个功能呢,可能用户在提交一份数据后,可能因为网络的原因、处理数据的速度慢等原因导致页面没有及时将用户刚提交数据的后台处理结果展示给用户,这时用户…

LayoutTransformer: Layout Generation and Completion with Self-attention

LayoutTransformer: Layout Generation and Completion with Self-attention (Paper reading) Kamal Gupta, University of Maryland, US, Cited:41, Code, Paper 1. 前言 我们解决了在各种领域中(如图像、移动应用、文档和3D对象)进行场景布局生成的…

后台管理系统模板 - zhadminvue

没事的时候写了一个后台管理系统模板:zhadminvue,欢迎大家提issue和PR,以及想要添加一些有意思的功能模块,在没事的时候我也会加进去~ github:https://github.com/iotzzh/zh-admin-vue gitee: https://gitee.com/iotzzh/zh-admin.…

算法模板(4):动态规划(1)

动态规划 闫氏 d p dp dp 分析法: 集合:怎么划分。通常以集合的划分来定义数组。 f ( i , j ) f(i, j) f(i,j):选前 i i i 个物品. 体积不超过 j j j。全部初始化为 0 0 0; j j j 非负时状态才合法。体积恰好是 j j j。 f…

Springboot集成magic-api

目录 1、前言 2、springboot集成magic-api 2.1、添加maven依赖 2.2、application.yml配置 2.3、编写测试接口 2.4、启动程序,访问接口 2.5、magic-api脚本 3、magic-api其他语法 4、注意事项 1、前言 今天项目中遇到一个问题,springboot后端项目…

《机器学习算法竞赛实战》-chapter3数据探索

《机器学习算法竞赛实战》学习笔记,记录一下自己的学习过程,详细的内容请大家购买作者的书籍查阅。 数据探索 数据探索是竞赛的核心模块之一,贯穿竞赛始终,也是很多竞赛胜利的关键。 在竞赛中如何确保自己准备好竞赛使用的算法模…

cmake 添加一个库

目录 项目格式 cmake基本语法 添加库 链接库 添加库的头文件 cmake打印字符串 库的cmake文件 cmake生辰库 mian函数中使用 让库成为可选的 cmake基本语法 设置option变量 cmake设置条件链接库 链接库 添加头文件 修改cmake配置文件 修改引用的源码 项目格式 …

MM32F3273G8P火龙果开发板MindSDK开发教程12 -获取msa311加速器的敲击事件

MM32F3273G8P火龙果开发板MindSDK开发教程12 -获取msa311加速器的敲击事件 1、功能描述 msa311可以识别单击、双击事件,类似手机上的点击返回,双击截屏功能。 单击,双击都能产生中断事件。 中断事件产生后,从对应的状态寄存器读…

算法模板(4):动态规划(3) 做题积累(1)

动态规划 1. 背包 1. 1024. 装箱问题 题意:有一个箱子容量为 V,同时有 n 个物品,每个物品有一个体积(正整数)。要求 n 个物品中,任取若干个装入箱内,使箱子的剩余空间为最小。别学那么死板。…

2023夏-PAT甲级题解

目录 总结: A-1 Trap Input Specification: Output Specification: Sample Input: Sample Output: 题意: 思路: AC代码: A-2 Queue Using Two Stacks Input Specification: Output Specification: Sample Input: Sa…

SpringBoot 项目部署笔记

1. 直接通过 jar 包部署 本地直接 build package 成 jar 包,上传至服务器 ps -ef|grep XXX #查找项目进程sudo kill -9 19727 #杀掉项目进程nohup sudo java -jar *.jar >> app.log & #后台运行 jar &代表让该命令在后台执行 3. 通过 Jenkins …

pytorch笔记:conv2d

来自B站视频,API查阅,TORCH.NN nn.conv2d 中一般 kernel_size 是小奇数,padding 设置为 k − 1 2 \frac{k-1}{2} 2k−1​(实际上padding的是 k − 1 k-1 k−1,因为参数的意义是左右各padding),

探索Xiotman:物联网软件架构的创新之路

文章目录 探索Xiotman:物联网软件架构的创新之路什么是物联网什么是XiotmanXiotman的特点Xiotman的架构Xiotman的使用安装env工具获取源代码使用其他教程 Xiotman的开源地址 总结 探索Xiotman:物联网软件架构的创新之路 什么是物联网 🚀&am…