首页 > 解决方案 > 我可以使用 libav 流式传输实时音频吗?

问题描述

我正在尝试使用 libav/ffmpeg 在 C 中编写简单的互联网广播流媒体应用程序,但是我唯一能做的就是打开 url 并下载数据包。当我将它发送到 alsa 声卡时,我会得到一秒钟的噪音和静电,然后是 alsa buffer xrun。

我试图将数据包解码成帧,它们看起来还不错。

我看过https://gavv.github.io/articles/decode-play/https://www.ffmpeg.org/doxygen/3.2/group__lavf__encoding.html#detailshttps://github.com/leandromoreira/ ffmpeg-libav-tutorial和https://ffmpeg.org/doxygen/trunk/index.html上的许多页面,但我找不到任何有助于或看起来与我的问题相似的东西。

感谢所有评论。

这是我的代码:

//gcc -o radio radio.c -lavformat -lavcodec -lswresample -lavutil -lavdevice -lm

#include <unistd.h>
#include <stdio.h>
#include <libavutil/avassert.h>
#include <libavutil/channel_layout.h>
#include <libavutil/opt.h>
#include <libavutil/mathematics.h>
#include <libavutil/timestamp.h>
#include <libavformat/avformat.h>
#include <libswscale/swscale.h>
#include <libswresample/swresample.h>
#include <libavcodec/avcodec.h>
#include <libavformat/avformat.h>
#include <libavdevice/avdevice.h>

void dumpParameters(AVCodecParameters *codecParam){
    printf("Codec type: %d\nCodec id: %d\nSample format: %d\nChannel layout: %ld\nChannels: %d\nSample rate: %d\nFrame size: %d\n",
    codecParam->codec_type,
    codecParam->codec_id,
    codecParam->format,
    codecParam->channel_layout,
    codecParam->channels,
    codecParam->sample_rate,
    codecParam->frame_size);
}

int main(){
    const char* nowy_swiat = "http://stream.rcs.revma.com/ypqt40u0x1zuv";
    int ret = -1;
    int inputStream = 0;

    AVFormatContext *iFormatContext = avformat_alloc_context();
    
    if(avformat_open_input(&iFormatContext,nowy_swiat,NULL,NULL)<0){
        printf("av_open_input\n");
        exit(1);
    }
    if(avformat_find_stream_info(iFormatContext,NULL)<0){
        printf("cannot find stream info\n");
        exit(1);
    }

    AVCodecParameters *iCodecParameters = avcodec_parameters_alloc();
    while(iFormatContext->streams[inputStream]->codecpar->codec_type!=AVMEDIA_TYPE_AUDIO)inputStream++;
    iCodecParameters = iFormatContext->streams[inputStream]->codecpar;

    AVCodec *iCodec = avcodec_find_decoder(iCodecParameters->codec_id);
    if(iCodec==NULL){
        printf("cannot find codec\n");
        exit(0);
    }

    AVCodecContext *iCodecContext = avcodec_alloc_context3(iCodec);
    ret = avcodec_parameters_to_context(iCodecContext,iCodecParameters);
    if(ret<0){
        printf("Can't copy parameters to context\n");
        exit(0);
    }

    if(avcodec_open2(iCodecContext,iCodec,NULL)<0){
        printf("cannot initialize\n");
        exit(0);
    }  

    AVPacket *packet = av_packet_alloc();

    AVFrame *frame = av_frame_alloc();

    //--------------------------------------------------------------------------------

    avdevice_register_all();

    AVOutputFormat *output = av_guess_format("alsa",NULL,NULL);
    output->flags = AVFMT_ALLOW_FLUSH;

    AVFormatContext *outputFormatContext;
    avformat_alloc_output_context2(&outputFormatContext,output,NULL,NULL);
    //outputFormatContext->oformat = output;
    outputFormatContext->flags = AVFMT_NOFILE;
    outputFormatContext->audio_codec_id = 86017;

    AVStream *stream = avformat_new_stream(outputFormatContext,NULL);

    AVCodecParameters *oCodecParameters = avcodec_parameters_alloc();
    oCodecParameters->format = AV_SAMPLE_FMT_FLTP;
    oCodecParameters->codec_type = AVMEDIA_TYPE_AUDIO;
    oCodecParameters->sample_rate = 44100;
    oCodecParameters->channels = 2;
    oCodecParameters->channel_layout = AV_CH_LAYOUT_STEREO; 
    oCodecParameters->bit_rate = 64000;

    stream->codecpar = oCodecParameters;

    if(avformat_write_header(outputFormatContext,NULL)<0){
         dumpParameters(stream->codecpar);
         printf("avformat_write_header\n");
         exit(0);
    }

    while(1){

        if(av_read_frame(iFormatContext,packet)<0){
            printf("av_read_frame\n");
            exit(1);
        }

        if(packet->stream_index==inputStream){
            printf("pts: %ld\ndts: %ld\nduration: %ld\nstream index: %d\nsize: %d\npos: %ld\n",packet->pts,
                                                                                                    packet->dts,
                                                                                                    packet->duration,
                                                                                                    packet->stream_index,
                                                                                                    packet->size,
                                                                                                    packet->pos);
            //printf("Name: %s\nLong name: %s\n\n",output->name,output->long_name);
            if(av_interleaved_write_frame(outputFormatContext,packet)<0){
                printf("av_write_frame()\n");
                exit(0);
            }

        }
        av_packet_unref(packet);
    }
    
}

标签: cffmpegalsalibavinternet-radio

解决方案


推荐阅读