最简单的基于 FFmpeg 的音频解码器

最简单的基于 FFmpeg 的音频解码器

  • 最简单的基于 FFmpeg 的音频解码器
    • 正文
    • 参考
    • 工程文件下载

参考雷霄骅博士的文章,链接:最简单的基于FFMPEG+SDL的音频播放器:拆分-解码器和播放器

最简单的基于 FFmpeg 的音频解码器

正文

FFmpeg 音频解码器实现了音频数据到 PCM 采样数据的解码。

如果你不会 Vusual Studio 下 FFmpeg 的项目配置,可以看我写的教程:Visual Studio 2015 中 FFmpeg 开发环境的搭建。

源代码:

// Simplest FFmpeg Audio Decoder.cpp : 定义控制台应用程序的入口点。/**
* 最简单的基于 FFmpeg 的音频解码器
* Simplest FFmpeg Audio Decoder
*
* 刘文晨 Liu Wenchen
* 812288728@qq.com
* 电子科技大学/电子信息
* University of Electronic Science and Technology of China / Electronic and Information Science
* https://blog.csdn.net/ProgramNovice
*
* 本程序可以将音频码流(MP3,AAC等)解码为 PCM 采样数据。
*
* This software decode audio streams (MP3, ACC...) to PCM data.
*
*/#include "stdafx.h"#include <stdio.h>
#include <stdlib.h>
#include <string.h>#define __STDC_CONSTANT_MACROS
#ifdef _WIN32
// Windows
extern "C"
{
#include "libavcodec/avcodec.h"
#include "libavformat/avformat.h"
#include "libswresample/swresample.h"
};
#else
// Linux
#endif// 1 second of 48kHz 32bit audio,单位是字节
#define MAX_AUDIO_FRAME_SIZE 192000 int main(int argc, char* argv[])
{// 结构体及变量定义AVFormatContext* pFormatCtx;int i, audioStream;AVCodecContext* pCodecCtx;AVCodec* pCodec;AVPacket* packet;uint8_t* out_buffer;AVFrame* pFrame;int ret;uint32_t len = 0;int got_picture;int index = 0;int64_t in_channel_layout;struct SwrContext *au_convert_ctx;// 输出文件路径FILE *pFile = fopen("output.pcm", "wb");// 输入文件路径char url[] = "skycity.mp3";// 注册支持的所有的文件格式(容器)及其对应的 CODEC,只需要调用一次av_register_all();// 对网络库进行全局初始化(加载 socket 库以及网络加密协议相关的库,为后续使用网络相关提供支持)// 注意:此函数仅用于解决旧 GnuTLS 或 OpenSSL 库的线程安全问题。// 如果 libavformat 链接到这些库的较新版本,或者不使用它们,则无需调用此函数。// 否则,需要在使用它们的任何其他线程启动之前调用此函数。avformat_network_init();// 使用默认参数分配并初始化一个 AVFormatContext 对象pFormatCtx = avformat_alloc_context();// 打开输入媒体流,分配编解码器上下文、解复用上下文、I/O 上下文if (avformat_open_input(&pFormatCtx, url, NULL, NULL) != 0){printf("Can't open input stream.\n");return -1;}// 读取媒体文件的数据包以获取媒体流信息if (avformat_find_stream_info(pFormatCtx, NULL) < 0){printf("Can't find stream information.\n");return -1;}printf("---------------- File Information ---------------\n");// 将 AVFormatContext 结构体中媒体文件的信息进行格式化输出av_dump_format(pFormatCtx, 0, url, false);printf("-------------------------------------------------\n");audioStream = -1;for (i = 0; i < pFormatCtx->nb_streams; i++){if (pFormatCtx->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO){audioStream = i;break;}}if (audioStream == -1){printf("Can't find a audio stream.\n");return -1;}// pCodecCtx 是指向音频流的编解码器上下文的指针pCodecCtx = pFormatCtx->streams[audioStream]->codec;// 查找 ID 为 pCodecCtx->codec_id 的已注册的音频流解码器pCodec = avcodec_find_decoder(pCodecCtx->codec_id);if (pCodec == NULL){printf("Codec not found.\n");return -1;}// 初始化指定的编解码器if (avcodec_open2(pCodecCtx, pCodec, NULL) < 0){printf("Can't open codec.\n");return -1;}// 为 packet 分配空间packet = (AVPacket *)av_malloc(sizeof(AVPacket));// 将 packet 中的可选字段初始化为默认值av_init_packet(packet);// 输出音频参数// 通道类型:双声道uint64_t out_channel_layout = AV_CH_LAYOUT_STEREO;int out_nb_samples = pCodecCtx->frame_size;// 采样格式:pcm_s16le(整型 16bit)AVSampleFormat out_sample_fmt = AV_SAMPLE_FMT_S16;// 采样率:44100int out_sample_rate = 44100;int out_channels = av_get_channel_layout_nb_channels(out_channel_layout);int out_buffer_size = av_samples_get_buffer_size(NULL, out_channels, out_nb_samples, out_sample_fmt, 1);out_buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE * 2);pFrame = av_frame_alloc();// 根据声道数目获取声道布局in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);// 创建重采样结构体 SwrContext 对象au_convert_ctx = swr_alloc();// 设置重采样的转换参数au_convert_ctx = swr_alloc_set_opts(au_convert_ctx, out_channel_layout, out_sample_fmt, out_sample_rate,in_channel_layout, pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL);// 初始化 SwrContext 对象swr_init(au_convert_ctx);// 读取码流中的音频若干帧或者视频一帧while (av_read_frame(pFormatCtx, packet) >= 0){if (packet->stream_index == audioStream){// 解码 packet 中的音频数据,pFrame 存储解码数据ret = avcodec_decode_audio4(pCodecCtx, pFrame, &got_picture, packet);if (ret < 0){printf("Error in decoding audio frame.\n");return -1;}if (got_picture > 0){// 进行格式转换,返回值为实际转换的采样数swr_convert(au_convert_ctx, &out_buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pFrame->data, pFrame->nb_samples);// 打印每一帧的信息printf("index: %5d\t pts: %lld\t packet size: %d\n", index, packet->pts, packet->size);// 向输出文件中写入 PCM 数据fwrite(out_buffer, 1, out_buffer_size, pFile);index++;}}// 清空 packet 里面的数据av_free_packet(packet);}// 释放 SwrContext 对象swr_free(&au_convert_ctx);// 关闭文件指针fclose(pFile);// 释放内存av_free(out_buffer);// 关闭解码器avcodec_close(pCodecCtx);// 关闭输入音频文件avformat_close_input(&pFormatCtx);return 0;
}

本程序可以直接在 Visual Studio 2015 上运行。

程序运行后,会解码下面的音频文件。

在这里插入图片描述

解码后的 PCM 采样数据被保存成了一个文件,名叫 output.pcm。使用 Adobe Audition 设置采样率等信息后可以查看 PCM 的内容。

在这里插入图片描述

在这里插入图片描述

参考

05 FFmpeg4.4源码分析–解码

error C4996: ‘fopen’: This function or variable may be unsafe 的解决方法

工程文件下载

GitHub:UestcXiye / Simplest-FFmpeg-Audio-Decoder

CSDN:Simplest FFmpeg Audio Decoder.zip

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

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

相关文章

Spring Cloud Gateway 网关的基础使用

1. 什么是网关&#xff1f;网关有什么用&#xff1f; 在微服务架构中&#xff0c;网关就是一个提供统一访问地址的组件&#xff0c;它解决了内部微服务与外部的交互问题。网关主要负责流量的路由和转发&#xff0c;将外部请求引到对应的微服务实例上。同时提供身份认证、授权、…

Spring-Boot---配置文件

文章目录 配置文件的作用配置文件的格式PropertiesProperties基本语法读取Properties配置文件 ymlyml基本语法读取yml配置文件 Properties VS Yml 配置文件的作用 整个项目中所有重要的数据都是在配置文件中配置的&#xff0c;具有非常重要的作用。比如&#xff1a; 数据库的…

Python绘制多分类ROC曲线

目录 1 数据集介绍 1.1 数据集简介 1.2 数据预处理 2随机森林分类 2.1 数据加载 2.2 参数寻优 2.3 模型训练与评估 3 绘制十分类ROC曲线 第一步&#xff0c;计算每个分类的预测结果概率 第二步&#xff0c;画图数据准备 第三步&#xff0c;绘制十分类ROC曲线 1 数据集…

【数据结构】——排序篇(上)

前言&#xff1a;前面我们已经学过了许许多多的排序方法&#xff0c;如冒泡排序&#xff0c;选择排序&#xff0c;堆排序等等&#xff0c;那么我们就来将排序的方法总结一下。 我们的排序方法包括以下几种&#xff0c;而快速排序和归并排序我们后面进行详细的讲解。 直接插入…

Qt实现二维码生成和识别

一、简介 QZxing开源库: 生成和识别条码和二维码 下载地址&#xff1a;https://gitcode.com/mirrors/ftylitak/qzxing/tree/master 二、编译与使用 1.下载并解压&#xff0c;解压之后如图所示 2.编译 打开src目录下的QZXing.pro&#xff0c;选择合适的编译器进行编译 最后生…

MIT6S081-Lab2总结

大家好&#xff0c;我叫徐锦桐&#xff0c;个人博客地址为www.xujintong.com&#xff0c;github地址为https://github.com/xjintong。平时记录一下学习计算机过程中获取的知识&#xff0c;还有日常折腾的经验&#xff0c;欢迎大家访问。 Lab2就是了解一下xv6的系统调用流程&…

解决服务端渲染程序SSR运行时报错: ReferenceError: document is not defined

现象&#xff1a; 原因&#xff1a; 该错误表明在服务端渲染 (SSR) 过程中&#xff0c;有一些代码尝试在没有浏览器环境的情况下执行与浏览器相关的操作。这在服务端渲染期间是一个常见的问题&#xff0c;因为在服务端渲染期间是没有浏览器 API。 解决办法&#xff1a; 1. 修…

【2023传智杯-新增场次】第六届传智杯程序设计挑战赛AB组-DEF题复盘解题分析详解【JavaPythonC++解题笔记】

本文仅为【2023传智杯-第二场】第六届传智杯程序设计挑战赛-题目解题分析详解的解题个人笔记,个人解题分析记录。 本文包含:第六届传智杯程序设计挑战赛题目、解题思路分析、解题代码、解题代码详解 文章目录 一.前言二.赛题题目D题题目-E题题目-F题题目-二.赛题题解D题题解-…

深入理解Sentinel系列-1.初识Sentinel

&#x1f44f;作者简介&#xff1a;大家好&#xff0c;我是爱吃芝士的土豆倪&#xff0c;24届校招生Java选手&#xff0c;很高兴认识大家&#x1f4d5;系列专栏&#xff1a;Spring源码、JUC源码、Kafka原理、分布式技术原理&#x1f525;如果感觉博主的文章还不错的话&#xff…

如何搭建自己的直播电商系统?

当下&#xff0c;传统的图文电商模式已经走向没落&#xff0c;视频电商备受追捧。抖音、快手、小红书、京东、淘宝、拼多多都在发力直播电商业务&#xff0c;尤其是以抖音为首的直播电商备受用户欢迎&#xff0c;它具有实时直播和强互动的特点&#xff0c;是传统电商所不具备的…

最长子串问题(LCS)--动态规划解法

题目描述&#xff1a; 如果Z既是X的子串&#xff0c;又是Y的子串&#xff0c;则称Z为X和Y的公共子串。 如果给定X、Y&#xff0c;求出最长Z及其长度。 注意&#xff1a;这里求的不是子序列&#xff0c;两者的意思并不相同。子串要求连续&#xff0c;子序列并不需要。 如果想…

simulinkveristandlabview联合仿真环境搭建

目录 开篇废话 软件版本 明确需求 软件安装 matlab2020a veristand2020 R4 VS2017 VS2010 软件安装验证 软件资源分享 开篇废话 推免之后接到的第一个让人难绷的活&#xff0c;网上开源的软件资料和成功的案例很少&#xff0c;查来查去就那么几篇&#xff0c;而且版本…

SpringData

1.为什么要学习SpringData&#xff1f; 是因为对数据存储的框架太多了&#xff0c;全部都要学习成本比较高&#xff0c;SpringData对这些数据存储层做了一个统一&#xff0c;学习成本大大降低。

SQL命令---修改字段的数据类型

介绍 使用sql语句修改字段的数据类型。 命令 alter table 表明 modify 字段名 数据类型;例子 有一张a表&#xff0c;表里有一个id字段&#xff0c;长度为11。使用命令将长度修改为12 下面使用命令进行修改&#xff1a; alter table a modify id int(12) NOT NULL;下面使修…

stm32使用多串口不输出无反应的问题(usart1、usart2)

在使用stm32c8t6单片机时&#xff0c;由于需要使用两个串口usart1 、usart2。usart1用作程序烧录、调试作用&#xff0c;串口2用于与其它模块进行通信。 使用串口1时&#xff0c;正常工作&#xff0c;使用串口2时&#xff0c;无反应。查阅了相关资料串口2在PA2\PA3 引脚上。RX…

[仅供学习,禁止用于违法]编写一个程序来手动设置Windows的全局代理开或关,实现对所有网络请求拦截和数据包捕获(抓包或VPN的应用)

文章目录 介绍一、实现原理二、通过注册表设置代理2.1 开启代理2.2 关闭代理2.3 添加代理地址2.4 删除代理设置信息 三、代码实战3.1 程序控制代理操作控制3.1.1 开启全局代理3.1.2 添加代理地址3.1.3 关闭代理开关3.1.4 删除代理信息 3.2 拦截所有请求 介绍 有一天突发奇想&am…

在git使用SSH密钥进行github身份认证学习笔记

1.生成ssh密钥对 官网文档&#xff1a;Https://docs.github.com/zh/authentication&#xff08;本节内容对应的官方文档&#xff0c;不清晰的地方可参考此内容&#xff09; 首先&#xff0c;启动我们的git bush&#xff08;在桌面右键&#xff0c;点击 Git Bush Here &#xf…

iOS_制作 cocopods库

文章目录 1.创建项目2.配置项目3.发布 1.创建项目 在 github 上创建仓库&#xff0c;克隆到本地&#xff1a; git clone https://github.com/mxh-mo/MOOXXX.git在项目目录下执行&#xff1a; pod lib create <库名称>进行一些配置的选择&#xff1a; # 希望在那个平台…

随机分词与tokenizer(BPE->BBPE->Wordpiece->Unigram->sentencepiece->bytepiece)

0 tokenizer综述 根据不同的切分粒度可以把tokenizer分为: 基于词的切分&#xff0c;基于字的切分和基于subword的切分。 基于subword的切分是目前的主流切分方式。subword的切分包括: BPE(/BBPE), WordPiece 和 Unigram三种分词模型。其中WordPiece可以认为是一种特殊的BPE。完…

求Sn=m+mm+mmm+...+mm..mmm(有n个m)的值

题目&#xff1a;求 的值 一、做这个题我们其实可以直接一个for求解&#xff1a; a,aa,aaa...我们很容易知道它们后一项与前一项的关系就是&#xff1b; public static void Sum(int m,int n){long sum 0L;long curAn 0;for (int i 0; i < n; i){curAn m 10* curAn;/…