一个由通义千问以及FFmpeg的AVFrame、buffer引起的bug:前面几帧影响后面帧数据
目录
1 问题描述
2 我最开始的代码----错误代码
3 正确的代码
4 为什么前面帧的结果会叠加到了后面帧上----因为ffmpeg新一帧只更新上一帧变化的部分
5 以后不要用通义千问写代码
1 问题描述
某个项目中,需要做人脸马赛克,然后这个是君正的某款芯片,他没有硬件解码,我就用了ffmpeg解码,然后我让通义千问给我写一个用ffmpeg解码h264视频的代码,然后对人脸区域做马赛克处理,出现的问题就是比如我在打人脸马赛克的时候出现重影、残留,就是比如我前面几帧做的马赛克在后面几帧上竟然还有,

这个看现象就是前面帧的马赛克效果被叠加到后面了。
2 我最开始的代码----错误代码
int SkuDetect::face_mosaic(const char* video_path) {// 初始化 FFmpegav_register_all();// 打开视频文件AVFormatContext* format_context = nullptr;if (avformat_open_input(&format_context, video_path, nullptr, nullptr) != 0) {std::cerr << "Could not open source file " << video_path << "\n";return -1;}if (avformat_find_stream_info(format_context, nullptr) < 0) {std::cerr << "Failed to retrieve input stream information.\n";return -1;}int video_stream_index = -1;for (unsigned i = 0; i < format_context->nb_streams; ++i) {if (format_context->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) {video_stream_index = i;break;}}if (video_stream_index == -1) {std::cerr << "File does not contain any video stream.\n";return -1;}AVCodecParameters* codec_parameters = format_context->streams[video_stream_index]->codecpar;const AVCodec* codec = avcodec_find_decoder(codec_parameters->codec_id);AVCodecContext* codec_context = avcodec_alloc_context3(codec);avcodec_parameters_to_context(codec_context, codec_parameters);if (avcodec_open2(codec_context, codec, nullptr) < 0) {std::cerr << "Failed to open codec.\n";return -1;}printf("Pixel format: %d\n", codec_context->pix_fmt);// 获取视频的原始宽高int orig_w = codec_context->width;int orig_h = codec_context->height;// 加载人脸坐标std::map<int, std::vector<std::array<int, 4>>> face_coords_map = load_face_coordinates(video_path, orig_w, orig_h);//AVFrame* frame = av_frame_alloc();AVPacket packet;int frameCount = 0; // 记录帧数while (av_read_frame(format_context, &packet) >= 0) {AVFrame* frame = av_frame_alloc();if (packet.stream_index == video_stream_index) {if (avcodec_send_packet(codec_context, &packet) != 0) {std::cerr << "Error sending a packet for decoding." << std::endl;continue;}while (avcodec_receive_frame(codec_context, frame) == 0) {// 深拷贝 AVFrame 数据AVFrame* cloned_frame = av_frame_alloc();//用了深拷贝之后也还是有残影,并且深拷贝之后里面的data[0]的地址跟frame值一样的,指向同一块内存地址。cloned_frame = av_frame_clone(frame);// 获取当前帧的人脸坐标auto it = face_coords_map.find(frameCount);if (it != face_coords_map.end()) {const std::vector<std::array<int, 4>>& faces = it->second;printf("faces.size(): %d\n", faces.size());//用了深拷贝,并且memeset,然后前面这里保存依然会有马赛克残影,//save_frame_as_image(frame, frameCount, "result_image", it != face_coords_map.end() ? it->second : std::vector<std::array<int, 4>>());// 遍历所有人脸区域for (const auto& face : faces) {int x = face[0];int y = face[1];int width = face[2];int height = face[3];printf("frameCount:%d, x: %d, y: %d, width: %d, height: %d\n",frameCount, x, y, width, height);printf("frame->data[0]:0x%x, frame->linesize[0]:%d \n", frame->data[0], frame->linesize[0]);// 对 Y 分量进行马赛克apply_uniform_mosaic_y(dst_frame->data[0], dst_frame->linesize[0], x, y, width, height);// 对 U 和 V 分量进行马赛克int x_uv = x_expanded / 2, y_uv = y_expanded / 2;int width_uv = width_expanded / 2, height_uv = height_expanded / 2;apply_uniform_mosaic_uv(frame->data[1], frame->linesize[1], x_uv, y_uv, width_uv, height_uv);apply_uniform_mosaic_uv(frame->data[2], frame->linesize[2], x_uv, y_uv, width_uv, height_uv);}}// 保存处理后的帧为图片//save_frame_as_image(frame, frameCount, "result_image_mosaic", it != face_coords_map.end() ? it->second : std::vector<std::array<int, 4>>());// 保存处理后的帧为图片save_frame_as_image(dst_frame, frameCount, "result_image_mosaic", it != face_coords_map.end() ? it->second : std::vector<std::array<int, 4>>());av_frame_free(&dst_frame); //memset(frame, 0, sizeof(AVFrame));//用了memset之后也还是有残影。// 释放克隆帧av_frame_unref(cloned_frame);av_frame_free(&cloned_frame);frameCount++; // 增加帧数}}// 重置 AVFrameav_frame_unref(frame);av_packet_unref(&packet);av_frame_free(&frame);}// 清理资源//avcodec_free_context(&codec_context);avformat_close_input(&format_context);std::cout << "Processing completed." << std::endl;return 0;
}
上面的代码是让通义千问给写的,刚开始不对,他还让加上了clone函数做深拷贝,但其实深拷贝不是这样的,
3 正确的代码
AVFrame* apply_mosaic_with_copy(const AVFrame* src_frame, int x, int y, int width, int height, int block_size) {if (!src_frame || !src_frame->data[0]) {return nullptr;}// 创建新帧AVFrame* dst_frame = av_frame_alloc();if (!dst_frame) {return nullptr;}// 复制帧属性dst_frame->format = src_frame->format;dst_frame->width = src_frame->width;dst_frame->height = src_frame->height;// 分配缓冲区if (av_frame_get_buffer(dst_frame, 32) < 0) {av_frame_free(&dst_frame);return nullptr;}// 复制原始数据if (av_frame_copy(dst_frame, src_frame) < 0) {av_frame_free(&dst_frame);return nullptr;}// 设置其他属性if (av_frame_copy_props(dst_frame, src_frame) < 0) {av_frame_free(&dst_frame);return nullptr;}// 应用马赛克(使用修改后的版本)if (apply_mosaic_to_avframe(dst_frame, x, y, width, height, block_size) < 0) {av_frame_free(&dst_frame);return nullptr;}return dst_frame;
}
正确的深拷贝的代码应该是这样的,不只是alloc一个frame,还需要av_frame_get_buffer,重点就在这里的buffer。
4 为什么前面帧的结果会叠加到了后面帧上----因为ffmpeg新一帧只更新上一帧变化的部分
看完下面几个问题和答案之后就明白为什么了,下面几个问题是用deepseek问的,不是通义千问,通义千问的答案明显不行






5 以后不要用通义千问写代码
通义千问不适合写代码,不行,以前的h264转yuv视频的时候,也是通义千问给写的代码错了,将.mp4视频文件转成.yuv视频文件C++代码备份_mp4视频保存为yuv格式-CSDN博客
这个以前的代码就是通义千问给写错了,而且错误很隐蔽,转出来的yuv是对的,只是稍微有点色差,当初这个bug也耽误了不少时间。
相关文章:
一个由通义千问以及FFmpeg的AVFrame、buffer引起的bug:前面几帧影响后面帧数据
目录 1 问题描述 2 我最开始的代码----错误代码 3 正确的代码 4 为什么前面帧的结果会叠加到了后面帧上----因为ffmpeg新一帧只更新上一帧变化的部分 5 以后不要用通义千问写代码 1 问题描述 某个项目中,需要做人脸马赛克,然后这个是君正的某款芯片…...
12.第二阶段x64游戏实战-远程调试
免责声明:内容仅供学习参考,请合法利用知识,禁止进行违法犯罪活动! 本次游戏没法给 内容参考于:微尘网络安全 上一个内容:11.第二阶段x64游戏实战-框架代码细节优化 本次写的内容是关于调试、排错相关的…...
Coze 和 n8n 的详细介绍及多维度对比分析,涵盖功能、架构、适用场景、成本等关键指标
以下是 Coze 和 n8n 的详细介绍及多维度对比分析,涵盖功能、架构、适用场景、成本等关键指标: 一、Coze 详细介绍 1. 基础信息 类型:低代码自动化平台(SaaS)。开源性:闭源(企业版需付费&…...
咋用fliki的AI生成各类视频?AI生成视频教程
最近想制作视频,多方考查了决定用fliki,于是订阅了一年试试,这个AI生成的视频效果来看真是不错,感兴趣的自己官网注册个账号体验一下就知道了。 fliki官网 Fliki生成视频教程 创建账户并登录 首先,访问fliki官网并注…...
【NLP】 20. Attention 和 self-attention
1. 背景与基本概念 1.1 编码器-解码器模型的瓶颈问题 传统的序列到序列(Seq2Seq)模型主要依靠编码器生成单一固定长度的上下文向量,然后由解码器逐步生成输出。这个过程存在两个主要问题: 瓶颈问题:固定…...
vue3+element-plus实现省市区三级地址多选
目录 背景实现功能点遗留问题完整代码参考 背景 需要实现:选择省级地址时,回传节点为 [ 省级地址 id], 选择市级地址时,回传节点为 [ 省级地址 id,市级地址 id], 选择区县地址时,回传节点为 [ …...
centos部署的openstack发布windows虚拟机
CentOS上部署的OpenStack可以发布Windows虚拟机。在CentOS上部署OpenStack后,可以通过OpenStack平台创建和管理Windows虚拟机。以下是具体的步骤和注意事项: 安装和配置OpenStack: 首先,确保系统满足OpenStack的最低硬件…...
Linux : 进程等待以及进程终止
进程控制之进程等待 (一)fork函数1*fork函数返回值2.父子进程的写时拷贝 (二)进程终止1.进程退出码2.进程常见退出方法(1)_exit(2)exit(3)return 3.进程的异常…...
LSTM结合LightGBM高纬时序预测
1. LSTM 时间序列预测 LSTM 是 RNN(Recurrent Neural Network)的一种变体,它解决了普通 RNN 训练时的梯度消失和梯度爆炸问题,适用于长期依赖的时间序列建模。 LSTM 结构 LSTM 由 输入门(Input Gate)、遗…...
详细解释MCP项目中安装命令 bunx 和 npx区别
详细解释 bunx 和 npx 1. bunx bunx 是 Bun 的一个命令行工具,用于自动安装和运行来自 npm 的包。它是 Bun 生态系统中类似于 npx 或 yarn dlx 的工具。以下是 bunx 的主要特点和使用方法: 自动安装和运行: bunx 会自动从 npm 安装所需的包…...
【统信UOS操作系统】python3.11安装numpy库及导入问题解决
一、安装Python3.11.4 首先来安装Python3.11.4。所用操作系统:统信UOS 前提是准备好Python3.11.4的安装包(可从官网下载(链接)),并解压到本地: 右键,选择“在终端中打开”ÿ…...
【中间件】nginx反向代理实操
一、说明 nginx用于做反向代理,其目标是将浏览器中的请求进行转发,应用场景如下: 说明: 1、用户在浏览器中发送请求 2、nginx监听到浏览器中的请求时,将该请求转发到网关 3、网关再将请求转发至对应服务 二、具体操作…...
嵌入式硬件篇---加法减法积分微分器
文章目录 前言1. 加法器(Summing Amplifier)结构反相加法器同相加法器 特点反相输出虚地特性 应用 2. 减法器(差分放大器)结构特点差分放大共模抑制比 应用 3. 积分器结构特点直流漂移问题应用 4. 微分器结构特点应用关键注意事项…...
Spring Cloud Gateway 的执行链路详解
Spring Cloud Gateway 的执行链路详解 🎯 核心目标 明确 Spring Cloud Gateway 的请求处理全过程(从接收到请求 → 到转发 → 到返回响应),方便你在合适的生命周期节点插入你的逻辑。 🧱 核心执行链路图(执…...
鸿蒙应用(医院诊疗系统)开发篇2·Axios网络请求封装全流程解析
一、项目初始化与环境准备 1. 创建鸿蒙工程 src/main/ets/ ├── api/ │ ├── api.ets # 接口聚合入口 │ ├── login.ets # 登录模块接口 │ └── request.ets # 网络请求核心封装 └── pages/ └── login.ets # 登录页面逻辑…...
突发重磅消息!!!CVE项目将被取消?
突发重磅消息!!!CVE项目将被取消?突发!来自可靠消息来源。MITRE 对 CVE 项目的支持将于明天到期。附件信件已发送给 CVE 董事会成员。https://mp.weixin.qq.com/s/N3qkiHaDfzDuBMK3JbBCjw...
详解与FTP服务器相关操作
目录 什么是FTP服务器 搭建FTP服务器相关 编辑 Unity中与FTP相关的类 上传文件到FTP服务器 使用FTP服务器上传文件的关键点 开始上传 从FTP服务器下载文件到客户端 使用FTP下载文件的关键点 开始下载 关于FTP服务器的其他操作 将文件的上传,下载&…...
远程登录一个Linux系统,如何用命令快速知道该系统属于Linux的哪个发行版,以及该服务器的各种配置参数,运行状态?
远程登录一个Linux系统,如何用命令快速知道该系统属于Linux的哪个发行版,以及该服务器的各种配置参数,运行状态? 查看Linux发行版信息 查看发行版名称和版本: cat /etc/*-release或 lsb_release -a查看内核版本&#…...
解决 .Net 6.0 项目发布到IIS报错:HTTP Error 500.30
今天在将自己开发许久的项目上线的时候,发现 IIS 发布后请求后端老是报一个 HTTP Error 500.30 的异常,如下图所示。 后来仔细调查了一下发现是自己的程序中写了 UseStaticFiles 的依赖注入,这个的主要作用就是发布后端后,想…...
STM32F103_HAL库+寄存器学习笔记16 - 监控CAN发送失败(轮询方式)
导言 《STM32F103_HAL库寄存器学习笔记15 - 梳理CAN发送失败时,涉及哪些寄存器》从上一章节看到,当CAN消息发送失败时,CAN错误状态寄存器ESR的TEC会持续累加,LEC等于0x03(ACK错误)。本次实验的目的是编写一…...
Java并发-AQS框架原理解析与实现类详解
什么是AQS? AQS(AbstractQueuedSynchronizer)是Java并发包(JUC)的核心基础框架,它为构建锁和同步器提供了高效、灵活的底层支持。本文将从设计原理、核心机制及典型实现类三个维度展开,帮助读者…...
实现定长的内存池
池化技术 所谓的池化技术,就是程序预先向系统申请过量的资源,然后自己管理起来,以备不时之需。这个操作的价值就是,如果申请与释放资源的开销较大,提前申请资源并在使用后并不释放而是重复利用,能够提高程序…...
vs2022使用git方法
1、创建git 2、在cmd下执行 git push -f origin master ,会把本地代码全部推送到远程,同时会覆盖远程代码。 3、需要设置【Git全局设置】,修改的代码才会显示可以提交,否则是灰色的不能提交。 4、创建的分支,只要点击…...
Mysql中表的使用(3)
目录 1.updata的使用 2.delete(删除表中数据)drop(删除表) 数据库的约束 1.NOT NULL 指定列不能为空 2.UNIQUE指定列唯一 3.DEFAULT(默认值) 4.PRIMARY KEY 5.自增主键 1.updata的使用 1.0update 表名 set 列名x where 列名y; 2.0update 表名 s…...
BUUCTF-Web(1-20)
目录 一.SQL注入 (1)[极客大挑战 2019]EasySQL 万能密码 (7)[SUCTF 2019]EasySQL 堆叠注入 解一: 解二: (10)[强网杯 2019]随便注 堆叠注入 解一: 解二: 解三: (8)[极客大挑战 2019]LoveSQL 联…...
Uniapp:确认框
目录 一、 出现场景二、 效果展示三、具体使用 一、 出现场景 在项目的开发中,会经常出现删除数据的情况,如果直接删除的话,可能会存在误删,用户体验不好,所以需要增加一个消息提示,提醒用户是否删除。 二…...
【前端网络请求入门】XMLHttpRequest与Fetch保姆级教程
新手学前端时,经常会被「如何让网页和服务器说话」难住。今天我们用最通俗的语言,把浏览器最常用的两种网络请求方式——XMLHttpRequest和Fetch讲清楚,还会带完整的代码示例,跟着敲一遍就能上手! 一、先搞懂「网络请求…...
力扣热题100—滑动窗口(c++)
3.无重复字符的最长子串 给定一个字符串 s ,请你找出其中不含有重复字符的 最长 子串 的长度。 unordered_set<char> charSet; // 用于保存当前窗口的字符int left 0; // 窗口左指针int maxLength 0; // 最长子串的长度for (int right 0; right < s.siz…...
实验四 中断实验
一、实验目的 掌握中断服务程序的编写。 二、实验电路 三、实验内容 1.实验用PC机内部的中断控制器8259A,中断源用TPC-ZK实验箱上的单脉冲电路,将单脉冲电路的输出接中断请求信号IRQ,每按一次单脉冲按键产生一次…...
腾势品牌欧洲市场冲锋,科技豪华席卷米兰
在时尚与艺术的交汇点,米兰设计周的舞台上,一场汽车界的超级风暴正在酝酿,腾势品牌如一头勇猛无畏的雄狮,以雷霆万钧之势正式向欧洲市场发起了冲锋。其最新力作——腾势Z9GT的登场,仿佛是一道闪电划破夜空,…...
