8-采用ffmpeg,录制pcm原数据

  1. 小白学习音视频(八)采用ffmpeg,录制pcm原数据

小白学习音视频(八)采用ffmpeg,录制pcm原数据

image

关注微信号:cpp手艺人,获取更多文章

先上个流程图

image

贴上主要的代码:

int _tmain(int argc, char* argv[])
{
    av_register_all();
    avdevice_register_all();

    // 这里获取你的音频设备名称
    show_dshow_device();

    // 资源容器类
    ResourceContainer containter;

    // 释放资源函数
    std::function<void(void)> release_resource = [&containter] () {
            if (nullptr != containter.file_handle) { 
                fclose(containter.file_handle); 
            }

            if (nullptr != containter.frame) {
                av_free(containter.frame);
                containter.frame = nullptr;
            }

            if (nullptr != containter.codec_context) {
                avcodec_close(containter.codec_context);
            }

            avformat_close_input(&(containter.format_context));
            avformat_free_context(containter.format_context);
    };

    // 分配上下文
    AVFormatContext    *format_context = avformat_alloc_context();
    containter.format_context = format_context;

    // 需要录制的设备名称,每台机器的可能不一样,需要替换成你自己的设备名称
    string device_name = dup_wchar_to_utf8(
                        L"audio=立体声混音 (2- Realtek High Definition Audio)");

    int ret_code = 0;
    // 获取输入格式信息
    AVInputFormat *input_format = av_find_input_format("dshow");
    // 打开设备
    if(0 != (ret_code = avformat_open_input(&format_context, 
                                 device_name.c_str(), 
                                 input_format, 
                                 nullptr))) {
        cout << av_error(ret_code) << endl;
        goto Error;
    }

    int audioindex = -1;

    // 遍历寻找是否有音频流信息
    for(int i = 0; i < format_context->nb_streams; i++) {
        if(format_context->streams[i]->codec->codec_type ==
                                                        AVMEDIA_TYPE_AUDIO) {
            audioindex = i;
            break;
        }
    }

    if(-1 == audioindex) {
        cout << "Didn't find a audio stream." << endl;
        goto Error;
    }

    // 编码上下文
    AVCodecContext *codec_context = format_context->streams[audioindex]->codec;
    containter.codec_context      = codec_context;
    // 寻找解码器
    AVCodec *codec = avcodec_find_decoder(codec_context->codec_id);

    if(nullptr == codec) {
        cout << "audio codec not found." << endl;
        goto Error;
    }

    if(0 != (ret_code = avcodec_open2(codec_context, codec, nullptr))) {
        cout << av_error(ret_code) << endl;
        goto Error;
    }

    AVFrame *frame        = av_frame_alloc();
    containter.frame    = frame;

    AVPacket *packet    = (AVPacket *)av_malloc(sizeof(AVPacket));
    FILE *fp_pcm        = fopen("output.pcm", "wb");
    containter.file_handle = fp_pcm;

    float total_time    = 0;
    int got_frame        = 0;

    for(int i = 0; ; i++) {
        //就采集30秒
        if (total_time > 30)  { break; }

        // 读取音频信息失败,直接退出
        if(av_read_frame(format_context, packet) < 0) { break; }

        if(packet->stream_index == audioindex) {
            // 对音频进行解码
            if (0 != (ret_code = avcodec_decode_audio4(codec_context, 
                                        frame, 
                                        &got_frame, 
                                        packet))) {

                cout << av_error(ret_code) << endl;
                goto Error;
            }

            if (0 == got_frame) { continue; }

            int pcm_size = 
                    av_samples_get_buffer_size(nullptr, 
                                               codec_context->channels, 
                                               frame->nb_samples, 
                                               codec_context->sample_fmt, 
                                               1);
            uint8_t *pcm_buffer = frame->data[0];

            float used_time = 
                    frame->nb_samples * 1.0 / codec_context->sample_rate;

            total_time += used_time;

            // 保存到文件中
            fwrite(pcm_buffer, 1, pcm_size, fp_pcm); 
        }
        av_free_packet(packet);
    }

    release_resource();
    return 0;

Error:
    release_resource();
    return -1;
}

录制的好的pcm文件,使用ffplay播放就可以了。
命令行如下:
播放44.1kHz 双声道 16bit的xxx.pcm的PCM文件为例
ffplay.exe -ar 44100 -channels 2 -f s16le -i xxx.pcm

github地址:https://github.com/MingYueRuYa/FFmpeg-RTMP 在ffmpeg_demo解决方案下面


转载请注明来源,欢迎对文章中的引用来源进行考证,欢迎指出任何有错误或不够清晰的表达。可以在下面评论区评论,也可以邮件至 635672377@qq.com

文章标题:8-采用ffmpeg,录制pcm原数据

文章字数:555

本文作者:刘世雄

发布时间:2020-08-13, 11:46:44

最后更新:2020-08-13, 03:46:47

原始链接:http://lsxcpp.com/2020/08/13/8-%E9%87%87%E7%94%A8ffmpeg,%E5%BD%95%E5%88%B6pcm%E5%8E%9F%E6%95%B0%E6%8D%AE/

版权声明: "署名-非商用-相同方式共享 4.0" 转载请保留原文链接及作者。

目录