当前位置:网站首页>FFmpeg 音频解码(秒懂)
FFmpeg 音频解码(秒懂)
2022-07-21 16:58:00 【Mr.codeee】
1.简介
解码音频数据,如下图所示,把MP3或者AAC数据解码成原始的数据pcm。
2.流程
2.1在使用FFmpeg API之前,需要先注册API,然后才能使用API。当然,新版本的库不需要再调用下面的方法。
av_register_all()
2.2 构建输入AVFormatContext声明输入的封装结构体,通过输入文件或者流地址作为封装结构的句柄。
AVFormatContext* ifmt_ctx = NULL;
const char* inputUrl = "test.mp4";
///打开输入的流
int ret = avformat_open_input(&ifmt_ctx, inputUrl, NULL, NULL);
if (ret != 0)
{
printf("Couldn't open input stream.\n");
return -1;
}
2.3查找音频流信息,通过下面的接口与AVFormatContext中建立输入文件对应的流信息。
//查找;
if (avformat_find_stream_info(inputFmtCtx, NULL) < 0)
{
printf("Couldn't find stream information.\n");
return -1;
}
2.4查找解码器
先找到音频流索引,找到音频流,根据音频流的codec_id找到解码器。
//找到音频流索引
int audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
AVStream* st = ifmt_ctx->streams[audio_index];
AVCodec* codec = nullptr;
//找到解码器
codec = avcodec_find_decoder(st->codecpar->codec_id);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
2.5申请AVCodecContenxt
//申请AVCodecContext
AVCodecContext* codec_ctx = nullptr;
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
exit(1);
}
2.6同步AVCodecParameters
avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[audio_index]->codecpar);
2.7打开解码器
//打开解码器
if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0))
{
return -1;
}
2.8然后通过while循环,不停的读取数据,解码。
av_read_frame(ifmt_ctx, pkt)
avcodec_send_packet(codec_ctx, pkt);
avcodec_receive_frame(codec_ctx, frame);
3.源码
演示输入一个flv文件,保存解码后的pcm数据。
#include "pch.h"
#include <iostream>
extern "C"
{
#include "libavformat/avformat.h"
#include "libavutil/dict.h"
#include "libavutil/opt.h"
#include "libavutil/timestamp.h"
#include "libswscale/swscale.h"
#include "libswresample/swresample.h"
#include "libavutil/imgutils.h"
};
int main()
{
//av_register_all();
avformat_network_init();
AVFormatContext* ifmt_ctx = NULL;
const char* inputUrl = "out.flv";
///打开输入的流
int ret = avformat_open_input(&ifmt_ctx, inputUrl, NULL, NULL);
if (ret != 0)
{
printf("Couldn't open input stream.\n");
return -1;
}
//查找流信息
if (avformat_find_stream_info(ifmt_ctx, NULL) < 0)
{
printf("Couldn't find stream information.\n");
return -1;
}
//找到音频流索引
int audio_index = av_find_best_stream(ifmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1, NULL, 0);
AVStream* st = ifmt_ctx->streams[audio_index];
AVCodec* codec = nullptr;
//找到解码器
codec = avcodec_find_decoder(st->codecpar->codec_id);
if (!codec)
{
fprintf(stderr, "Codec not found\n");
exit(1);
}
//申请AVCodecContext
AVCodecContext* codec_ctx = nullptr;
codec_ctx = avcodec_alloc_context3(codec);
if (!codec_ctx)
{
exit(1);
}
avcodec_parameters_to_context(codec_ctx, ifmt_ctx->streams[audio_index]->codecpar);
//打开解码器
if ((ret = avcodec_open2(codec_ctx, codec, NULL) < 0))
{
return -1;
}
AVPacket* pkt = av_packet_alloc();
//av_init_packet(pkt);
AVFrame *frame = av_frame_alloc();
char fileName[20] = "test.pcm";
FILE* f;
f = fopen(fileName, "wb");
while (av_read_frame(ifmt_ctx, pkt) >= 0)
{
if (pkt->stream_index == audio_index)
{
int ret = avcodec_send_packet(codec_ctx, pkt);
if (ret >= 0)
{
ret = avcodec_receive_frame(codec_ctx, frame);
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
{
break;
}
else if (ret < 0)
{
break;
}
int data_size = av_get_bytes_per_sample(codec_ctx->sample_fmt);
if (data_size < 0) {
continue;
}
for (int i = 0; i < frame->nb_samples; i++)
{
for (int ch = 0; ch < codec_ctx->channels; ch++)
{
fwrite(frame->data[ch] + data_size * i, 1, data_size, f);
}
}
}
}
}
fclose(f);
avcodec_close(codec_ctx);
avcodec_free_context(&codec_ctx);
avformat_close_input(&ifmt_ctx);
av_frame_free(&frame);
av_packet_free(&pkt);
return 0;
}
4.pcm数据工具,用于播放pcm文件
pcm工具pcm工具pcm工具-C++文档类资源-CSDN下载
5.查看解码前的音频数据
可以看见解码前 :采样率是48000HZ,双声道,fltp格式。
使用pcm工具播放 保存好的pcm文件。
选择导入原始数据,设置参数跟上面一样,点击播放就行了,如果数据正确,跟解码前听到的音频是一致的。
6.一些命令使用
6.1从视频文件中分离出MP3文件
ffmpeg -i out.flv -acodec libmp3lame output.mp3
6.2查看文件信息
ffprobe.exe -i out.flv
边栏推荐
- 移动端测试需要注意的问题
- Error: L6200E: Symbol keyflag multiply defined (by main.o and key.o).
- Airflow scheduling start_ Date explanation
- C语言大小端模式判断函数
- youtube字幕下载
- 服务器中激活刚安装好的anaconda
- Detailed explanation of UNET (with graphics and code implementation)
- “万物互联,使能千行百业”,2022 开放原子全球开源峰会 OpenAtom OpenHarmony 分论坛即将开幕
- Information sharing | hc-05 Bluetooth module information
- SSM项目完整源码[通俗易懂]
猜你喜欢
支付宝统一支付回调接口(适用于H5、PC、APP)
Intégration de l'efk avec l'odoo pour réaliser la visualisation des journaux
小波变换中的多贝西小波(DB小波函数)概述
Anaconda installs jupyter lab + jupyterlsp (code prompt, code error correction) detailed construction process
WebSockets and server sent events
FFT快速傅里叶变换在字符串匹配中的应用详解【附模板,例题】五千字详解
NOR FLASH 和 NAND FLASH异同
"Everything is interconnected, enabling thousands of industries", the 2022 open atom global open source summit openatom openharmony sub forum is about to open
Detailed explanation of the application of FFT fast Fourier transform in string matching [attached template, example] 5000 word detailed explanation
生成函数(线性递推关系,生成函数概念与公式推导,暴力计算)四千字详细解析,附例题
随机推荐
jmmert聚合测试报告
资料分享|基于SHT11的简易温湿度检测仿真
Anaconda安装jupyter lab + jupyterlsp(代码提示,代码纠错)详细搭建过程
C中如何打开stdio.h ? 如何找到printf的定义?
CDH 6.1 environment construction graphic tutorial
excel 中粘贴时怎么不覆盖
STM32 HAL库 SPI总是读出FF的问题解决!
Airflow scheduling start_ Date explanation
R语言使用oneway.test函数执行单因素方差分析(One-Way ANOVA)、如果组间具有相同的方差则设置var.equal参数为TRUE获取更加宽松的检验
物理地址介绍「建议收藏」
Extjs4实例地址和中文文档地址
Distsql deep parsing: creating a dynamic distributed database
R语言ggplot2可视化:可视化散点图并为散点图中的数据点添加公式标签、使用ggrepel包的geom_text_repel函数避免数据点公式标签互相重叠(添加公式标签)
R language ggplot2 visualization: visualize the scatter diagram, add formula labels to the data points in the scatter diagram, and use geom of ggrep package_ text_ The repl function avoids overlapping
JMeter --- FTP performance test
Detailed explanation of ternary operators in JS
同花顺开户安全么 中国十大证券公司排名
R language & and & Precautions
R language uses the mean function to calculate the relative frequency of the specified variables in the sample (observation) data: calculate the proportion of the observation samples in the dataframe
jmeter---ftp性能测试