jjzjj

FFmpeg 音频解码(秒懂)

Mr.codeee 2023-12-15 原文

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 音频解码(秒懂)的更多相关文章

  1. python ffmpeg 使用 pyav 转换 一组图像 到 视频 - 2

    2022/8/4更新支持加入水印水印必须包含透明图像,并且水印图像大小要等于原图像的大小pythonconvert_image_to_video.py-f30-mwatermark.pngim_dirout.mkv2022/6/21更新让命令行参数更加易用新的命令行使用方法pythonconvert_image_to_video.py-f30im_dirout.mkvFFMPEG命令行转换一组JPG图像到视频时,是将这组图像视为MJPG流。我需要转换一组PNG图像到视频,FFMPEG就不认了。pyav内置了ffmpeg库,不需要系统带有ffmpeg工具因此我使用ffmpeg的python包装p

  2. ruby - 无法在 Ruby 中将 ffmpeg 作为子进程运行 - 2

    我正在尝试使用以下代码通过将ffmpeg实用程序作为子进程运行并获取其输出并解析它来确定视频分辨率:IO.popen'ffmpeg-i'+path_to_filedo|ffmpegIO|#myparsegoeshereend...但是ffmpeg输出仍然连接到标准输出并且ffmepgIO.readlines是空的。ffmpeg实用程序是否需要一些特殊处理?或者还有其他方法可以获得ffmpeg输出吗?我在WinXP和FedoraLinux下测试了这段代码-结果是一样的。 最佳答案 要跟进mouviciel的评论,您需要使用类似pope

  3. micropython复现经典单片机项目(二)可视化音频 频谱解析(基本搞定) - 2

    本人是音乐爱好者,从小就特别喜欢那个随着音乐跳动的方框效果,就是这个:arduino上一大把对,我忍你很久了,我就想用mpy做,全网没有,行我自己研究。果然兴趣是最好的老师,我之前有篇博客专门讲音频,有兴趣的可以回顾一下。提到可视化频谱,必然绕不开fft,大学学过这玩意,当时一心玩,老师讲的一个字都么听进去,网上教程简略扫了一下,大该就是把时域转频域的工具,我大mpy居然没有fft函数,奶奶的,先放着。音频信息如何收集?第一种傻瓜式的ADC,模拟转数字,原始粗暴,第二种,I2S库,我之前博客有讲过,数据是PCM编码。然后又去学PCM编码,一学豁然开朗,舒服,以代码为例:audio_in=I2S

  4. ruby-on-rails - JSON解码参数问题 - 2

    我有一个使用postgresql的Rails4应用程序。我还有一个backbone.js应用程序,可将JSON推送到Rails4应用程序。这是我的Controller:defcreate@product=Product.new(ActiveSupport::JSON.decodeproduct_params)respond_todo|format|if@product.saveformat.json{renderaction:'show',status::created,location:@product}elseformat.json{renderjson:@product.erro

  5. ruby - 如何使用 bash 命令或 Ruby 使用 ffmpeg 将 mp4 文件批量转换为 ogg - 2

    我运行的是OSX,对视频转换一无所知。但我有大约200个视频都是mp4格式,无法在Firefox中播放。我需要将它们转换为ogg才能使用html5视频标签。这些文件位于一个文件夹结构中,这使得一次一个地处理一个文件变得困难。我希望bash命令或Ruby命令遍历所有子文件夹并找到所有.mp4并转换它们。我找到了一份关于如何使用Google执行此操作的引用资料:http://athmasagar.wordpress.com/2011/05/12/a-bash-script-to-convert-mp4-files-to-oggogv/#!/bin/bashforfin$(ls*mp4|se

  6. Java调用ffmpeg处理视频,并记录下遇到的坑 - 2

    目录需求基于JavaCV跨平台执行ffmpeg命令[^1]坑一内存不足坑二多个ffmpeg进程并行导致IO负载大,进而导致ioerror?坑三使用Java操作ffmpeg时,有时会卡死坑四Process的waitFor死锁问题及解决办法需求给透明背景的视频自动叠加一张背景图片基于JavaCV跨平台执行ffmpeg命令1我测试发现的本需求的最小依赖:dependency>groupId>org.bytedecogroupId>artifactId>ffmpeg-platform-gplartifactId>version>5.0-1.5.7version>dependency>核心代码:Stri

  7. ruby-on-rails - ActiveSupport::JSON 解码散列丢失符号 - 2

    我正在尝试序列化和反序列化哈希。当散列被反序列化时,键被去符号化;例如不是更多:一个,而是“一个”。从Rails控制台:>>h={:one=>1,:two=>"two"}{:one=>1,:two=>"two"}>>j=ActiveSupport::JSON.encode(h)"{\"one\":1,\"two\":\"two\"}">>h2=ActiveSupport::JSON.decode(j){"one"=>1,"two"=>"two"}>>h2[:one]nil>>h[:one]1我现在已经切换到使用Marshal.dump/load。但是,我想把它扔出去看看是否有办法将它保

  8. 基于ffmpeg的视频处理与MPEG的压缩试验(下载安装使用全流程) - 2

    基于ffmpeg的视频处理与MPEG的压缩试验ffmpeg介绍与基础知识对提取到的图像进行处理RGB并转化为YUV对YUV进行DCT变换对每个8*8的图像块进行进行量化操作ffmpeg介绍与基础知识ffmpeg是视频和图像处理的工具包,它的下载网址是https://ffmpeg.org/download.html。页面都是英文且下载正确的包的路径笔者找的时候还费点劲,这里记录一下也方便读者。选中这个Windows下的下午files,选择第一个这里有essential和full版本的,大家根据需要自行选择版本包下载下载好之后,在官网上下载ffmpeg的full包,一共300+MB解压,然后安装b

  9. 解决台式机麦克风不可用问题,只有音频输出,无音频输入 - 2

    解决台式机麦克风不可用问题戴尔灵越3880最近因为需要开线上会议,发现戴尔台式机音频只有输出没有输入,也就是只能听见声音,无法输入声音。先后尝试了各种驱动安装更新之类的调试,无果。之后通过戴尔支持解决~这里多说一句,专业的就是专业,问题描述过去,直接给了解决方案,可能是他们遇到的相似问题比较多了,但也告诉我们,有些时候是可以通过这些官方服务解决问题的,比起自己折腾效率要高很多。那就记录一下吧~问题描述:电脑只能输出声音,不能输入声音。1、前提需要准备一只带麦克风的耳机,将耳机插入面板。2、先确定是否可以听到声音,可以通过播放歌曲或者视频。3、然后确认麦克风是否可用,可以通过调用win自带麦克风

  10. html - 如何在 Ruby 中编码/解码 HTML 实体? - 2

    我正在尝试解码一些HTML实体,例如'&lt;'成为'.我有一个旧gem(html_helpers),但它似乎已经被遗弃了两次。有什么建议吗?我需要在模型中使用它。 最佳答案 要对字符进行编码,可以使用CGI.escapeHTML:string=CGI.escapeHTML('test"escaping"')要解码它们,有CGI.unescapeHTML:CGI.unescapeHTML("test"unescaping"<characters>")当然,在此之前你需要包含CGI库:requi

随机推荐