FFmpeg 音频解码(秒懂)

Posted Mr.codeee

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了FFmpeg 音频解码(秒懂)相关的知识,希望对你有一定的参考价值。

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

FFmpeg进行音频的解码和播放

参考技术A FFmpeg4.0.2编译32位和64位动态库
FFmpeg 内容介绍 音视频解码和播放

音频数字化主要有压缩与非压缩(pcm)两种方式。

上一篇 FFmpeg 内容介绍 音视频解码和播放 介绍了FFmpeg进行解码的常见函数和,解码的过程。相关的函数介绍忘记了,可以参考上一篇。

思路:由FFmpeg进行解码,将解码后的数据再通过jni传到Java中的audioTrack对象进行播放

以上就是利用FFmpeg对音频文件进行解码以及播放的内容,如果有错误,欢迎大家指正出来

以上是关于FFmpeg 音频解码(秒懂)的主要内容,如果未能解决你的问题,请参考以下文章

Qt-FFmpeg开发-音频解码为PCM文件

FFMPEG 视频图像解封装解码

第十章 视频播放器开发之音频播放

QT软件开发-基于FFMPEG设计视频播放器-解码音频

基于FFmpeg的视频播放器之七:音频解码

Linux下基于ffmpeg音视频解码