Qt FFmpeg 音视频播放器

使用FFmpeg库实现 本地和rtp 音视频播放器,使用qt绘制视频。

本demo环境为 qt5.12 vs2019-32位 .pro的qt工程

FFmpeg版本位3.4.8 vs2092-32位

本demo一共分为四部分

1:FFmpeg接口类,封装了一些FFmpeg的api,方便提供调用

2:thread类, 线程类,读取视频,解码,发送数据

3:UI类 使用qt的QOpenGLWidget类来绘制图像

4:audio播放类。 使用qt的QAudioOutput来播放解码后的音频数据

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

初始化ffmpeg

    avcodec_register_all();//注册所有解码器
    av_register_all();//注册所有格式
    avformat_network_init();//初始化网络流格式,使用RTSP网络流时必须先执行
 
    m_avFormatContext = avformat_alloc_context();
    m_yuvFrame = av_frame_alloc();
    m_pcmFrame = av_frame_alloc();

打开视频流或者rtp,流获取视频信息

    //打开视频流
    int result=avformat_open_input(&m_avFormatContext, url.toStdString().c_str(),nullptr,nullptr);
    if (result<0)
    {
        qDebug()<<"avformat_open_input error ---"<<result;
        return false;
    }
    //获取视频流信息
    result=avformat_find_stream_info(m_avFormatContext,nullptr);
    if (result<0)
    {
        qDebug()<<"avformat_find_stream_info error ---"<<result;
        return false;
    }

初始化音频相关,需要获取音频流的索引,初始化解码器上下文,音频重采样上下文

    //获取音频流索引
    for (uint i = 0; i < m_avFormatContext->nb_streams; i++)
    {
        if (AVMEDIA_TYPE_AUDIO == m_avFormatContext->streams[i]->codec->codec_type)
        {
            m_audioCodecContext = m_avFormatContext->streams[i]->codec;
            m_audioStreamIndex = i;
            break;
        }
    }
 
    if (-1 == m_audioStreamIndex)
    {        
        return false;
    }
 
    if(nullptr == m_audioCodecContext)
    {        
        return false;
    }
 
    //初始化一个视音频编解码器的AVCodecContext
    AVCodec *codec = avcodec_find_decoder(m_audioCodecContext->codec_id);//查找解码器
    if (avcodec_open2(m_audioCodecContext, codec, nullptr) < 0)
    {
        qDebug()<<"avcodec_open2 error---";
        return false;
    }
 
    m_sampleRate = m_audioCodecContext->sample_rate;//样本率
    m_channel = m_audioCodecContext->channels;//通道数
    switch (m_audioCodecContext->sample_fmt)//样本大小
    {
    case AV_SAMPLE_FMT_S16:
        this->m_sampleSize = 16;
        break;
    case  AV_SAMPLE_FMT_S32:
        this->m_sampleSize = 32;
    default:
        break;
    }
   
 
    if (nullptr == m_audioSwrContext)
    {
        m_audioSwrContext = swr_alloc();//初始化
        swr_alloc_set_opts(m_audioSwrContext,m_audioCodecContext->channel_layout,
                           AV_SAMPLE_FMT_S16,
                           m_audioCodecContext->sample_rate,
                           m_audioCodecContext->channels,
                           m_audioCodecContext->sample_fmt,
                           m_audioCodecContext->sample_rate,
                           0,0
                           );
        swr_init(m_audioSwrContext);
    }

初始化视频相关,获取视频流的索引,初始化解码器上下文。

 //获取视频流索引
    for (uint i = 0; i < m_avFormatContext->nb_streams; i++)
    {
        if (AVMEDIA_TYPE_VIDEO == m_avFormatContext->streams[i]->codec->codec_type)
        {
            m_videoStreamIndex = i;
            m_videoCodecContext = m_avFormatContext->streams[i]->codec;
            break;
        }
    }
 
    if(-1 == m_videoStreamIndex)
    {
        qDebug()<<"videoStreamIndex init error---";
        return false;
    }
    if (m_videoCodecContext == nullptr)
    {
        qDebug()<<"videoCodecContext init error---";
        return false;
    }
 
    //获取视频流解码器
    AVCodec *pAVCodec = avcodec_find_decoder(m_videoCodecContext->codec_id);
    //打开对应解码器
    int result=avcodec_open2(m_videoCodecContext,pAVCodec,nullptr);
    if (result<0)
    {
        qDebug()<<"avcodec_open2 video open error";
        return false;
    }
 
    m_videoSwsContext = sws_getContext(m_videoCodecContext->width,m_videoCodecContext->height,
                                       m_videoCodecContext->pix_fmt,
                                       m_videoCodecContext->width,m_videoCodecContext->height,
                                       AV_PIX_FMT_BGRA,SWS_BICUBIC,0,0,0);
 
    avpicture_alloc(&pAVPicture,AV_PIX_FMT_BGRA,m_videoCodecContext->width,m_videoCodecContext->height);

接下来就是线程run里面的读取数据,解码,发送数据的操作

void VideoThread::run()
{
    char audioOut[10000] = {0};
 
    while(m_isRun)
    {
        int free = AudioPlayer::Get()->GetFree();
        if (free < 10000)
        {
            msleep(1);
            continue;
        }
        AVPacket pkt = m_ffmpeg->getPacket();
        if (pkt.size <= 0)
        {
 
            msleep(10);
            continue;
        }
        if (pkt.stream_index == m_ffmpeg->m_audioStreamIndex)
        {
            m_ffmpeg->decode(&pkt);//解码
 
            int len = m_ffmpeg->getPCM(audioOut);//获取一帧音频的pcm
 
            AudioPlayer::Get()->Write(audioOut, len);            
        }
        else
        {
            if(m_ffmpeg->decode(&pkt))
            {
                m_ffmpeg->getRBG();
            }
        }
 
        av_packet_unref(&pkt);
    }
}

AudioPlayer::Get()->Write(audioOut, len); 此部分是音频播放

m_ffmpeg->getRBG(); 此部分是获取rgb数据帧, 并且绑定信号跟槽函数到QTopenglWidget绘制

UI绘制上:

在槽函数中接受数据,并且updata刷新

void OpenglWidget::paintEvent(QPaintEvent *e)
{
    QPainter painter;
    painter.begin(this);
    painter.drawImage(QPoint(0, 0), m_image);
    painter.end();
}
 
void OpenglWidget::showImage(const QImage &image)
{
    if(image.width() > image.height())
        m_image = image.scaledToWidth(width(),Qt::SmoothTransformation);
    else
        m_image = image.scaledToHeight(height(),Qt::SmoothTransformation);
 
    update();
}

绘制是按照视频原有的比例来绘制, 如果大分辨率切成小分辨率则需要刷新一下背景

如果你对音视频开发感兴趣,觉得文章对您有帮助,别忘了点赞、收藏哦!或者对本文的一些阐述有自己的看法,有任何问题,欢迎在下方评论区讨论!

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

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
基于QTFFmpeg开发的视频播放器可以实现跨平台的功能。首先,需要确保环境的搭建和配置。所需环境包括:操作系统为Windows 10 64位,QT版本为QT5.14.0,编译器为MinGW 64,FFmpeg版本为4.2.2。 在QT中使用FFmpeg进行视频播放,需要进行以下步骤: 1. 首先,需要创建一个QT项目,并在项目中添加FFmpeg库文件。在QT的.pro文件中添加如下代码: LIBS += -L/path/to/ffmpeg/libs -lavformat -lavcodec -lavutil 2. 在QT项目的代码中,需要导入FFmpeg相关的头文件,并初始化FFmpeg。可以使用avformat_open_input函数打开视频文件,并使用avformat_find_stream_info函数获取视频流信息。 3. 接下来,需要为视频播放创建一个窗口或者使用QT自带的视频播放器组件。可以使用QMediaPlayer组件或者自定义的视频播放组件。使用QMediaPlayer组件可以简化代码的编写,只需要设置视频源和播放控制即可。 4. 如果想要播放网络流媒体,可以使用FFmpeg提供的网络协议进行视频流的解析和播放。可以使用avformat_open_input函数打开网络流媒体,并使用av_read_frame函数读取视频帧数据,然后使用QImage或者FFmpeg提供的解码函数对视频帧进行解码显示。 5. 最后,需要在QT的事件循环中添加视频播放的逻辑,可以使用定时器或者其他方式来更新视频帧的显示。 通过以上步骤,就可以在QT中使用FFmpeg进行视频播放了。这样的视频播放器可以支持播放RTSP流、RTMP流和UDP流等不同的视频流媒体。 综上所述,QT结合FFmpeg开发的视频播放器可以实现跨平台的功能,并且可以满足播放不同类型的视频流的需求。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值