CLion中avcodec_receive_frame()问题

news2024/11/19 23:24:50

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/830645.html

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

相关文章

谈「效」风生 |“效能指标”,该由谁来定义?

#第5期&#xff1a;效能指标&#xff0c;该由谁来定义&#xff1f;# 回顾上期《「自动化」聊起来简单&#xff0c;做起来难》我们聊了聊如何打造「自动化」的事&#xff0c;这也是真正实现研发效能提升的必要条件。从单点自动化提升效率&#xff0c;到全工具链自动化&#xff…

【Java环境不会搭建?一文带你读懂Windows下安装Java!】

JKD下载网址 —— https://www.oracle.com/java/technologies/javase/javase-jdk8-downloads.html 1、如果你是32位系统下载 jdk-8u241-windows-i586.exe&#xff08;32位&#xff09;&#xff1b; 2、如果你是64位系统下载 jdk-8u241-windows-x64.exe&#xff08;64位&…

【freespace】HybridNets: End-to-End Perception Network

目录 摘要 1. 介绍 1.1. 背景 1.2. 相关工作 2. 方法 2.1. 网络体系结构 2.2. 编码器 2.3. 译码器 2.4. 损失函数和训练 3. 实验与评估 3.1. 实验设置 3.2. 评价指标 3.3. 成本计算性能 3.4. 多任务性能 4. 结论与展望 摘要 端到端网络在多任务处理中变得越来越重要…

Godot 4 源码分析 - 增加格式化字符串功能

Godot 4的主要字符串类型为String&#xff0c;已经设计得比较完善了&#xff0c;但有一个问题&#xff0c;格式化这块没怎么考虑。 String中有一个format函数&#xff0c;但这个函数只有两个参数&#xff0c;这咋用&#xff1f; String String::format(const Variant &va…

Rocketmq 定时消息源码分析

定时消息定义 生产者将消息投放到broker后&#xff0c;不会马上被消费者消费。需要等待到特定时间才会被消费。 调用链路 producer 将定时消息写入commitLog线程ReputThead 休息1毫秒&#xff0c;读取一次commitlog数据&#xff0c;写入ConsumeQueue和IndexFile线程Scheduled…

所学即所用:方飞将AI技术运用于反偷猎领域

原创 | 文 BFT机器人 方飞&#xff0c;高中毕业于江苏省常州高级中学&#xff0c;于2007年进入清华大学电子工程系攻读学士学位&#xff0c;2011年本科毕业后赴美国南加州大学计算机系攻读博士&#xff0c;主要从事安全博弈研究&#xff0c;师从安全博弈领域的权威专家 Milind…

vxworks文件系统分析

参考https://www.freebuf.com/articles/endpoint/335030.html 测试固件 https://service.tp-link.com.cn/detail_download_7989.html 固件提取 binwalk解压固件&#xff0c;在第一部分即为要分析的二进制文件&#xff0c;可以拖进ida分析 设置为arm小端字节序&#xff0c;点…

爆火的“为i做e”梗,小红书如何成为年轻人的社交货币?

话题浏览超13亿&#xff0c;“新社交密码”抢占用户心智 2023-08-03 草稿临时预览&#xff0c;有效期剩余59分59秒 请勿包含诱导分享&#xff0c;虚假中奖&#xff0c;违法违纪等信息。 爆火的“为i做e”梗、将MBTI写进个人简介、花样百出的MBI梗图 ...... 从去年5月到现在&…

手把手教你安装Eclipse最新版本的详细教程 (非常详细,非常实用)

简介 首先声明此篇文章主要是针对测试菜鸟或者刚刚入门的小伙们或者童鞋们&#xff0c;大佬就没有必要往下看了。 写这篇文章的由来是因为后边要用这个工具&#xff0c;但是由于某些原因有部分小伙伴和童鞋们可能不会安装此工具&#xff0c;为了方便小伙伴们和童鞋们的后续学习…

第五届宁波市卫生健康系统信息化技能竞赛暨赛前培训成功举办 平凯星辰受邀授课

近日&#xff0c; 第五届宁波市卫生健康系统第五届信息化技能竞赛暨赛前培训在宁波饭店成功举办 。本次培训吸引了来自区、县、市属各级医疗单位的信息化相关负责人参与。宁波市卫生信息中心副主任唐玲作主题发言&#xff0c; 平凯星辰作为中国数据库代表厂商&#xff0c;受邀进…

企业级,Pytest自动化测试框架脚本编写总结,看这篇就够了...

目录&#xff1a;导读 前言一、Python编程入门到精通二、接口自动化项目实战三、Web自动化项目实战四、App自动化项目实战五、一线大厂简历六、测试开发DevOps体系七、常用自动化测试工具八、JMeter性能测试九、总结&#xff08;尾部小惊喜&#xff09; 前言 用到的知识点&…

web爬虫第四弹 - JS逆向入门(猿人学第一题)

0- 前言 爬虫是一门需要实战的学问。 而对于初学者来说&#xff0c;要想学好反爬&#xff0c;js逆向则是敲门砖。今天给大家带来一个js逆向入门实例&#xff0c;接下来我们一步一步来感受下入门的逆向是什么样的。该案例选自猿人学练习题。猿人学第一题 1- 拿到需求 进入页面…

矩阵怎么求导数(学习笔记)

当标量 拓展到向量的时候 需要弄清楚形状 这里 看图大概是不清晰的 先要看清楚谁是向量 y 是向量 x 是标量 求导之后 仍然还是向量 y 是标量 x 是向量 求导之后 仍然还是向量 两个都是向量 求导之后 是矩阵 标量大家都会的 啊 求导 的意义很重要 如图所示 梯度一定指…

51单片机(普中HC6800-EM3 V3.0)实验例程软件分析 实验一 点亮第一个LED

目录 前言 一、原理图及知识点介绍 1.1、LED原理图 1.2、MCU51原理图 二、代码分析 知识点一&#xff1a;#include "reg52.h" //此文件中定义了单片机的一些特殊功能寄存器 知识点二&#xff1a;你知道sfr P0 0x80;是怎么来的呢为什么要赋值0x80&#xff…

Java基础面试题2

Java基础面试题 一、IO和多线程专题 1.介绍下进程和线程的关系 进程&#xff1a;一个独立的正在执行的程序 线程&#xff1a;一个进程的最基本的执行单位&#xff0c;执行路径 多进程&#xff1a;在操作系统中&#xff0c;同时运行多个程序 多进程的好处&#xff1a;可以充…

7种有效安全的网页抓取方法,如何避免被禁止?

网页抓取是一种从互联网上抓取网页内容的过程&#xff0c;但在网络抓取种相信您也经常遇到障碍&#xff1f;尤其是做跨境业务的&#xff0c;在抓取国外的网站时更有难度。但我们站在您的立场上&#xff0c;提供七种有效的方法来进行网页抓取而不被阻止&#xff0c;最大限度地降…

JVM面试突击班2

JVM面试突击班2 对象被判定为不可达对象之后就“死”了吗 对象的生命周期 创建阶段 &#xff08;1&#xff09;为对象分配存储空间 &#xff08;2&#xff09;开始构造对象 &#xff08;3&#xff09;从超类到子类对static成员进行初始化 &#xff08;4&#xff09;超类成…

如何搭建WordPress博客网站,并且发布至公网上?

如何搭建WordPress博客网站&#xff0c;并且发布至公网上&#xff1f; 文章目录 如何搭建WordPress博客网站&#xff0c;并且发布至公网上&#xff1f;概述前置准备1 安装数据库管理工具1.1 安装图形图数据库管理工具&#xff0c;SQL_Front 2 创建一个新数据库2.1 创建数据库2.…

基于DiscordMidjourney API接口实现文生图

https://discord.com/api/v9/interactions 请求头&#xff1a; authorization:取自 浏览器中discord 文生图请求头中的 authorization 的值 Content-Type:application/json 请求体&#xff1a; {“type”:2,“application_id”:“93692956130267xxxx”,“guild_id”:“1135900…

Error message “error:0308010C:digital envelope routines::unsupported“

https://stackoverflow.com/questions/69692842/error-message-error0308010cdigital-envelope-routinesunsupported nvm install 16即可解决