qq_40959271 2023-09-17 19:06 采纳率: 0%
浏览 19

ffmpeg麦克风如何编码推流

ffmpeg捕获麦克风数据解码后得到的frame的nb_sample为22050,但是编码器编码要求传入的frame的nb_sample只能是1024,所以就算传入编码也没有声音。我拉流视频得到的frame的nb_sampl为1024可以直接编码推流,但是麦克风一直不行,是哪里出错了,应该如何解决呀?
代码放这里了,有兴趣的帮忙看看,麦克风编码推流哪里出了问题,解决了可以私我有偿。
https://download.csdn.net/download/qq_40959271/88352930
主线程填充路径和创建三个子线程,子线程分别进行解封装 视频编解码 音频编解码 ,比较乱,主要看主线程和三个子线程就行。

  • 写回答

2条回答 默认 最新

  • 专家-赤兔[在线] 全栈领域优质创作者 2023-09-17 20:01
    关注

    引用 皆我百晓生 小程序回复内容作答:
    在使用FFmpeg进行麦克风编码推流时遇到的问题可能是由于不匹配的采样率导致的。解决这个问题的方法是对麦克风捕获的音频数据进行重采样,以确保与编码器要求的采样率一致。

    以下是一个示例代码,展示如何使用FFmpeg进行麦克风编码推流,且对捕获的音频数据进行重采样:

    #include <iostream>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    #ifdef __cplusplus
    extern "C" {
    #endif
    #include <libavutil/avutil.h>
    #include <libavdevice/avdevice.h>
    #include <libavformat/avformat.h>
    #include <libavcodec/avcodec.h>
    #ifdef __cplusplus
    }
    #endif
    
    int main(int argc, char* argv[]) {
        AVFormatContext* format_ctx = NULL;
        AVCodecContext* codec_ctx = NULL;
        AVCodec* codec = NULL;
        AVFrame* frame = NULL;
        AVPacket* packet = NULL;
    
        const char* input_device = "audio=Microphone";
        const char* output_url = "rtmp://your_streaming_server/live/stream_name";
    
        av_register_all();
        avdevice_register_all();
        avformat_network_init();
    
        // 打开输入设备
        AVInputFormat* input_fmt = av_find_input_format("dshow");
        if (avformat_open_input(&format_ctx, input_device, input_fmt, NULL) != 0) {
            std::cout << "Failed to open input device." << std::endl;
            return -1;
        }
    
        // 查找音频流
        int audio_stream_index = -1;
        avformat_find_stream_info(format_ctx, NULL);
        for (int i = 0; i < format_ctx->nb_streams; i++) {
            if (format_ctx->streams[i]->codecpar->codec_type == AVMEDIA_TYPE_AUDIO) {
                audio_stream_index = i;
                break;
            }
        }
    
        if (audio_stream_index == -1) {
            std::cout << "Failed to find audio stream." << std::endl;
            avformat_close_input(&format_ctx);
            return -1;
        }
    
        // 打开音频解码器
        codec = avcodec_find_decoder(format_ctx->streams[audio_stream_index]->codecpar->codec_id);
        if (codec == NULL) {
            std::cout << "Failed to find audio decoder." << std::endl;
            avformat_close_input(&format_ctx);
            return -1;
        }
    
        codec_ctx = avcodec_alloc_context3(codec);
        avcodec_parameters_to_context(codec_ctx, format_ctx->streams[audio_stream_index]->codecpar);
        avcodec_open2(codec_ctx, codec, NULL);
    
        // 初始化frame和packet
        frame = av_frame_alloc();
        packet = av_packet_alloc();
    
        // 打开输出流
        AVOutputFormat* output_fmt = av_guess_format(NULL, output_url, NULL);
        AVFormatContext* output_ctx = NULL;
        avformat_alloc_output_context2(&output_ctx, output_fmt, NULL, output_url);
        if (output_ctx == NULL) {
            std::cout << "Failed to allocate output context." << std::endl;
            avcodec_free_context(&codec_ctx);
            avformat_close_input(&format_ctx);
            return -1;
        }
    
        AVStream* output_stream = avformat_new_stream(output_ctx, codec);
        if (output_stream == NULL) {
            std::cout << "Failed to create output stream." << std::endl;
            avcodec_free_context(&codec_ctx);
            avformat_close_input(&format_ctx);
            avformat_free_context(output_ctx);
            return -1;
        }
    
        // 配置编码器参数和重采样参数
        output_stream->codecpar->codec_id = codec_ctx->codec_id;
        output_stream->codecpar->codec_type = codec_ctx->codec_type;
        output_stream->codecpar->sample_rate = 1024;
        output_stream->codecpar->channel_layout = AV_CH_LAYOUT_MONO;
    
        // 打开输出流并写入头信息
        output_ctx->streams[0]->codecpar = output_stream->codecpar;
        if (avio_open(&output_ctx->pb, output_url, AVIO_FLAG_WRITE) < 0) {
            std::cout << "Failed to open output URL." << std::endl;
            avcodec_free_context(&codec_ctx);
            avformat_close_input(&format_ctx);
            avformat_free_context(output_ctx);
            return -1;
        }
        avformat_write_header(output_ctx, NULL);
    
        // 读取音频数据并编码推流
        AVPacket* encode_packet = av_packet_alloc();
        while (av_read_frame(format_ctx, packet) >= 0) {
            if (packet->stream_index != audio_stream_index) {
                av_packet_unref(packet);
                continue;
            }
    
            // 解码音频帧
            avcodec_send_packet(codec_ctx, packet);
            avcodec_receive_frame(codec_ctx, frame);
            av_packet_unref(packet);
    
            // 重采样音频数据
            SwrContext* swr_ctx = swr_alloc_set_opts(NULL,
                                                     codec_ctx->channel_layout,
                                                     AV_SAMPLE_FMT_S16,
                                                     codec_ctx->sample_rate,
                                                     frame->channel_layout,
                                                     static_cast<AVSampleFormat>(frame->format),
                                                     frame->sample_rate,
                                                     0,
                                                     NULL);
            swr_init(swr_ctx);
    
            int num_samples = av_rescale_rnd(swr_get_delay(swr_ctx, frame->sample_rate) + frame->nb_samples, codec_ctx->sample_rate, frame->sample_rate, AV_ROUND_UP);
            int buffer_size = av_samples_get_buffer_size(NULL, codec_ctx->channels, num_samples, AV_SAMPLE_FMT_S16, 1);
            uint8_t* resampled_data = (uint8_t*)av_malloc(buffer_size);
            swr_convert(swr_ctx, &resampled_data, num_samples, (const uint8_t**)frame->data, frame->nb_samples);
    
            // 更新重采样后的数据参数
            frame->pts = av_frame_get_best_effort_timestamp(frame);
            frame->format = AV_SAMPLE_FMT_S16;
            frame->sample_rate = codec_ctx->sample_rate;
            frame->nb_samples = num_samples;
            frame->channel_layout = codec_ctx->channel_layout;
            frame->channels = codec_ctx->channels;
            frame->linesize[0] = buffer_size;
    
            // 编码音频帧并推流
            avcodec_send_frame(codec_ctx, frame);
            while (avcodec_receive_packet(codec_ctx, encode_packet) == 0) {
                encode_packet->stream_index = output_stream->index;
                av_write_frame(output_ctx, encode_packet);
                av_packet_unref(encode_packet);
            }
    
            swr_free(&swr_ctx);
            av_free(resampled_data);
        }
    
        // 写入文件尾部信息并关闭输出流和输入设备
        av_write_trailer(output_ctx);
        avcodec_free_context(&codec_ctx);
        av_frame_free(&frame);
        av_packet_free(&packet);
        av_packet_free(&encode_packet);
        avformat_close_input(&format_ctx);
        avformat_free_context(output_ctx);
    
        return 0;
    }
    

    在上述代码中,我们通过swr_convert函数对捕获的音频数据进行重采样,将其采样率转换为与编码器要求相匹配的1024。然后,我们将重采样后的音频数据编码为压缩帧,并使用av_write_frame函数将其推流到输出URL。请注意,你需要将input_device更改为与你的麦克风设备匹配的设备名称,并将output_url更改为你要推流到的URL。

    希望这可以帮助到你解决问题!

    评论

报告相同问题?

问题事件

  • 修改了问题 9月18日
  • 修改了问题 9月18日
  • 创建了问题 9月17日

悬赏问题

  • ¥20 IDEA ssm项目 跳转页面报错500
  • ¥20 系统直接进入应急模式了,请教一下,人要裂开了
  • ¥15 页面初次加载时,JS调用对象可以调用成功,但是一旦跳转到另一个页面,再跳转回来后这个对象就显示undefind了,调用也调用不了了,什么原因?
  • ¥15 来个厉害的程序开发的,安排点活给你做
  • ¥15 rexroth indramotion MTX micro系统轴耦合编程
  • ¥100 springboot2.7.x 整合 sharding 的问题
  • ¥15 如何通过命令行操作统信360安全浏览器?
  • ¥15 upload-labs-master第三关
  • ¥15 关于LT3758反激式负压电源,功率三极管烧毁的问题
  • ¥20 aruba ap305 CAP转IAP