制作一个播放器(二)

制作一个播放器(一)

制作一个播放器(二)

接着上一章的热身,咱们继续写播放器。上一篇中咱们用的是句柄的方式来播放视频。实际开发中,我们更多的是把数据给回调出来,这样更好的去显示视频,处理视频。这期,继续写一个小demo。

这一篇,咱们把数据回调出来。

做个小广告

推荐免费学习直播课程:C/C++Linux服务器开发高级架构师学习视频 

这期,使用回调方式,将数据直接回调出来播放。

实现代码

main.h

#ifndef _MAIN_H_
#define _MAIN_H_

#include <QWidget>
#include <QPainter>

class CDisplay : public QWidget
{
    Q_OBJECT
public:
    CDisplay(QWidget* parent = nullptr) {}
    ~CDisplay() = default;
    
    void SetImage(QImage img)
    {
        m_img = img;
        update();
    }

protected:
    void paintEvent(QPaintEvent* e)
    {
        if (m_img.isNull())
        {
            return;
        }
        QPainter p(this);
        p.drawImage(rect(), m_img);
    }

private:
    QImage m_img;
};

#endif // _MAIN_H_

main.cpp

#include <QApplication>
#include "vlc/vlc.h"
#include <QDialog>
#include <QHBoxLayout>
#include <QObject>
#include <memory>
#include <stdint.h>
#include <thread>
#include "main.h"

#define qtu(str) ((str).toUtf8().constData())

const char* const vlc_args[] = {
   "-I",
   "dummy",
   "--ignore-config",
   "--rtsp-frame-buffer-size=1000000",
   "--rtsp-tcp",
};

// 通过方式获取宽高
int g_width = 0;
int g_height = 0;
std::shared_ptr<uint8_t> g_spBuffer;
libvlc_media_player_t* g_pVlcMediaPlayer = nullptr;
CDisplay* g_pDisplay = nullptr;

static void* lock(void* opaque, void** planes)
{
    try
    {
        *planes = g_spBuffer.get();
        return *planes;
    }
    catch (const std::exception&)
    {

    }
    return nullptr;
}

static void unlock(void* opaque, void* picture, void* const* planes)
{
    Q_UNUSED(opaque);
    Q_UNUSED(picture);
    Q_UNUSED(planes);
}

static void display(void* opaque, void* picture)
{
    QImage img((uchar*)picture, g_width, g_height, QImage::Format_ARGB32);
    if (g_pDisplay)
    {
        g_pDisplay->SetImage(img);
    }
    
}

void StartPlayer(void *context, QString strUrl)
{
    int argc = sizeof(vlc_args) / sizeof(vlc_args[0]);
    libvlc_instance_t* pInstance = libvlc_new(argc, vlc_args);
    libvlc_media_t* pVlcMedia = libvlc_media_new_location(pInstance, qtu(strUrl));
    g_pVlcMediaPlayer = libvlc_media_player_new_from_media(pVlcMedia);
    libvlc_media_player_set_hwnd(g_pVlcMediaPlayer, context);
    libvlc_media_release(pVlcMedia);
    libvlc_media_player_play(g_pVlcMediaPlayer);

    libvlc_state_t state = libvlc_media_player_get_state(g_pVlcMediaPlayer);
    if (state == libvlc_NothingSpecial || state == libvlc_Opening)
    {
        state = libvlc_media_player_get_state(g_pVlcMediaPlayer);
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
    }
    if (state == libvlc_Error)
    {
        // error
        libvlc_media_player_stop(g_pVlcMediaPlayer);
        return;
    }
    
    libvlc_media_track_t** tracks = nullptr;
    bool bFindResolution = false;
    while (!bFindResolution)
    {

        unsigned tracksCount = libvlc_media_tracks_get(pVlcMedia, &tracks);
        if (tracks != nullptr)
        {
            for (unsigned i = 0; i < tracksCount; i++)
            {
                if (tracks[i]->i_type == libvlc_track_video
                    && tracks[i]->video->i_height != 0
                    && tracks[i]->video->i_width != 0)
                {
                    g_width = tracks[i]->video->i_width;
                    g_height = tracks[i]->video->i_height;
                    bFindResolution = true;
                    break;
                }
            }

        }
        libvlc_media_tracks_release(tracks, tracksCount);
        std::this_thread::sleep_for(std::chrono::milliseconds(5));
    }
    libvlc_media_player_stop(g_pVlcMediaPlayer);
    if (bFindResolution)
    {
        libvlc_video_set_callbacks(g_pVlcMediaPlayer, lock, unlock, display, context);
        libvlc_video_set_format(g_pVlcMediaPlayer, "RV32", g_width, g_height, g_width << 2);
        g_spBuffer.reset(new uint8_t[(g_width * g_height) * 4], std::default_delete<uint8_t[]>());
        std::this_thread::sleep_for(std::chrono::milliseconds(10));
        libvlc_media_player_play(g_pVlcMediaPlayer);
    }

}

int main(int argc, char* argv[])
{
    QApplication a(argc, argv);
    QWidget w; // 避免屏幕出现闪动
    w.setVisible(false);
    CDisplay d;
    d.resize(640, 480);
    g_pDisplay = &d;
    QString strUrl = "rtsp://wowzaec2demo.streamlock.net/vod/mp4";
    std::thread th(std::bind(&StartPlayer, (void *)w.winId(), strUrl));
    d.show();
    int ret = a.exec();
    //release 
    th.join();
    if (g_pVlcMediaPlayer)
    {
        libvlc_media_player_stop(g_pVlcMediaPlayer);
        libvlc_media_player_release(g_pVlcMediaPlayer);
    }
    return ret;
}

代码地址:gitee

参考链接https://github.com/rocking5566/RtspPlayerDemo

注意事项:

1、生成工程以及一些注意事项,见我的第一篇《制作一个播放器(一)

2、main方法中,为什么使用QWidget w, w隐藏,这样可以避免屏幕闪(不使用CDisplay的原因也是基于此)。开始会使用句柄,是能获取对应流的宽高。

3、这期使用回调的方式,能够很方便的让我们处理图片。

4、新增了sqlite3,方便后期使用

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值