ffmpeg虽然是跨平台库,mac和windows还是有区别的,这里介绍下mac如何打开audo并采集。
1.查找解码器
_input_fmt = av_find_input_format("avfoundation");
2.打开设备
_fmt_ctx = avformat_alloc_context();
ret = avformat_open_input(&_fmt_ctx, device_name.c_str(), _input_fmt, NULL);
if (ret != 0) {
error = AE_FFMPEG_OPEN_INPUT_FAILED;
break;
}
这需要注意的是设备名字,在window我们可能输入的:audio = xxxxxx,mac不一样,mac这里的设备包含video和audio类似"0:1",输入的是屏幕index和audio index。直接输入设备名字打开是失败的,设备index和可以根据ffmpeg命令获得:
ffmpeg -f avfoundation -list_devices true -i ""
这里会列出所有avfoundation 设备,我电脑显示如下:
liuzhaomingdeMacBook-Pro:Recorder liuzhaoming$ ffmpeg -f avfoundation -list_devices true -i ""
ffmpeg version N-100493-gc720286 Copyright (c) 2000-2020 the FFmpeg developers
built with Apple clang version 11.0.3 (clang-1103.0.32.62)
configuration: --enable-libx264 --enable-gpl --enable-decoder=h264 --enable-encoder=libx264 --enable-shared --enable-static
libavutil 56. 62.100 / 56. 62.100
libavcodec 58.115.102 / 58.115.102
libavformat 58. 65.100 / 58. 65.100
libavdevice 58. 11.103 / 58. 11.103
libavfilter 7. 94.100 / 7. 94.100
libswscale 5. 8.100 / 5. 8.100
libswresample 3. 8.100 / 3. 8.100
libpostproc 55. 8.100 / 55. 8.100
[AVFoundation indev @ 0x7fd24440f580] AVFoundation video devices:
[AVFoundation indev @ 0x7fd24440f580] [0] FaceTime HD Camera
[AVFoundation indev @ 0x7fd24440f580] [1] Capture screen 0
[AVFoundation indev @ 0x7fd24440f580] AVFoundation audio devices:
[AVFoundation indev @ 0x7fd24440f580] [0] Soundflower (2ch)
[AVFoundation indev @ 0x7fd24440f580] [1] Built-in Microphone
[AVFoundation indev @ 0x7fd24440f580] [2] Soundflower (64ch)
我们可以看到 有两个video设备 3个audio设备,每个设备都有序号,ffmpeg打开就需要这个序号。
如果我们只想打开audo设备,输入如下:
ret = avformat_open_input(&_fmt_ctx, ":1", _input_fmt, NULL);
如果只想打开video,输入如下:
ret = avformat_open_input(&_fmt_ctx, "0:", _input_fmt, NULL);
如果想同时打开,输入如下:
ret = avformat_open_input(&_fmt_ctx, "0:1", _input_fmt, NULL);
这样可以同时打开视频和audio设备。
然后可以通过codetype来区分具体是什么流
codec->codec_type == AVMEDIA_TYPE_AUDIO//音频
codec->codec_type == AVMEDIA_TYPE_VIDEO//视频
3.采集
创建一个线程循环读取进行编码
AVPacket *packet = av_packet_alloc();
AVFrame *frame = av_frame_alloc();
while (_running == true) {
av_init_packet(packet);
ret = av_read_frame(_fmt_ctx, packet);
if (ret < 0) {
av_packet_unref(packet);
continue;
}
if (packet->stream_index == _stream_index) {
ret = decode(frame, packet);
if (ret != AE_NO) {
if (_on_error) _on_error(AE_FFMPEG_DECODE_FRAME_FAILED, _cb_extra_index);
al_fatal("decode pcm packet failed:%d", ret);
av_packet_unref(packet);
continue;
}
}
av_packet_unref(packet);
}
//flush packet left in decoder
decode(frame, NULL);
av_packet_free(&packet);
av_frame_free(&frame);