ffmpeg代码实现流媒体推流(rtsp)(代码片段)

音视频开发老舅 音视频开发老舅     2023-03-28     586

关键词:

实时录屏并把视频推流到RTSP服务器,具体流程是抓取屏幕内容(bitmap),并把bitmap转化为YUV,接着把YUV编码成H264,再把H264码流推到RTSP服务器;把采集到的PCM编码为AAC,再把AAC推流至RTSP服务器。

RTSP服务器使用的是HappyTime的免费试用版本。

1. bitmap转YUV

我抓到的bitmap是BGRA格式的,所以使用的图像格式是AV_PIX_FMT_BGRA,cropImage是含有rgba图像的数组

bool init_RGB_to_YUV()
    
    //BGRA 转 YUV
    swrCtxBGRA2YUV = sws_getContext(
        cap_w, cap_h, AV_PIX_FMT_BGRA,
        cap_w, cap_h, AV_PIX_FMT_YUV420P,
        SWS_BICUBIC,
        NULL, NULL, NULL
        );

    //创建BGRA帧
    frame_bgra = av_frame_alloc();
    frame_bgra->format = AV_PIX_FMT_BGRA;
    frame_bgra->width = cap_w;
    frame_bgra->height = cap_h;
    if (av_frame_get_buffer(frame_bgra, 32) < 0) 
        printf("Failed: av_frame_get_buffer\\n");
        return false;
    
    frame_bgra->data[0] = cropImage;
    

    //YUV帧
    frame_yuv = av_frame_alloc();
    frame_yuv->width = cap_w;
    frame_yuv->height = cap_h;
    frame_yuv->format = AV_PIX_FMT_YUV420P;

    //
    uint8_t *picture_buf = (uint8_t *)av_malloc(cap_w * cap_h * 1.5);
    if (av_image_fill_arrays(frame_yuv->data, frame_yuv->linesize, picture_buf, AV_PIX_FMT_YUV420P, cap_w, cap_h, 1) < 0)
        printf("Failed: av_image_fill_arrays\\n");
        return false;
    
    return true;

调用:

//BGRA 转 YUV
    if (sws_scale(swrCtxBGRA2YUV,
        frame_bgra->data, frame_bgra->linesize,
        0, cap_h,
        frame_yuv->data, frame_yuv->linesize) < 0)
    
        printf("失败:BGRA 转 YUV\\n");
        return;
    

    frame_yuv->pts = av_gettime();

由于我是实时抓取的屏幕,frame_yuv->pts设为当前的时间戳,以保证能正常播放。

2. H264编码

bool init_YUV_to_H264()
    //寻找编码器
    codec_h264 = avcodec_find_encoder(AV_CODEC_ID_H264);
    if (!codec_h264)
        printf("Fail: avcodec_find_encoder\\n");
        return false;
    

    //编码器上下文
    codec_ctx_h264 = avcodec_alloc_context3(codec_h264);
    if (!codec_ctx_h264)
        printf("Fail: avcodec_alloc_context3\\n");
        return false;
    
    codec_ctx_h264->pix_fmt = AV_PIX_FMT_YUV420P;
    codec_ctx_h264->codec_type = AVMEDIA_TYPE_VIDEO;
    codec_ctx_h264->width = cap_w;
    codec_ctx_h264->height = cap_h;
    codec_ctx_h264->channels = 3;
    codec_ctx_h264->time_base =  1, 25 ;
    codec_ctx_h264->gop_size = 5;   //图像组两个关键帧(I帧)的距离
    codec_ctx_h264->max_b_frames = 0;
    //codec_ctx_h264->qcompress = 0.6;
    //codec_ctx_h264->bit_rate = 90000;
    codec_ctx_h264->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;   //添加PPS、SPS
    
    av_opt_set(codec_ctx_h264->priv_data, "preset", "ultrafast", 0);    //快速编码,但会损失质量
    //av_opt_set(codec_ctx_h264->priv_data, "tune", "zerolatency", 0);  //适用于快速编码和低延迟流式传输,但是会出现绿屏
    //av_opt_set(codec_ctx_h264->priv_data, "x264opts", "crf=26:vbv-maxrate=728:vbv-bufsize=3640:keyint=25", 0);


    //打开编码器
    if (avcodec_open2(codec_ctx_h264, codec_h264, NULL) < 0)
        printf("Fail: avcodec_open2\\n");
        return false;
    

    //用于接收编码好的H264
    pkt_h264 = av_packet_alloc();

    return true;

本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部↓↓

调用:

    ret = avcodec_send_frame(codec_ctx_h264, frame_yuv);
    if (ret < 0)
        printf("send frame fail\\n");
        return;
    

    while (ret >= 0)        
        ret = avcodec_receive_packet(codec_ctx_h264, pkt_h264);
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            break;
        

        if (ret < 0)
            printf("Error during encoding\\n");
            break;
        

        pkt_h264->stream_index = videoindex;
        //printf("pkt_h264 timestamp = %d\\n", pkt_h264->pts);

        if (av_interleaved_write_frame(fmt_ctx, pkt_h264) < 0) 
            printf("Error muxing packet\\n");
        

        av_packet_unref(pkt_h264);
    

3. AAC编码 

bool init_PCM_to_AAC()

    codec_aac = avcodec_find_encoder(AV_CODEC_ID_AAC);
    if (!codec_aac) 
        printf("avcodec_find_encoder fail\\n");
        return false;
    

    codec_ctx_aac = avcodec_alloc_context3(codec_aac);
    if (!codec_ctx_aac) 
        printf("avcodec_find_encoder fail\\n");
        return false;
    
    codec_ctx_aac->sample_fmt = AV_SAMPLE_FMT_FLT;
    codec_ctx_aac->codec_type = AVMEDIA_TYPE_AUDIO;
    codec_ctx_aac->channels = channels;
    codec_ctx_aac->channel_layout = av_get_default_channel_layout(channels);
    codec_ctx_aac->sample_rate = sample_rete;

    if (avcodec_open2(codec_ctx_aac, codec_aac, NULL) < 0) 
        printf("open codec fail\\n");
        return false;
    

    swrCtxS162FLT = swr_alloc_set_opts(NULL,
        codec_ctx_aac->channel_layout, codec_ctx_aac->sample_fmt, codec_ctx_aac->sample_rate,
        codec_ctx_aac->channel_layout, AV_SAMPLE_FMT_S16, codec_ctx_aac->sample_rate,
        0, 0);

    if (!swrCtxS162FLT)
    
        printf("swr_alloc_set_opts error\\n");
        return false;
    
    if (swr_init(swrCtxS162FLT) < 0) 
        printf("open resample fail\\n");
        return false;
    

    frame_pcm = av_frame_alloc();
    frame_pcm->nb_samples = nbSamples_; //一帧音频存放的样本数量
    frame_pcm->format = codec_ctx_aac->sample_fmt;
    frame_pcm->channels = codec_ctx_aac->channels;
    frame_pcm->channel_layout = codec_ctx_aac->channel_layout;

    if (av_frame_get_buffer(frame_pcm, 0) < 0) 
        printf("av_frame_get_buffer error\\n");
        return false;
    

    pkt_aac = av_packet_alloc();

    return true;

调用:
其中pcm_buff是包含pcm数据的数组

const uint8_t *pcm[1];
        pcm[0] = pcm_buff;
        int len = swr_convert(swrCtxS162FLT,
            frame_pcm->data, frame_pcm->nb_samples,
            pcm, nbSamples_);

        if (len <= 0) 
            printf("---Encodec:PCM->AAC--- swr_convert fail \\n");
            return;
        

        frame_pcm->pts = av_gettime();

        //printf("channels = %d\\n", frame_pcm->channels);
        //printf("framePCM->linesize = %6d %6d\\n", frame_pcm->linesize[0], frame_pcm->linesize[1]);

        //AAC编码
        int ret = avcodec_send_frame(codec_ctx_aac, frame_pcm);
        if (ret < 0)
            printf("send frame fail\\n");
            return;
        

        ret = avcodec_receive_packet(codec_ctx_aac, pkt_aac);
        
        if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)
            return;
        

        if (ret < 0)
            printf("Error during encoding\\n");
            return;
        

        pkt_aac->stream_index = audioindex;
        //printf("pkt_aac timestamp = %d\\n", pkt_aac->pts);

        if (av_interleaved_write_frame(fmt_ctx, pkt_aac) < 0) 
            printf("Error muxing packet\\n");
        
        av_packet_unref(pkt_aac);

4. 推流器

使用udp传输时传到1400多帧就断开链接了,原因不明,所以改用使用tcp协议传输

bool init_rtsp_pusher()
    
    //RTSP
    if (avformat_alloc_output_context2(&fmt_ctx, NULL, "RTSP", RTSP_URL.c_str()) < 0)
        printf("Fail: avformat_alloc_output_context2\\n");
        return false;
    

    //使用tcp协议传输
    av_opt_set(fmt_ctx->priv_data, "rtsp_transport", "tcp", 0);

    //检查所有流是否都有数据,如果没有数据会等待max_interleave_delta微秒
    fmt_ctx->max_interleave_delta = 1000000;

    //输出视频流
    AVStream *video_s = avformat_new_stream(fmt_ctx, codec_h264);
    if (!video_s)
        printf("Fail: avformat_new_stream\\n");
        return false;
    
    video_s->time_base =  1, 25 ;
    videoindex = video_s->id = fmt_ctx->nb_streams - 1;  //加入到fmt_ctx流

    //复制AVCodecContext的设置
    if (avcodec_copy_context(video_s->codec, codec_ctx_h264) < 0) 
        printf("Fail: avcodec_copy_context\\n");
        return false;
    
    video_s->codec->codec_tag = 0;
    if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
        video_s->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
    
    avcodec_parameters_from_context(video_s->codecpar, codec_ctx_h264);

    
        //输出音频流
        AVStream *audio_s = avformat_new_stream(fmt_ctx, codec_ctx_aac->codec);
        if (!audio_s)
            printf("Fail: avformat_new_stream\\n");
            return false;
        
        audio_s->time_base =  1, 25 ;
        audioindex = audio_s->id = fmt_ctx->nb_streams - 1;

        //复制AVCodecContext的设置
        if (avcodec_copy_context(audio_s->codec, codec_ctx_aac) < 0) 
            printf("Fail: avcodec_copy_context\\n");
            return false;
        
        audio_s->codec->codec_tag = 0;
        if (fmt_ctx->oformat->flags & AVFMT_GLOBALHEADER)
            audio_s->codec->flags |= AV_CODEC_FLAG_GLOBAL_HEADER;
        avcodec_parameters_from_context(audio_s->codecpar, codec_ctx_aac);
    
        //printf("fmt_ctx nb_streams = %d\\n", fmt_ctx->nb_streams);

    av_dump_format(fmt_ctx, 0, fmt_ctx->filename, 1);
    if (!(fmt_ctx->oformat->flags & AVFMT_NOFILE))     //???
        //打开输出URL(Open output URL)
        if (avio_open(&fmt_ctx->pb, fmt_ctx->filename, AVIO_FLAG_WRITE) < 0) 
            printf("Fail: avio_open('%s')\\n", fmt_ctx->filename);
            return false;
        
    
    return true;

结果 

 

 原文链接:FFmpeg 代码实现流媒体推流(RTSP) - 资料 - 我爱音视频网 - 构建全国最权威的音视频技术交流分享论坛

本文福利, C++音视频学习资料包、技术视频,内容包括(音视频开发,面试题,FFmpeg webRTC rtmp hls rtsp ffplay srs↓↓↓↓↓↓见下面↓↓文章底部↓↓ 

流媒体服务海康摄像头rtsp视频推流转码拉流直播综合应用:vlc+ffmpeg+nginx实现rtsp到rtmp网页直播(代码片段)

...综合直播应用,延迟5秒钟左右…一、前几章节回顾【流媒体服务】基础协议了解(一):【1】RTP/RTMP/RTSP等基础协议了解【流媒体服务】推流拉流体验(二):【1】使用VLC轻松体验本地视频推流、拉流... 查看详情

流媒体解码及h.264编码推流(代码片段)

简介相关理论程序流程Opencv解析视频流像素格式转换FFmpeg进行H.264编码FFmpeg进行格式封装和推流这里我们使用了FFmpge的sdk和Opencv的sdk。为了方便测试,我们直接使用在线的rtsp网络流。rtmp://live.hkstv.hk.lxdns.com/live/hks这个是香港... 查看详情

ffmpeg搭建一个简单的rtsp推流方案(代码片段)

文章目录ffmpeg搭建一个简单的rtsp推流方案基础环境要求开始demoffmpeg搭建一个简单的rtsp推流方案基础环境要求ffmpegffplay/VLCrtsp服务器开始首先我们必须要安装好ffmpeg,不管是源码编译还是直接安装网上都有很多教程,这里不多展开.... 查看详情

win10下用ffmpeg推流拉流(代码片段)

...中第一个“”代表摄像头的RTSP地址,第二个“”代表流媒体服务器地址,如果出现下图所示代表推流成功。   三.拉流打 查看详情

javacv开发详解之rtsp推流实战:rtsp转推到rtsp(代码片段)

...是那句话,Nocodenobb!废话少谈,直接上代码。参考资料ffmpeg官方rtsp封装格式说明:https://ffmpeg.org/ffmpeg-protocols.html#rtsp开始前的准备工作1、依赖项使用maven添加依赖 查看详情

如何通过python实现h.264视频推流与接收(代码片段)

...SP推流2.3.2简单的UDP推流2.3.3简单的RTSP流接收3.网络上基于FFmpeg的视频推流 3.1FFmpeg安装3.2FFmpeg的基本指令3.3基于FFmpeg的RTSP推流3.3.1基于管道的本地推流3.3.2基于FFmpeg的网络推流示例4.实例与验证4.1基于GStreamer的推流实现4.2基于FFmpeg... 查看详情

ffmpeg监控拉流,向流媒体服务器推流

解决用FFMPEG拉网络监控的RTSP流,然后再推到流媒体服务器,然后再通过流媒体服务器对外发布。拉流推流同时由MMPEG完成,网上的教程大部分都是通过OPENCV拉流,然后通过共享管道向FFMPEG推流。-i"rtsp://admin:12345... 查看详情

ffmpeg音视频开发:发布rtsp流(采用easydarwin作为流媒体服务器)(代码片段)

...n拥有完整的源代码,可以帮助开发者更快更简单实现流媒体音视频产品功能,使用完全免费;下面就介绍一下EasyDarwin的使用过程。官网地址: EasyDarwin开源流媒体服务器OpenSourceStreamingServer如果官 查看详情

javacv音视频开发宝典:rtsp拉流转码方式转推到rtmp

...rtmp协议相信大家都不陌生了,rtmp协议是Adobe公司制定的流媒体协议。rtmp推流可以说是直播行业最常用的推流方式,没有之二。但是由于rtmp规范已经不在维护了,不支持h265编码,更不用说goole出品的vp8、vp9和av1了。好了,还是那... 查看详情

javacv开发详解之rtp推流实战:rtsp转推到rtp(代码片段)

...。Nocodenobb!废话少谈,让我们直接上代码吧。参考资料ffmpeg官方rtp封装格式说明:https://ffmpeg.org/ffmpeg-protocols.html#rtp开始前的准备工作1、依赖项使用maven添加依赖 查看详情

利用ffmpeg推流到rtsp,再利用jmpeg在html界面上显示的解决办法(代码片段)

目录需求在python代码里推流到rtsphtml里播放rtsp视频流需求最近在百度飞桨上训练了一个摔倒识别的模型,用的PaddleDetection这个模型,训练好以后我部署到了Windows,但是我看大多数人都是部署到了Linux,具体方法大家可以自行百度... 查看详情

c#使用ffmpeg推流,并且获取流保存在本地,随时取媒体进行播放!

...一点成果,这边做个笔记;本文着重在于讲解下如何使用ffmpeg进行简单的推流,看似简单几行代码没有官方的文档很吃力。并获取流的源代码:如下→#regionRTMP推流(**已成功推流至服务器**)Network.Create().WithSource(inputPath)//inputPath可... 查看详情

ffmpeg推流相关指令

1.rtsp->rtsp(只解封装,不解码)ffmpeg-re-rtsp_transporttcp-irtsp://usr:[email protected]:port/h264/ch1/sub/av_stream-acodeccopy-vcodeccopy-frtsprtsp://ip:port/name2.rtsp->rtmp(只解封装,不解码)ffmpeg-re-rts 查看详情

c#ffmpeg推流vlc.dotnet拉流优化参数(代码片段)

FFmpeg是流媒体开源神器,视频转换、剪裁包括推流,无所不能,很多系统都是基于其开发的。拉流可以用FFplay,但是不利于集成到自己的代码中,因此拉流选择了Vlc.DotNet。在使用中,仅使用默认参数,... 查看详情

qt软件开发-基于ffmpeg设计录屏与rtsprtmp推流软件(支持桌面与摄像头)(代码片段)

QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(一)https://xiaolong.blog.csdn.net/article/details/126954626QT软件开发-基于FFMPEG设计录屏与rtsp、rtmp推流软件(支持桌面与摄像头)(二)https://xiaolong.blog.cs 查看详情

写代码实现直播推流

...制,这些知识已经可以做到推流了。花满楼:之前是使用ffmpeg命令来推流,控制度不够高,现在以代码的方式来实现,可灵活控制。本文介绍如何写代码实现直播的推流功能。最终的效果是这样的:演示推流的代码:#include<std... 查看详情

ffmpeg推流摄像头(代码片段)

一般的直播网站都使用OBS推流,其实ffmpeg也可以推流,在无界面环境下就可以推流使用。本文以Windows下为例,简单介绍下使用ffmpeg工具推流的方法和步骤。下载安装下载地址:https://ffmpeg.zeranoe.com/builds/选择版本&#... 查看详情

ffmpeg推流摄像头(代码片段)

一般的直播网站都使用OBS推流,其实ffmpeg也可以推流,在无界面环境下就可以推流使用。本文以Windows下为例,简单介绍下使用ffmpeg工具推流的方法和步骤。下载安装下载地址:https://ffmpeg.zeranoe.com/builds/选择版本&#... 查看详情