CLion和VS中avcodec_receive_frame()获取结果不同

news2024/11/14 21:45:28

1. 介绍

在提取音视频文件中音频的PCM数据时,使用avcodec_receive_frame()函数进行解码时,遇到了一些问题,代码在Visual Studio 2022中运行结果符合预期,但是在CLion中运行时,获取的AVFrame有错误,和VS中获得的结果不一样。

FFMpeg 5.1.2

2. 源码

  1. Utils.h
#pragma once

#define _CRT_SECURE_NO_WARNINGS

extern "C" {
#include <libavutil/error.h>
}

static char* wrap_av_err2str(int errnum) {
	static char str[256] = {0};
	return av_make_error_string(str, sizeof(str), errnum);
}
  1. AudioDecoder2.h
#pragma once

extern "C"
{
#include "libavutil/log.h"
#include "libavutil/imgutils.h"
#include "libavutil/samplefmt.h"
#include "libavutil/timestamp.h"
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
};
#include "Utils.h"
#include <cinttypes>

class AudioDecoder2
{
public:
	AudioDecoder2();
	AudioDecoder2(const char* src_filename, const char* dst_filename);
	~AudioDecoder2();
	int start();

private:
	int ret;
	char src_filename[256];
	char dst_filename[256];
	FILE* dst_fd = NULL;

	AVFormatContext* ifmt_ctx = NULL;
	AVCodecContext* audio_dec_ctx = NULL;
	const AVCodec* audio_dec = NULL;
	AVStream* audio_stream = NULL;
	int audio_stream_index = -1;
	AVFrame* frame = NULL;
	AVPacket* packet = NULL;
};


  1. AudioDecoder2.cpp
#include "AudioDecoder2.h"

AudioDecoder2::AudioDecoder2(const char* src_filename, const char* dst_filename) {
	sscanf(src_filename, "%s", this->src_filename);
	sscanf(dst_filename, "%s", this->dst_filename);
}

int AudioDecoder2::start() {
	// 设置日志输出级别
	av_log_set_level(AV_LOG_INFO);

	// 打开输入文件
	ret = avformat_open_input(&ifmt_ctx, src_filename, NULL, NULL);
	if (ret < 0)
	{
		av_log(NULL, AV_LOG_ERROR, "Can't open source file:%s\n", wrap_av_err2str(ret));
		return -1;
	}

	// 读取一部分数据获得一些相关信息
	ret = avformat_find_stream_info(ifmt_ctx, NULL);
	if (ret < 0)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to find stream information: %s\n", wrap_av_err2str(ret));
		return -1;
	}

	// 查找流
	audio_stream_index = -1;
	audio_stream_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
	if (audio_stream_index < 0)
	{
		av_log(NULL, AV_LOG_DEBUG, "Failed to find the best audio stream!\n");
		return AVERROR(EINVAL);
	}

	// 获取流
	audio_stream = ifmt_ctx->streams[audio_stream_index];

	// 通过数据流查找对应的解码器
	audio_dec = avcodec_find_decoder(audio_stream->codecpar->codec_id);
	if (audio_dec == NULL)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to find codec.\n");
		return AVERROR(EINVAL);
	}

	// 创建解码器上下文
	audio_dec_ctx = avcodec_alloc_context3(audio_dec);
	if (audio_dec_ctx == NULL)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to allocate the codec context.\n");
		return AVERROR(ENOMEM);
	}

	// 从输入流中拷贝对应的参数到解码器中
	ret = avcodec_parameters_to_context(audio_dec_ctx, audio_stream->codecpar);
	if (ret < 0)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to copy codec parameters to decoder context.\n");
		return ret;
	}

	// 打开解码器
	ret = avcodec_open2(audio_dec_ctx, audio_dec, NULL);
	if (ret < 0)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to open codec.\n");
		return ret;
	}

	// 创建输出文件
	dst_fd = fopen(dst_filename, "wb");
	if (!dst_fd)
	{
		av_log(NULL, AV_LOG_ERROR, "Could not open destination file %s\n", dst_filename);
		return -1;
	}

	// 分配帧
	frame = av_frame_alloc();
	if (frame == NULL)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to allocate frame.\n");
		return AVERROR(ENOMEM);
	}

	// 分配数据包
	packet = av_packet_alloc();
	if (packet == NULL)
	{
		av_log(NULL, AV_LOG_ERROR, "Failed to allocate packet.\n");
		return AVERROR(ENOMEM);
	}

	// 读取音频流的数据包,并解码
	while (av_read_frame(ifmt_ctx, packet) >= 0)
	{
		if (packet->stream_index == audio_stream_index)
		{
			ret = avcodec_send_packet(audio_dec_ctx, packet);
			if (ret < 0)
			{
				av_log(NULL, AV_LOG_ERROR, "Failed to decode packet.\n");
				return ret;
			}

			// 对数据进行解码输出
			while (ret >= 0)
			{
				ret = avcodec_receive_frame(audio_dec_ctx, frame);
				if (ret < 0)
				{
					if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
					{
						break;
					}
					else
					{
						break;
					}
				}
				if (ret == 0)
				{
					// 将内容输出到文件
					av_log(NULL, AV_LOG_INFO, "pts:%10" PRId64"\t packet size:%d\n",
						packet->pts, packet->size);

					size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
					fwrite(frame->extended_data[0], 1, unpadded_linesize, dst_fd);
				}

				av_frame_unref(frame);
			}
		}
		av_packet_unref(packet);
	}

	// 刷新解码器
	while (true)
	{
		if (!(audio_dec->capabilities & AV_CODEC_CAP_DELAY))
		{
			return 0;
		}

		ret = avcodec_send_packet(audio_dec_ctx, packet);
		if (ret < 0)
		{
			//            av_log(NULL, AV_LOG_ERROR, "Failed to decode packet.\n");
			//            return ret;
			break;
		}

		// 对数据进行解码输出
		while (ret >= 0)
		{
			ret = avcodec_receive_frame(audio_dec_ctx, frame);
			if (ret < 0)
			{
				if (ret == AVERROR_EOF || ret == AVERROR(EAGAIN))
				{
					break;
				}
			}

			// 将内容输出到文件
			size_t unpadded_linesize = frame->nb_samples * av_get_bytes_per_sample((enum AVSampleFormat)frame->format);
			fwrite(frame->extended_data[0], 1, unpadded_linesize, dst_fd);

			av_frame_unref(frame);
		}

		av_packet_unref(packet);
	}

	// 释放资源
	avcodec_free_context(&audio_dec_ctx);
	avformat_close_input(&ifmt_ctx);
	if (dst_fd)
	{
		fclose(dst_fd);
	}
	av_packet_free(&packet);
	av_frame_free(&frame);

	return 0;
}
  1. main.cpp
#include <iostream>
#include "AudioDecoder2.h"
using namespace std;

int main(int argc, char** argv)
{

	char src_filename[20] = "ball_10s.mp4";
	char audio_dst_filename[20] = "ball_10s.pcm";

	AudioDecoder2* audioDecoder2 = new AudioDecoder2(src_filename, audio_dst_filename);
	audioDecoder2->start();
	return 0;
}

3. 问题

  1. Visual Studio 2022调试结果

在这里插入图片描述

  1. CLion中调试结果

在这里插入图片描述

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

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

相关文章

HTTP——六、HTTP首部

HTTP首部 一、HTTP报文首部HTTP 请求报文HTTP 响应报文 二、HTTP 首部字段1、HTTP 首部字段传递重要信息2、HTTP 首部字段结构3、4 种 HTTP 首部字段类型4、HTTP/1.1 首部字段一览5、非 HTTP/1.1 首部字段6、End-to-end 首部和 Hop-by-hop 首部 三、HTTP/1.1 通用首部字段1、Ca…

HCIP的mgre小实验

实验要求&#xff1a; 第一步&#xff1a;拓扑的搭建 第二步&#xff1a;路由、IP的配置&#xff1a; r1: <Huawei>sys Enter system view, return user view with CtrlZ. [Huawei]sys r1 [r1]int g 0/0/0 [r1-GigabitEthernet0/0/0]ip add 192.168.1.2 24 [r1-Gigabi…

TCP三次握手,四次挥手理解

1. 三次握手 *三次握手&#xff08;Three-way Handshake&#xff09;*其实就是指建立一个TCP连接时&#xff0c;需要客户端和服务器总共发送3个包。进行三次握手的主要作用就是为了确认双方的接收能力和发送能力是否正常、指定自己的初始化序列号为后面的可靠性传送做准备。实…

【双指针_移动零_C++】

题目解析 移动零 nums [0,1,0,3,12] [1,3,12,0,0]算法原理 数组划分&#xff08;数组分块&#xff09; 双指针算法&#xff08;利用数组下标来充当指针&#xff09;使用两个指针的作用&#xff1a; cur指针&#xff1a;从左往右扫描数组&#xff0c;就是遍历数组。 dest指针…

【ES】笔记-let 声明及其特性

let 声明及其特性 声明变量 变量赋值、也可以批量赋值 let a;let b,c,d;let e100;let f521,giloveyou,h[];变量不能重复声明 let star罗志祥;let star小猪;块级作用域&#xff0c;let声明的变量只在块级作用域内有效 {let girl周杨青;}console.log(girl)注意&#xff1a;在 i…

flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能

flutter开发实战-实现css线性渐变转换flutter渐变LinearGradient功能 在之前项目开发中&#xff0c;遇到更换样式&#xff0c;由于从服务器端获取的样式均为css属性值&#xff0c;需要将其转换成flutter类对应的属性值。这里只处理线性渐变linear-gradient 比如渐变 “linear-…

macOS install redis遇到的bug(tar包,homebrew安装,守护进程redis.conf配置)

官网下载tar包再make install 首先是sudo make test的时候一直报 !!! WARNING The following tests failed: *** [err]: trim on SET with big value in tests/unit/type/string.tcl Expected [r memory usage key] < 42000 (context: type source line 478 file /usr/loca…

【二开】前端项目二开技巧 组件相关dependencies

【二开】前端项目二开技巧 组件相关dependencies 二开 依赖的组件 dependencies 方案一 1.直接去 项目下 node_modules目录里改对应的组件代码 2.清理缓存 rimraf node_modules/.cache/ && rimraf node_modules/.vite 3.启动项目生效 方案二&#xff08;推荐&#xf…

接口测试常用技能:Jmeter操作数据库

01、配置JDBC Request 1、添加需要的驱动jar包 使用不同的数据库&#xff0c;我们需要引入不同的jar包。 方式1&#xff1a;直接将jar包复制到jmeter的lib目录 mysql数据库&#xff1a; 下载mysql-connector-java-5.1.28.jar放到 jmeter根目录的lib目录下 sql server 数据…

从零开始学极狐GitLab|02 基本功能使用

目录 0. 如何查看当前版本&#xff1f; 1. 群组创建与删除 1.1 新建群组 1.2 删除群组 2. 项目创建与删除 2.1 新建项目 2.2 删除项目 3. 用户管理 3.1 新建用户 3.2 权限管理 3.3 关闭用户注册 4. 项目管理 4.1 修改 Git 地址 4.2 分支 ➤ 新建分支 ➤ 分支保…

【eNSP】静态路由

【eNSP】静态路由 原理网关路由表 实验根据图片连接模块配置路由器设备R1R2R3R4 配置PC的IP地址、掩码、网关PC1PC2PC3 配置静态路由查看路由表R1R2R3R4测试能否通信 原理 网关 网关与路由器地址相同&#xff0c;一般路由地址为.1或.254。 网关是当电脑发送的数据的目标IP不在…

2023ChinaJoy,撕歌APP实力突围多元化娱乐市场

ChinaJoy作为中国最大的数字娱乐展览会之一&#xff0c;以及亚洲最具影响力的数字娱乐盛会之一&#xff0c;自2003首次举办以来&#xff0c;ChinaJoy不断拓展创新&#xff0c;早已经成为了数字娱乐行业的风向标和重要交流平台&#xff0c;吸引了国内外众多知名企业和品牌参与。…

基于Java的校园二手交易平台设计与实现

基于Java的JSP校园二手交易平台&#xff0c;不仅减少了学生资源的浪费&#xff0c;还能达到资金“回血”的目的。简洁方便、易用。 页面展示 1 登录页面 2 注册页面 3 主页页面 4 商品页面 5 卖家一览页面 6 求购信息页面 7 商城介绍页面 8 商城资讯页面 9 留言信息页面 10…

AcWing244. 谜一样的牛(树状数组)

输入样例&#xff1a; 5 1 2 1 0输出样例&#xff1a; 2 4 5 3 1 解析&#xff1a; 从后往前遍历&#xff0c;每次需要在剩余的数中&#xff0c;找到第 h[ i ]1 大的数即为当前牛的身高。 每次二分&#xff0c;然后求前缀和。 #include<bits/stdc.h> using namespace …

Scratch 之 “2000年至今的天数”积木 的用法

2000年至今的天数 看起来&#xff0c;这块积木好像没有什么用&#xff0c;2000年还是固定的一个值&#xff0c;不能输入。点一下它&#xff0c;可以看到返回了一个小数位数特别多的数。 但实际上&#xff0c;这块积木有着非常多的作用。在很多自制积木包中都用到了这块积木。…

穷举深搜暴搜回溯剪枝(3)

一)字母大小写全排列 784. 字母大小写全排列 - 力扣&#xff08;LeetCode&#xff09; 1)从每一个字符开始进行枚举&#xff0c;如果枚举的是一个数字字符&#xff0c;直接忽视 如果是字母的话&#xff0c;进行选择是变还是不变 2)当进行遍历到叶子结点的时候&#xff0c;直接将…

【Android】在AndroidStudio开发工具运行Java程序

在Android Studio开发工具中&#xff0c;Android系统开始就是用java语言开发的&#xff0c;还可以java代码来写程序&#xff0c;控制台&#xff0c;桌面应用&#xff0c;还可以写可调用的模块&#xff0c;这里讲一下创建Java程序步骤&#xff0c;方便入门java语言开发。 新建一…

数字化采购:提升效率、优化供应链的新趋势

随着信息技术的快速发展&#xff0c;数字化采购正成为企业追求效率和优化供应链的新趋势。数字化采购是利用数字技术和互联网平台&#xff0c;实现采购流程的自动化和在线化。本文将围绕数字化采购的应用场景&#xff0c;探讨其在采购环节中带来的效益与优势。 一、在线供应商…

家居行业解决方案 | 君子签电子签约助力家居企业减负增效

过去&#xff0c;家居行业因供需两端碎片化、服务链条较长等因素&#xff0c;导致线上发展较为缓慢&#xff0c;近年来&#xff0c;互联网的发展推动直播电商、兴趣电商兴起&#xff0c;促使家居行业数字化建设需求越来越为迫切。 合同管理作为家居行业企业经营的一项重要管理…

wordpress发表文章时报错: rest_cannot_create,抱歉,您不能为此用户创建文章(已解决)

使用wordpress 的rest api发布文章&#xff0c;首先使用wp-json/jwt-auth/v1/token接口获取token&#xff0c;然后再使用/wp-json/wp/v2/posts 接口发表文章&#xff0c;但是使用axios请求时&#xff0c;却报错&#xff1a; 但是&#xff0c;我在postman上却是可以的&#xff0…