使用ffmpeg访问系统音频设备alsa驱动,从音频设备中读取音频流,读出的是pcm数据,然后编码推流到rtmp服务器。
关于流媒体服务器的搭建,以及配置windows使得虚拟机可以访问到pc的音频或视频设备,在之前的文章中有专门介绍。
#include <string> #include <iostream> using namespace std; extern "C" { #include <libavcodec/avcodec.h> #include <libavformat/avformat.h> #include <libavdevice/avdevice.h> #include <libswscale/swscale.h> #include <libavutil/opt.h> #include <libavcodec/avcodec.h> #include <libavutil/channel_layout.h> #include <libavutil/common.h> #include <libavutil/imgutils.h> #include <libavutil/mathematics.h> #include <libavutil/samplefmt.h> #include <libavutil/frame.h> #include <libavformat/avformat.h> #include <libswscale/swscale.h> } //8000 11025 12000 16000 22050 24000 32000 44100 48000 64000 88200 96000 void ErrorFunc(int errNum) { char buf[1024] = {0}; av_strerror(errNum, buf, sizeof(buf)); cout << "@@@" << buf << "@@@" << endl; exit(1); } int main(void) { av_register_all(); avcodec_register_all(); avformat_network_init(); avdevice_register_all(); AVInputFormat *ifmt_a = NULL; ifmt_a = av_find_input_format("alsa"); if (ifmt_a == NULL) { printf("无法找到设备\n"); } // av_dict_set(&options, "") AVFormatContext *ic_a = NULL; AVDictionary *options = NULL; // av_dict_set(&options, "video_size", "1920x1080", 0);//sample_rate // av_dict_set(&options, "framerate", "30", 0); av_dict_set(&options, "sample_rate", "48000", 0);//只能是48000不支持改动 av_dict_set(&options, "channels", "2", 0);//无法改,不支持改动 //null:131072 sysdefault:3760 pulse:512 default:512 front:64 dsnoop:4096(正常) hw:64(鬼声) plughw:64(鬼声) //null:131072但要是1024 sysdefault:3760(能听到,有噪音,无缓存,) pulse:512(听不到,无缓存) default:512(听不到,无缓存) front:64 dsnoop:4096(清晰,无缓存) int re = avformat_open_input(&ic_a, "dsnoop", ifmt_a, &options); if (re != 0) { printf("无法打开输入流\n"); ErrorFunc(re); } re = avformat_find_stream_info(ic_a, NULL); if (re != 0) { printf("找不到流信息\n"); ErrorFunc(re); } int audio_index = -1; for (int i = 0; i < ic_a->nb_streams; i++) { if (ic_a->streams[i]->codec->codec_type == AVMEDIA_TYPE_AUDIO) //AVMEDIA_TYPE_VIDEO { // ic->streams[i]->codecpar audio_index = i; } } if (audio_index == -1) { printf("找不到视频流\n"); } av_dump_format(ic_a, audio_index, "dsnoop", 0);//第四个参数填1则段错误 printf("here\n"); AVCodec *encodec_a = NULL; encodec_a = avcodec_find_encoder_by_name("libfdk_aac"); if (encodec_a == NULL) { printf("找不到编码器\n"); exit(1); } AVCodecContext *encodec_ctx_a = NULL; encodec_ctx_a = avcodec_alloc_context3(encodec_a); if (encodec_ctx_a == NULL) { printf("申请编码器上下文失败\n"); exit(1); } encodec_ctx_a->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; encodec_ctx_a->channel_layout = AV_CH_LAYOUT_STEREO; encodec_ctx_a->channels = 2; encodec_ctx_a->sample_rate = 48000; encodec_ctx_a->sample_fmt = AV_SAMPLE_FMT_S16; // encodec_ctx_a->framerate = (AVRational){44100, 128}; // encodec_ctx_a->time_base = (AVRational){128, 44100}; re = avcodec_open2(encodec_ctx_a, encodec_a, NULL); if (re != 0) { printf("打开编码器失败\n"); ErrorFunc(re); } AVFormatContext *oc_a = NULL; char *URL_a = "rtmp://127.0.0.1/live"; re = avformat_alloc_output_context2(&oc_a, NULL, "flv", URL_a); AVStream *o_stream_a = NULL; o_stream_a = avformat_new_stream(oc_a, NULL); //第二个参数 if (o_stream_a == NULL) { printf("fail to new stream\n"); ErrorFunc(re); } avcodec_parameters_from_context(o_stream_a->codecpar, encodec_ctx_a); // av_dump_format(oc_a, 0, URL_a, 1); re = avio_open(&oc_a->pb, URL_a, AVIO_FLAG_WRITE); if (re < 0) { printf("打开网络IO失败\n"); ErrorFunc(re); } re = avformat_write_header(oc_a, NULL); AVPacket read_pkt_a; av_init_packet(&read_pkt_a); //? AVFrame *p_pcm = NULL; p_pcm = av_frame_alloc(); p_pcm->format = AV_SAMPLE_FMT_S16; p_pcm->nb_samples = 1024; //1024/30 p_pcm->channels = 2; p_pcm->channel_layout = AV_CH_LAYOUT_STEREO; re = av_frame_get_buffer(p_pcm, 0); if (re != 0) { printf("fail to get buffer for p_pcm\n"); ErrorFunc(re); } AVPacket send_pkt_a; av_init_packet(&send_pkt_a); int count_a = 0; while (1) { av_init_packet(&read_pkt_a); re = av_read_frame(ic_a, &read_pkt_a); if (re < 0) { printf("read_frame error\n"); ErrorFunc(re); } // printf("here_mem\n"); // p_pcm->data = read_pkt_a.data; printf("read_pkt_a.size = %d\n", read_pkt_a.size); memcpy(p_pcm->data[0], read_pkt_a.data, 1024*2*2); // read_pkt_a.side_data // printf("here_mem_2\n"); count_a++; p_pcm->pts = count_a; re = avcodec_send_frame(encodec_ctx_a, p_pcm); if (re < 0) { printf("fail to send encode frame error = %d\n", re); ErrorFunc(re); } re = avcodec_receive_packet(encodec_ctx_a, &send_pkt_a); if (re == AVERROR(EAGAIN) || re == AVERROR_EOF) { // av_init_packet(&send_pkt); // av_packet_unref(&send_pkt); // av_packet_unref(&send_pkt); // printf("here_unref\n"); //记录前50帧都进入这里,说明缓冲了50帧,以后每个send,对应一个receive continue; } else if (re < 0) { printf("encode receive packet error = ret\n", re); ErrorFunc(re); } { send_pkt_a.pts = av_rescale_q(send_pkt_a.pts, encodec_ctx_a->time_base, o_stream_a->time_base); send_pkt_a.dts = av_rescale_q(send_pkt_a.dts, encodec_ctx_a->time_base, o_stream_a->time_base); send_pkt_a.duration = av_rescale_q(send_pkt_a.duration, encodec_ctx_a->time_base, o_stream_a->time_base); printf("size = %d\n", send_pkt_a.size); re = av_interleaved_write_frame(oc_a, &send_pkt_a); if (re != 0) { printf("write network err = %d\n", re); ErrorFunc(re); } printf("write\n"); // av_packet_unref(&send_pkt); } } }