c - 我可以使用 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#details,https://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);
}
}
解决方案
推荐阅读
- google-apps-script - 如何计算Google表格中单元格中出现多次的单词每次出现之间的字符数?
- html - 弯曲方向组件设置
- c# - 在 Knockoutjs 中动态添加行
- python - re.sub() 如何改变不可变的 Python 字符串?
- laravel - Laravel 在条件下在路由中加载中间件
- android - Google 的 SupportMapFragment 类型转换异常与 v4 Fragment
- angular - 无法使用量角器单击按钮。按钮文本在子范围内
- python - 使用 dtreeviz 可视化决策树
- git - git不会在子文件夹中添加内容
- python-3.x - PySimpleGUI 中 return_keyboard_events 的意外行为