FFMPEG-音频PCM实时采集保存

FFMPEG-音频PCM实时采集保存

//-------------------------------------------------------------------------------------------------
参考链接1、
参考链接2、

//-------------------------------------------------------------------------------------------------
音视频同步录制相关文章
//-------------------------------------------------------------------------------------------------
1、 ffmpeg-摄像头采集保存
2、 ffmpeg-摄像头采集编码封装
3、 ffmpeg-音频正弦产生并编码封装
4、 ffmpeg-音频实时采集保存
5、 ffmpeg-音频实时采集编码封装
6、 ffmpeg-音视频实时采集编码封装
//---------------------------------------------------------------

系统环境:
系统版本:lubuntu 16.04
Ffmpge版本:ffmpeg version N-93527-g1125277
摄像头:1.3M HD WebCan
虚拟机:Oracle VM VirtualBox 5.2.22

指令查看设备 ffmpeg -devices
指令播放实时音频 ffplay -f alsa -showmode 1 -ac 2 -i default -ar 44100

指令录制实时音频ffmpeg -f alsa -ar 44100 -i hw:0,0 audio.wav
ffmpeg -f alsa -ar 44100 -i default ffmpeg_record_audio.wav

指令分离音视频:ffmpeg -i test.mp4 -vn -y -acodec copy test.aac
ffmpeg -i test.mp4 -vn -y -avcodec copy test.h264

本章文档基于 《ffmpeg-摄像头采集保存》采集摄像头一帧数据并将其转化为pcm,保存下来

1.简介

FFmpeg中有一个和多媒体设备交互的类库:Libavdevice。使用这个库可以读取电脑(或者其他设备上)的多媒体设备的数据,或者输出数据到指定的多媒体设备上

2.源码

最简单的基于Libavdevice的摄像头数据读取一帧帧pcm数据,经过音频重采样,保存成output.pcm文件,也可以修改成将编码音频AAC转换为音频源数据pcm(屏蔽的地方打开即可)

1.	#include <stdio.h>  
2.	   
3.	  
4.	//Linux...  
5.	#ifdef __cplusplus  
6.	extern "C"  
7.	{  
8.	#endif  
9.	#include <libavcodec/avcodec.h>  
10.	#include <libavformat/avformat.h>  
11.	#include <libswscale/swscale.h>  
12.	#include <libavdevice/avdevice.h>  
13.	#include <SDL/SDL.h>  
14.	#ifdef __cplusplus  
15.	};  
16.	#endif  
17.	   
18.	//Output PCM   
19.	#define OUTPUT_PCM 1  
20.	int thread_exit=0;  
21.	 #define MAX_AUDIO_FRAME_SIZE 192000  
22.	  
23.	   
24.	int main(int argc, char* argv[])  
25.	{  
26.	   
27.	    AVFormatContext *pFormatCtx;  
28.	    int             i, videoindex;  
29.	    AVCodecContext  *pCodecCtx;  
30.	    AVCodec         *pCodec;  
31.	      
32.	    av_register_all();  
33.	    avformat_network_init();  
34.	    pFormatCtx = avformat_alloc_context();  
35.	      
36.	    //Register Device  
37.	    avdevice_register_all();  
38.	      
39.	  
40.	    //Linux  
41.	    AVInputFormat *ifmt=av_find_input_format("alsa");  
42.	    if(avformat_open_input(&pFormatCtx,"default",ifmt,NULL)!=0){  
43.	        printf("Couldn't open input stream.default\n");  
44.	        return -1;  
45.	    }  
46.	    /*if (avformat_open_input(&pFormatCtx, filepath, NULL, NULL) != 0)  
47.	    {  
48.	        printf("Couldn't open an input stream.\n");  
49.	        return -1;  
50.	    }  */ 
51.	
52.	   
53.	   
54.	    if(avformat_find_stream_info(pFormatCtx,NULL)<0)  
55.	    {  
56.	        printf("Couldn't find stream information.\n");  
57.	        return -1;  
58.	    }  
59.	    videoindex=-1;  
60.	    for(i=0; i<pFormatCtx->nb_streams; i++)   
61.	        if(pFormatCtx->streams[i]->codec->codec_type==AVMEDIA_TYPE_AUDIO)  
62.	        {  
63.	            videoindex=i;  
64.	            break;  
65.	        }  
66.	    if(videoindex==-1)  
67.	    {  
68.	        printf("Couldn't find a video stream.\n");  
69.	        return -1;  
70.	    }  
71.	    pCodecCtx=pFormatCtx->streams[videoindex]->codec;  
72.	    pCodec=avcodec_find_decoder(pCodecCtx->codec_id);  
73.	    if(pCodec==NULL)  
74.	    {  
75.	        printf("Codec not found.\n");  
76.	        return -1;  
77.	    }  
78.	    if(avcodec_open2(pCodecCtx, pCodec,NULL)<0)  
79.	    {  
80.	        printf("Could not open codec.\n");  
81.	        return -1;  
82.	    }  
83.	               
84.	    int ret, got_audio;  
85.	   
86.	    AVPacket *packet=(AVPacket *)av_malloc(sizeof(AVPacket));  
87.	  
88.	    AVFrame* pAudioFrame=av_frame_alloc();  
89.	    if(NULL==pAudioFrame)  
90.	    {  
91.	        printf("could not alloc pAudioFrame\n");  
92.	        return -1;  
93.	    }  
94.	  
95.	//audio output paramter //resample   
96.	    uint64_t out_channel_layout = AV_CH_LAYOUT_MONO;  
97.	    int out_sample_fmt = AV_SAMPLE_FMT_S16;  
98.	    int out_nb_samples =1024; //pCodecCtx->frame_size;  
99.	    int out_sample_rate = 44100;  
100.	    int out_nb_channels = av_get_channel_layout_nb_channels(out_channel_layout);  
101.	    int out_buffer_size = av_samples_get_buffer_size(NULL, out_nb_channels, out_nb_samples, out_sample_fmt, 1);    
102.	    uint8_t *buffer=NULL;    
103.	    buffer = (uint8_t *)av_malloc(MAX_AUDIO_FRAME_SIZE);   
104.	    int64_t in_channel_layout = av_get_default_channel_layout(pCodecCtx->channels);    
105.	  
106.	    printf("audio sample_fmt=%d size=%d channel=%d in_channel_layout=%d sample_rate=%d\n",pCodecCtx->sample_fmt, pCodecCtx->frame_size,  
107.	        pCodecCtx->channels,in_channel_layout,pCodecCtx->sample_rate);  
108.	  
109.	    struct SwrContext   *audio_convert_ctx = NULL;    
110.	    audio_convert_ctx = swr_alloc();    
111.	    if (audio_convert_ctx == NULL)    
112.	    {    
113.	        printf("Could not allocate SwrContext\n");    
114.	        return -1;    
115.	    }    
116.	  
117.	#if 1  
118.	      /* set options */  
119.	        av_opt_set_int       (audio_convert_ctx, "in_channel_count",   pCodecCtx->channels,       0);  
120.	        av_opt_set_int       (audio_convert_ctx, "in_sample_rate",     pCodecCtx->sample_rate,    0);  
121.	        av_opt_set_sample_fmt(audio_convert_ctx, "in_sample_fmt",      pCodecCtx->sample_fmt, 0);  
122.	        av_opt_set_int       (audio_convert_ctx, "out_channel_count",  out_nb_channels,       0);  
123.	        av_opt_set_int       (audio_convert_ctx, "out_sample_rate",   out_sample_rate,    0);  
124.	        av_opt_set_sample_fmt(audio_convert_ctx, "out_sample_fmt",     out_sample_fmt,     0);  
125.	  
126.	        /* initialize the resampling context */  
127.	        if ((ret = swr_init(audio_convert_ctx)) < 0) {  
128.	            fprintf(stderr, "Failed to initialize the resampling context\n");  
129.	            exit(1);  
130.	        }  
131.	#else  
132.	  
133.	  
134.	    if((ret=swr_alloc_set_opts(audio_convert_ctx, out_channel_layout, out_sample_fmt,\  
135.	        out_sample_rate,in_channel_layout, \  
136.	        pCodecCtx->sample_fmt, pCodecCtx->sample_rate, 0, NULL))<0){  
137.	          printf("Could not swr_alloc_set_opts\n");    
138.	         return -1;    
139.	    }  
140.	  
141.	     if ((ret = swr_init(audio_convert_ctx)) < 0) {  
142.	            fprintf(stderr, "Failed to initialize the resampling context\n");  
143.	            exit(1);  
144.	        }  
145.	          
146.	#endif  
147.	  
148.	      
149.	    int frameCnt=200;  
150.	#if OUTPUT_PCM   
151.	    FILE *fp_pcm=fopen("output.pcm","wb+");    
152.	#endif   
153.	  
154.	    while(frameCnt--){  
155.	        if(av_read_frame(pFormatCtx, packet)>=0){  
156.	        if(packet->stream_index==videoindex){  
157.	            ret = avcodec_decode_audio4(pCodecCtx, pAudioFrame, &got_audio, packet);  
158.	            if(ret < 0){  
159.	                printf("Decode Error.\n");  
160.	                return -1;  
161.	            }  
162.	            if(got_audio){  
163.	  
164.	                //printf("nb_samples %d\n",pAudioFrame->nb_samples);  
165.	                  swr_convert(audio_convert_ctx, &buffer, MAX_AUDIO_FRAME_SIZE, (const uint8_t **)pAudioFrame->data, pAudioFrame->nb_samples);    
166.	                    
167.	#if OUTPUT_PCM    
168.	            fwrite(buffer,1,out_buffer_size,fp_pcm);    //Y     
169.	          
170.	#endif   
171.	            }  
172.	        }  
173.	        av_free_packet(packet);  
174.	                  
175.	        }  
176.	    }  
177.	  
178.	 #if OUTPUT_PCM  
179.	    fclose(fp_pcm);  
180.	#endif   
181.	    swr_free(&audio_convert_ctx);   
182.	    av_free(buffer);   
183.	    //av_free(out_buffer);  
184.	    av_free(pAudioFrame);  
185.	    avcodec_close(pCodecCtx);  
186.	    avformat_close_input(&pFormatCtx);  
187.	   
188.	    return 0;  
189.	}  

2.1源码下载链接

3.验证

3.1编译

1.	#!/bin/sh  
2.	export PKG_CONFIG_PATH=/home/quange/ffmpeg_build/lib/pkgconfig/:$PKG_CONFIG_PATH  
3.	gcc ffmpeg_get_pcm_frame.c -g -o ffmpeg_get_pcm_frame.out  -lSDLmain -lSDL  `pkg-config "libavcodec" --cflags --libs` `pkg-config "libavformat" --cflags --libs` `pkg-config "libavutil" --cflags --libs` `pkg-config "libswscale" --cflags --libs` `pkg-config "libavdevice" --cflags --libs`

3.2结果

使用软件audacity打开output.pcm
FFMPEG-音频PCM实时采集保存
FFMPEG-音频PCM实时采集保存

3.3存在的问题

1、在软件audacity打开output.pcm,会发现有杂音(48000->44100采样率,双声道转单声道),而不进行采样率转换(双声道转单声道),声音是完好的,无杂音。说明在不同采样率转换时,出现了问题。

2、参考resample_audio.c,采用另外一种方法来进行音频重采样。因为在不同采样率之间转换时(ps:48000->44100;),in_nb_sample:1024,out_nb_sample生成的大小会随机的,需要多次采样才会合成1024采样率大小空间。
1)初始化:

1.	int64_t src_ch_layout = AV_CH_LAYOUT_STEREO, dst_ch_layout = AV_CH_LAYOUT_STEREO;  
2.	int src_rate = 48000, dst_rate = 44100;  
3.	uint8_t **src_data = NULL, **dst_data = NULL;  
4.	int src_nb_channels = 0, dst_nb_channels = 0;  
5.	int src_linesize, dst_linesize;  
6.	int src_nb_samples = 1024, dst_nb_samples, max_dst_nb_samples;  
7.	enum AVSampleFormat src_sample_fmt = AV_SAMPLE_FMT_DBL, dst_sample_fmt = AV_SAMPLE_FMT_S16;  
8.	const char *dst_filename = NULL;  
9.	FILE *dst_file;  
10.	int dst_bufsize;  
11.	const char *fmt;  
12.	  
13.	 src_ch_layout= in_channel_layout;  
14.	 src_rate=pCodecCtx->sample_rate;  
15.	 src_sample_fmt= pCodecCtx->sample_fmt;  
16.	// dst_ch_layout=out_nb_channels;  
17.	// dst_rate=out_sample_rate;  
18.	// dst_sample_fmt=out_sample_fmt;  
19.	    /* set options */  
20.	  
21.	printf("dst_sample_fmt %d dst_ch_layout=%s src_sample_fmt=%d src_ch_layout=%s\n",  
22.	dst_sample_fmt,av_ts2str(dst_ch_layout),src_sample_fmt,av_ts2str(src_ch_layout));  
23.	  
24.	  
25.	   av_opt_set_int(audio_convert_ctx, "in_channel_layout",    src_ch_layout, 0);  
26.	   av_opt_set_int(audio_convert_ctx, "in_sample_rate",       src_rate, 0);  
27.	   av_opt_set_sample_fmt(audio_convert_ctx, "in_sample_fmt", src_sample_fmt, 0);  
28.	  
29.	   av_opt_set_int(audio_convert_ctx, "out_channel_layout",    dst_ch_layout, 0);  
30.	   av_opt_set_int(audio_convert_ctx, "out_sample_rate",       dst_rate, 0);  
31.	   av_opt_set_sample_fmt(audio_convert_ctx, "out_sample_fmt", dst_sample_fmt, 0);  
32.	  
33.	       /* initialize the resampling context */  
34.	   if ((ret = swr_init(audio_convert_ctx)) < 0) {  
35.	       fprintf(stderr, "Failed to initialize the resampling context\n");  
36.	  
37.	   }  
38.	  
39.	   /* allocate source and destination samples buffers */  
40.	  
41.	   src_nb_channels = av_get_channel_layout_nb_channels(src_ch_layout);  
42.	   ret = av_samples_alloc_array_and_samples(&src_data, &src_linesize, src_nb_channels,  
43.	                                            src_nb_samples, src_sample_fmt, 0);  
44.	   if (ret < 0) {  
45.	       fprintf(stderr, "Could not allocate source samples\n");  
46.	  
47.	   }  
48.	  
49.	   /* compute the number of converted samples: buffering is avoided 
50.	    * ensuring that the output buffer will contain at least all the 
51.	    * converted input samples */  
52.	   max_dst_nb_samples = dst_nb_samples =  
53.	       av_rescale_rnd(src_nb_samples, dst_rate, src_rate, AV_ROUND_UP);  
54.	  
55.	   /* buffer is going to be directly written to a rawaudio file, no alignment */  
56.	   dst_nb_channels = av_get_channel_layout_nb_channels(dst_ch_layout);  
57.	   ret = av_samples_alloc_array_and_samples(&dst_data, &dst_linesize, dst_nb_channels,  
58.	                                            dst_nb_samples, dst_sample_fmt, 0);  
59.	   if (ret < 0) {  
60.	       fprintf(stderr, "Could not allocate destination samples\n");  
61.	  
62.	   }  

2)重采样:

64.	/* compute destination number of samples */  
65.	      /*  dst_nb_samples = av_rescale_rnd(swr_get_delay(audio_convert_ctx, src_rate) + 
66.	                                        src_nb_samples, dst_rate, src_rate, AV_ROUND_UP); 
67.	 
68.	        printf("src_rate= %d  src_nb_samples=%d dst_rate=%d dst_nb_samples=%d\n", 
69.	            src_rate,src_nb_samples,dst_rate,dst_nb_samples); 
70.	 
71.	        if (dst_nb_samples > max_dst_nb_samples) { 
72.	            av_freep(&dst_data[0]); 
73.	            ret = av_samples_alloc(dst_data, &dst_linesize, dst_nb_channels, 
74.	                                   dst_nb_samples, dst_sample_fmt, 1); 
75.	            if (ret < 0) 
76.	                break; 
77.	            max_dst_nb_samples = dst_nb_samples; 
78.	        }*/  
79.	  //在48000->44100采样率是,第二个dst_nb_samples数据会异常
80.	  //上面注释部分,主要是动态分配适合大小的空间来存放重采样后的数据,目前用一个大的空间4*1014(16bit,立体音)来代替存放,以后再解决异常问题。 
81.	  
82.	        /* convert to destination format */  
83.	        ret = swr_convert(audio_convert_ctx, dst_data, dst_nb_samples, (const uint8_t **)pAudioFrame->data, pAudioFrame->nb_samples);  
84.	        if (ret < 0) {  
85.	            fprintf(stderr, "Error while converting\n");  
86.	  
87.	        }  
88.	        dst_bufsize = av_samples_get_buffer_size(&dst_linesize, dst_nb_channels,  
89.	                                                 ret, dst_sample_fmt, 1);  
90.	        if (dst_bufsize < 0) {  
91.	            fprintf(stderr, "Could not get sample buffer size\n");  
92.	  
93.	        }  
94.	        printf(" in:%d out:%d dst_bufsize=%d\n", src_nb_samples, ret,dst_bufsize);  
95.	#if OUTPUT_PCM  
96.				fwrite(dst_data[0],1,dst_bufsize,fp_pcm);    //Y   
97.			
98.	#endif 		

3)反注销:

	swr_free(&audio_convert_ctx);

4.附件

版本二:源码附件

5.参考资料

[1]

;