FFMPEG-音频PCM实时采集保存
//-------------------------------------------------------------------------------------------------
参考链接1、https://blog.csdn.net/leixiaohua1020/article/details/39702113
参考链接2、https://blog.csdn.net/li_wen01/article/details/67631687
//-------------------------------------------------------------------------------------------------
音视频同步录制相关文章
//-------------------------------------------------------------------------------------------------
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
https://blog.csdn.net/Tang_Chuanlin/article/details/86775881
指令录制实时音频ffmpeg -f alsa -ar 44100 -i hw:0,0 audio.wav
ffmpeg -f alsa -ar 44100 -i default ffmpeg_record_audio.wav
https://blog.csdn.net/dingjianfeng2014/article/details/57424473
指令分离音视频: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源码下载链接
https://download.csdn.net/download/quange_style/11172132
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
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.附件
版本二:源码附件