FFMPEG提取音频流数据

  FFmpeg是一套开源的计算机程序,主要用于记录、转换数字音频、视频,并能将其转化为流。它提供了录制、转换以及流化音视频的完整解决方案,被誉为多媒体业界的“瑞士军刀”。

1.使用ffmpeg命令实现音频流数据提取

[wbyq@wbyq ffmpeg]$ ffmpeg -i 1.mp4 -acodec copy -vn test.aac
  • acodec: 指定音频编码器,copy 指明只拷贝,不做编解码。
  • vn: v 代表视频,n 代表 no 也就是无视频的意思。

2.调用ffmpeg库使用音频流数据提取

  从一个视频中抽取音频流数据操作步骤:
  (1)打开音视频原文件avformat_open_input()
  (2)读取音视频流数据包,获取流信息avformat_find_stream_info()
    该函数不会影响正常文件信息,一些媒体文件在没有标头信息必须要调用该函数;
    若要输出当前媒体流信息,可调到av_dump_format() ;输出流信息,若不需要查看,则可不调用该函数;
    从媒体文件中查找要解析的流数据av_find_best_stream() ;调用成功返回解析的流下标;
  (3)创建一个输出媒体上下文件指针avformat_alloc_context()
  (4)根据媒体文件类型注册格式av_guess_format()
  (5)创建一个流数据avformat_new_stream()
  (6)将源媒体文件流数据拷贝到目的媒体文件中avcodec_parameters_copy()
  (7)打开目的媒体文件avio_open(),将多媒体头数据写入到目标文件avformat_write_header()
  (8)循环从源媒体文件中读取流数据包av_read_frame() ;判断读取的流数据是否和查找解析的流数据一致,若一致的话将数据包写入大目标媒体文件中av_interleaved_write_frame() ,该函数可以按dts顺序写入,写入完后释放pack包av_packet_unref() ;在写入数据包之前,需要设置dts、pts、duration、stream_index、pos 参数;
  (9)写入多媒体尾数据av_write_trailer
  (10)释放资源,自此,流数据抽取成功;
    avformat_free_context()
    avforamt_close_input()

  整体流程图如下所示:
在这里插入图片描述

3.整体代码实现

#include <stdio.h>
#include <libavutil/log.h>//日志文件处理
#include <libavformat/avformat.h>
#include <libavcodec/avcodec.h>
int main(int argc,char **argv)
{
	/*
		函数功能:抽取音频流数据
	*/
	//1.设置日志信息等级
	av_log_set_level(AV_LOG_INFO);
	//请求输入参数:./app <源文件> <目标文件>
	if(argc!=3)
	{
		av_log(NULL,AV_LOG_ERROR,"运行格式:./app <源文件> <目标文件>\n");
		return 0;
	}
	const char *src=argv[1];
	const char *dest=argv[2];
	//2.打开文件
	AVFormatContext *pfmt_ctx=NULL;//上下文指针
	int ret;
	ret=avformat_open_input(&pfmt_ctx,src,NULL, NULL);
	if(ret!=0)
	{
		av_log(NULL,AV_LOG_ERROR,"打开媒体文件失败,err=%d,%s\n",ret,av_err2str(ret));
		return 0;
	}
	//读取流数据包,获取流信息
	avformat_find_stream_info(pfmt_ctx, NULL);
	//输出流信息
	av_dump_format(pfmt_ctx,0,src,0);
	/*
		3.查找音频流数据
		ic --上下文指针
		type --媒体文件类型        AVMEDIA_TYPE_VIDEO(视频) AVMEDIA_TYPE_AUDIO(音频)
		wanted_stream_nb --流编号,-1表示自动选择
		related_stream --相关流,一般填-1
		decoder_ret --流解码器,不清楚则填NULL
		flags --暂未定义,填0即可
		返回值:成功返回一个非负整数,表示对应流编号
				失败返回负数
	*/
	int index=-1;
	index=av_find_best_stream(pfmt_ctx, AVMEDIA_TYPE_AUDIO, -1, -1,NULL,0);
	if(index<0)
	{
		av_log(pfmt_ctx,AV_LOG_ERROR,"查找音频流数据失败err=%d,%s\n",index,av_err2str(index));
		goto _fil;
	}
	av_log(pfmt_ctx,AV_LOG_INFO,"index=%d\n",index);
	/*4.创建输出流上下文指针*/
	AVFormatContext *ofmatctx=avformat_alloc_context();
	if(ofmatctx==NULL)
	{
		av_log(NULL,AV_LOG_ERROR,"创建输出流上下文件指针失败\n");
		goto _fil;
	}
	/*
		5.根据类型注册输出格式
		short_name --格式短参名,不清楚则填NULL
		filename --输出格式的目标名字
		mime_type --MIME类型,不清楚则填NULL
		该函数可以根据short_name、filename、mime_type的任意一个实现格式注册,成功返回AVOutputFormat
		失败返回NULL
	*/
	AVOutputFormat *ofmt=av_guess_format(NULL,dest,NULL);
	if(ofmt==NULL)
	{
		av_log(NULL,AV_LOG_ERROR,"注册输出格式失败\n");
		goto _fil2;
	}
	//6.将输出流信息写入到输出流上下文指针
	ofmatctx->oformat=ofmt;
	//7.创建一个新的流数据
	AVStream *ostream=avformat_new_stream(ofmatctx, NULL);
	if(ostream==NULL)
	{
		av_log(ofmatctx,AV_LOG_ERROR,"创建数据流失败\n");
		goto _fil2;
	}
	//8.将输入媒体文件中的音频流数据拷贝到输出媒体文件中
	AVStream *istream=pfmt_ctx->streams[index];//输入流数据
	avcodec_parameters_copy(ostream->codecpar, istream->codecpar);
	ostream->codecpar->codec_tag=0;//填0,表示编解码器有系统选择
	//将输出媒体文件打开,便于后续写数据
	ret=avio_open(&ofmatctx->pb, dest, AVIO_FLAG_WRITE);
	if(ret<0)
	{
		av_log(ofmatctx,AV_LOG_ERROR,"输出媒体文件打开失败err=%s\n",av_err2str(ret));
		goto _fil2;
	}
	//9.写多媒体文件头到目标文件
	ret=avformat_write_header(ofmatctx,NULL);
	if(ret<0)
	{
		av_log(ofmatctx,AV_LOG_ERROR,"写入多媒体头数据失败,ret=%s\n",av_err2str(ret));
	}
	//循环写入音频流数据
	AVPacket pkt;
	while(av_read_frame(pfmt_ctx, &pkt)==0)//从源文件中读取流数据
	{
		if(pkt.stream_index==index)//判断读取的流数据是否为需要的音频流
		{
			/*
				PTS:(Presentation Time Stamp)显示时间戳         PTS主要用于度量解码后的视频帧什么时候被显示出来。
				DTS:(Decode Time Stamp)解码时间戳 DTS主要是标识读入内存中的数据流在什么时候开始送入解码器中进行解码。
				
				音频流数据,没有视频,所以PTS和DTS一致
				
				av_rescale_q_rnd 函数:实现时间戳pts从输入流基准时间时间戳bq 转换 为输出流基准时间时间戳cq
				av_rescale_q_rnd(int64_t a, AVRational bq, AVRational cq,enum AVRounding rnd)
				计算方式:a*bq/cq 
							rnd  --表示计算处理方式,AV_ROUND_PASS_MINMAX表示限制最大最小值;AV_ROUND_NEAR_INF表示四舍五入处理方式
			*/
			pkt.pts=av_rescale_q_rnd(pkt.pts,istream->time_base,ostream->time_base, AV_ROUND_PASS_MINMAX|AV_ROUND_NEAR_INF);
			pkt.dts=pkt.pts;
			
			//计算音频时长
			pkt.duration=av_rescale_q(pkt.duration,istream->time_base,ostream->time_base);
			pkt.stream_index=0;//流下标
			pkt.pos=-1;//相对位置
			//根据dts递增顺序正确交织写入数据到到媒体文件
			av_interleaved_write_frame(ofmatctx,&pkt);
			av_packet_unref(&pkt);//释放pkt包
		}
	}
	//写入多媒体文件尾数据
	av_write_trailer(ofmatctx);
	
_fil2:
	if(!ofmatctx)
	{
		avformat_free_context(ofmatctx);//释放流指针
	}
_fil:
	if(!pfmt_ctx)
	{
		avformat_close_input(&pfmt_ctx);//关闭媒体文件
	}
	
}

4.程序编译Makefile

obj=getaudio.o 
CC=gcc

#CFLAGS=-I/home/wbyq/src_pack/ffmpeg-5.1.4/_install/include 
#CFLAGS+=-L/home/wbyq/src_pack/ffmpeg-5.1.4/_install/lib 
#CFLAGS+=-lavutil

CFLAGS=`pkg-config --libs libavformat libavutil libavcodec --cflags`

app:$(obj)
	$(CC) $^ -o $@ $(CFLAGS)

5.相关函数介绍

5.1日志信息输出

  ffmpeg中提供了日志打印函av_log,在输出调试信息时,可以先通过设置日志等级来决定输出的调试信息。

/*
leve可填写的参数:AV_LOG_DEBUG、AV_LOG_INFO、AV_LOG_WARNING、AV_LOG_ERROR等
*/
void av_log_set_level(int level);
/*
打印日志信息
形参:avcl --上下文关联指针,不用可直接填NULL
     level --输出类型:AV_LOG_DEBUG、AV_LOG_INFO、AV_LOG_WARNING、AV_LOG_ERROR等
     后需参数和printf一致
*/
void av_log(void* avcl, int level, const char *fmt, ...);

5.2 打开媒体文件

/*
形参:ps --打开成功返回一个AVFormatContext 上下文指针
      filename  --要打开的文件名
      fmt  --格式,填NULL可有系统根据文件名自行判断
      options  --可选参数,一般填NULL
返回值:成功返回0,失败返回<0
*/
int avformat_open_input(AVFormatContext **ps, const char *filename,
                        const AVInputFormat *fmt, AVDictionary **options)

5.3 获取流信息

/*
形参:ic --上下文指针
     options  --可选参数,一般填NULL
返回值:成功>=0,失败返回<0
*/
int avformat_find_stream_info(AVFormatContext *ic, AVDictionary **options)

5.4 输出流信息

/*
形参:ic --上下文指针
     index --流下标,一般填0
     url  --媒体文件名
     is_output --0表示输入媒体文件,1表示输出媒体文件
*/
void av_dump_format(AVFormatContext *ic, int index,
                    const char *url, int is_output)

5.6 查找音视频流数据

/*
形参:
	ic --上下文指针
		type --媒体文件类型        AVMEDIA_TYPE_VIDEO(视频) AVMEDIA_TYPE_AUDIO(音频)
		wanted_stream_nb --流编号,-1表示自动选择
		related_stream --相关流,一般填-1
		decoder_ret --流解码器,不清楚则填NULL
		flags --暂未定义,填0即可
返回值:成功返回一个非负整数,表示对应流编号
	失败返回负数
*/
int av_find_best_stream(AVFormatContext *ic, enum AVMediaType type,
                        int wanted_stream_nb, int related_stream,
                        const AVCodec **decoder_ret, int flags)
  • 22
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 1
    评论
### 回答1: 使用FFmpeg可以将RTSP中的音频保存为MP4文件。下面是一个示例命令: ffmpeg -i rtsp://input_stream_url -c:a copy output.mp4 在这个命令中,"-i rtsp://input_stream_url"指定需要保存的RTSP的URL。你可以替换成你要保存的具体RTSP的URL。 "-c:a copy"参数用于复制音频而不进行任何编码。这可以确保音频的原始质量得以保留。 "output.mp4"是保存的MP4文件的名称。你可以根据需要更改名称和路径。 执行上述命令后,FFmpeg会开始从RTSP提取音频并将其保存为MP4文件。进度和其他信息会显示在命令行界面中。完成后,你将在当前工作目录中找到保存的MP4文件。 ### 回答2: 使用FFmpeg可以实现将RTSP音频保存为MP4格式的操作。 首先,我们需要获取RTSP音频数据。通过FFmpeg命令行输入以下指令即可实现: ffmpeg -i rtsp://输入RTSP地址 -vn -acodec copy 音频文件的保存路径 在上述命令中,-i参数用于指定输入的RTSP地址,-vn参数表示不保存视频帧,-acodec copy参数表示直接复制音频编码格式,不进行重新编码。最后,我们需要指定音频文件的保存路径。 例如,我们将RTSP音频保存为名为audio.mp4的MP4文件,保存在当前目录下,可以使用以下命令: ffmpeg -i rtsp://输入RTSP地址 -vn -acodec copy audio.mp4 执行命令后,FFmpeg会首先连接到输入的RTSP地址,提取其中的音频数据,并将其保存为MP4格式的文件audio.mp4。 需要注意的是,每个RTSP的具体格式和音频编码可能不同,因此在实际操作中需要根据输入的RTSP的具体情况进行相应的调整。可以通过FFmpeg的各种参数进行进一步的配置,例如指定音频编码格式、音频码率等。 总之,通过FFmpeg的命令行工具,我们可以轻松实现将RTSP音频保存为MP4格式的操作。具体的实现方式和参数配置可以根据实际需求进行调整。 ### 回答3: 使用FFmpeg可以通过RTSP协议从网络摄像头或者媒体服务器接收音频,并将其保存为MP4格式。 要保存RTSP音频为MP4文件,可以使用以下命令行: ``` ffmpeg -i rtsp://输入URL -vn -c:a copy 输出文件名.mp4 ``` 其中`输入URL`是音频RTSP的地址,`输出文件名`是保存的MP4文件名。 解析: - `-i rtsp://输入URL`:指定输入的RTSP音频的URL。 - `-vn`:禁用视频输出,只保留音频。 - `-c:a copy`:使用原始音频编码方式进行复制,不进行重新编码。 - `输出文件名.mp4`:指定保存的MP4文件名及扩展名。 使用这个命令行,FFmpeg将从指定的RTSP音频接收音频数据,并将其保存为MP4文件。 需要注意的是,FFmpeg在处理RTSP时可能会遇到连接问题或者网络延迟等,可能需要根据实际情况进行调整和优化。 另外,如果需要同时保存音频和视频,可以删除`-vn`参数,这样即可保存完整的音视频
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

IT_阿水

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值