使用VLC media player 发布RTSP流

举报
DS小龙哥 发表于 2022/02/28 09:46:25 2022/02/28
【摘要】 VLC可以播放本地视频、可以播放流媒体、并且还支持 视频流转码、串流、视频画面录制、区域放大、任意角度翻转等等功能。 这篇文章就介绍如何使用VLC发布RTSP视频流,将本地视频文件使用RTSP流发布。

来至官网的介绍:

VLC media player 是一款自由、开源的跨平台多媒体播放器及框架,可播放大多数多媒体文件,以及 DVD、音频 CD、VCD 及各类流媒体协议。

官网地址: https://www.videolan.org/

image.png

VLC支持跨平台、Linux、windows、IOS、Android 等等平台都支持,VLC不仅仅是一款万能播放器,主要是还有很多附加的功能很强大,特别作为音视频开发人员来讲,使用起来特别方便。

VLC可以播放本地视频、可以播放流媒体、并且还支持 视频流转码、串流、视频画面录制、区域放大、任意角度翻转等等功能。

这篇文章就介绍下使用VLC发布RTSP视频流,就是将本地视频文件使用RTSP流的形式串流出来,其他播放器就可以通过RTSP地址来访问视频,进行播放。 这个功能主要是开发流媒体播放器的时候,本地测试自己代码时非常方便,过程也简单;之前网上还有很多功能可以用的rtsp、rtmp,比如: CCTV 之类的,现在全部不能使用了。 测试时还是本地自己搭建一个比较方便。 除了VLC能串流RTSP外,ffmpeg命令行+EasyDarwin服务器 也可以发布RTSP流,也很稳定,特别是大视频比VLC还流畅。

目前网上公开还可以正常使用的一个RTSP地址: rtmp://media3.scctv.net/live/scctv_800

image.png

关于EasyDarwin服务器的使用方法可以看这里: https://blog.csdn.net/xiaolong1126626497/article/details/120673742

下面就介绍 VLC media player 串流RTSP流的步骤:

image.png

image.png

选择一个本地视频,然后点击串流:

image.png

image.png

image.png

image.png

image.png

image.png

得到RTSP地址是: rtsp://127.0.0.1:8554/abc

下面是使用ffmpeg开发的播放器,播放VLC发布的RTSP流效果:

image.png

image.png

//拉流
int Thread_FFMPEG_LaLiu::ffmpeg_rtmp_client()
{
    ffmpeg_laliu_run_flag=true;
    int video_width=0;
    int video_height=0;

    // Allocate an AVFormatContext
    AVFormatContext* format_ctx = avformat_alloc_context();
    format_ctx->interrupt_callback.callback = interrupt_cb; //--------注册回调函数

    // 打开rtsp:打开输入流并读取标题。 编解码器未打开
    std_str_rtsp_rtmp_addr=m_rtmp_addr.toStdString();

    const char* url =std_str_rtsp_rtmp_addr.c_str();// "rtmp://193.112.142.152:8888/live/abcd";

    //打印ffmpge的版本
    LogSend(QString("FFMPEG版本: %1\n").arg(av_version_info()));

    LogSend(QString("拉流地址: %1\n").arg(url));
    int ret = -1;

    LogSend(QString("正在打开输入流并读取头信息.\n"));

    AVDictionary* options = nullptr;

    //设置使用TCP协议拉取RTSP流
    ret=av_dict_set(&options,"rtsp_transport", "tcp", 0);
    if(ret != 0)
    {
        LogSend(QString("设置使用TCP协议拉取RTSP流失败.\n"));
        return -1;
    }

    //设置超时时间
    ret=av_dict_set(&options,"stimeout","10000000",0);
    if(ret != 0)
    {
        LogSend(QString("设置超时时间失败.\n"));
        return -1;
    }

    ret = avformat_open_input(&format_ctx, url, nullptr, nullptr);
    if(ret != 0)
    {
        LogSend(QString("无法打开网址: %1, return value: %2 \n").arg(url).arg(ret));
        return -1;
    }

    LogSend(QString("正在读取媒体文件的数据包以获取流信息.\n"));

    // 读取媒体文件的数据包以获取流信息
    ret = avformat_find_stream_info(format_ctx, nullptr);
    if(ret < 0)
    {
        LogSend(tr("无法获取流信息: %1\n").arg(ret));
        return -1;
    }

    AVCodec  *video_pCodec;
    // audio/video stream index
    int video_stream_index = -1;
    LogSend(tr("视频中流的数量: %1\n").arg(format_ctx->nb_streams));
    for(int i = 0; i < format_ctx->nb_streams; ++i)
    {
        const AVStream* stream = format_ctx->streams[i];
        LogSend(tr("编码数据的类型: %1\n").arg(stream->codecpar->codec_id));
        if(stream->codecpar->codec_type == AVMEDIA_TYPE_VIDEO)
        {
            //查找解码器
            video_pCodec=avcodec_find_decoder(AV_CODEC_ID_H264);
            //打开解码器
            int err = avcodec_open2(stream->codec,video_pCodec, NULL);
            if(err!=0)
            {
                  LogSend(tr("H264解码器打开失败.\n"));
                  return 0;
            }
            video_stream_index = i;
            //得到视频帧的宽高
            video_width=stream->codecpar->width;
            video_height=stream->codecpar->height;

            LogSend(tr("视频帧的尺寸(以像素为单位): (宽X高)%1x%2 像素格式: %3\n").arg(
                stream->codecpar->width).arg(stream->codecpar->height).arg(stream->codecpar->format));
        }
    }

    //打印流的详细信息
    //这是只是为了查看流的信息,打印出来了解
    av_dump_format(format_ctx,video_stream_index, url,0);

    //初始化解码相关的参数
    AVFrame *yuv420p_pFrame = nullptr;
    if (video_stream_index == -1)
    {
         LogSend("没有检测到视频流.\n");
         return -1;
    }
    else
    {
          yuv420p_pFrame = av_frame_alloc();// 存放解码后YUV数据的缓冲区
    }

    //申请存放yuv420p数据的空间
    yuv420p_data=new unsigned char[video_width*video_height*3/2];
    //申请存放rgb24数据的空间
    rgb24_data=new unsigned char[video_width*video_height*3];
    int y_size=video_width*video_height;

    AVPacket pkt;
    int re;

    LogSend("开始读取数据包...\n");
    while(ffmpeg_laliu_run_flag)
    {
        //读取一帧数据
        ret=av_read_frame(format_ctx, &pkt);
        if(ret < 0)
        {
            continue;
        }

        //得到视频包
        if(pkt.stream_index == video_stream_index)
        {
            //解码视频 frame
             re = avcodec_send_packet(format_ctx->streams[video_stream_index]->codec,&pkt);//发送视频帧
             if (re != 0)
             {
                 av_packet_unref(&pkt);//不成功就释放这个pkt
                 continue;
             }
             re = avcodec_receive_frame(format_ctx->streams[video_stream_index]->codec, yuv420p_pFrame);//接受后对视频帧进行解码
             if (re != 0)
             {
                 av_packet_unref(&pkt);//不成功就释放这个pkt
                 continue;
             }

            //将YUV数据拷贝到缓冲区
            memcpy(yuv420p_data,(const void *)yuv420p_pFrame->data[0],y_size);
            memcpy(yuv420p_data+y_size,(const void *)yuv420p_pFrame->data[1],y_size/4);
            memcpy(yuv420p_data+y_size+y_size/4,(const void *)yuv420p_pFrame->data[2],y_size/4);

            //将yuv420p转为RGB24格式
            YUV420P_to_RGB24(yuv420p_data,rgb24_data,video_width,video_height);

            //加载图片数据
            QImage image(rgb24_data,video_width,video_height,QImage::Format_RGB888);
            VideoDataOutput(image); //发送信号
        }
        av_packet_unref(&pkt);
    }

    qDebug()<<"退出拉流线程";

    avformat_close_input(&format_ctx);//释放解封装器的空间,以防空间被快速消耗完
    avformat_free_context(format_ctx);
    return 0;
}

下面是使用VLC-QT 开发的播放器,播放RTSP流的效果:

image.png

image.png

image.png

【版权声明】本文为华为云社区用户原创内容,转载时必须标注文章的来源(华为云社区)、文章链接、文章作者等基本信息, 否则作者和本社区有权追究责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容,举报邮箱: cloudbbs@huaweicloud.com
  • 点赞
  • 收藏
  • 关注作者

评论(0

0/1000
抱歉,系统识别当前为高风险访问,暂不支持该操作

全部回复

上滑加载中

设置昵称

在此一键设置昵称,即可参与社区互动!

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。

*长度不超过10个汉字或20个英文字符,设置后3个月内不可修改。