制作一个播放器(二)

制作一个播放器(一)

制作一个播放器(二)

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

<think>好的,用户想了解如何排查Linux系统的磁盘告警问题,我需要详细步骤和常用命令。首先,我得回忆一下之前学过的相关知识,结合提供的引用内容来整理回答。 首先,用户的问题是关于磁盘告警排查,所以需要从基础命令开始。引用[1]里提到了几个步骤,比如磁盘挂载情况、各目录使用情况,还有处理文件被删除但引用未释放的问题。这些应该是核心步骤。而引用[3]提到磁盘I/O过大的排查,可能也需要涉及iotop等工具。此外,引用[4]提到保留5%空间的情况,这也是一个常见但容易被忽视的点。 接下来,我需要组织步骤。通常排查磁盘问题会先看整体使用情况,用df命令,然后找具体哪个目录占用大,用du。但有时候删除的文件如果还被进程占用,空间不会释放,这时候需要lsof来找这些文件,并重启进程。引用[1]里的步骤正好覆盖了这些,所以可以按照这个顺序来写。 另外,用户可能需要知道如何处理特定问题,比如日志文件过大,比如binlog,这时候可以引用[5]的建议,清理旧的日志。还有保留空间的问题,引用[4]提到的调整保留空间的方法,可能需要用tune2fs命令。 还要考虑I/O过高的情况,这时候iotop(引用[3])和iostat命令就派上用场了。这些工具可以帮助看哪些进程在大量读写磁盘。 需要确保步骤清晰,分步骤讲解,每个步骤对应的命令和解释。同时,要提到可能遇到的坑,比如已删除未释放的文件,以及保留空间的问题,这些都是实际运维中常见的情况。 最后,生成相关问题的时候,可以围绕进一步的优化、具体命令的使用、其他相关工具(如日志轮转)来提问,这样用户如果有更深的问题,可以继续探索。 确保使用中文回答,数学公式用$...$,独立公式用$$...$$,不过这个问题可能数学公式较少,但如果有的话要注意格式。引用标注要正确,比如处理已删除文件的部分引用[1],保留空间引用[4],binlog清理引用[5],I/O工具引用[3]等。 现在把这些整理成一个结构化的回答,分步骤说明,每个步骤的命令和解释,以及注意事项。最后附上相关问题,帮助用户深入理解。</think>### Linux系统磁盘告警问题排查步骤及常用命令 #### 一、看整体磁盘使用情况 使用 **`df -h`** 命令看当前磁盘挂载情况及空间占用率。重点关注 **`Use%`** 列,快速定位盘的分区[^1][^2]。 ```bash df -h ``` #### 二、定位大文件或目录 通过 **`du -sh /*`** 逐级排查占用较大的目录。例如: ```bash du -sh /var/* | sort -rh # 看/var目录下各子目录大小 du -sh /home/* | sort -rh # 看/home目录占用 ``` #### 三、处理已删除但未释放空间的文件 若发现磁盘占用异常但未找到对应大文件,可能是进程仍持有已删除文件的句柄。使用 **`lsof | grep deleted`** 找此类文件[^1][^3]: ```bash lsof | grep deleted # 列出被删除但仍被进程占用的文件 kill -9 <PID> # 终止相关进程释放空间(需谨慎操作) ``` #### 四、检保留空间策略 Linux默认保留5%磁盘空间供root使用,可通过 **`tune2fs`** 调整[^4]: ```bash tune2fs -m 1 /dev/sda1 # 将保留空间比例从5%改为1% ``` #### 五、清理日志文件 针对常见日志文件(如Nginx、MySQL的binlog)进行清理[^5]: ```bash # 清理MySQL binlog(需在MySQL内执行) PURGE BINARY LOGS BEFORE '2023-01-01 00:00:00'; # 清理系统日志 journalctl --vacuum-size=200M # 保留最近200MB日志 ``` #### 六、排查磁盘I/O异常 若告警为I/O负载过高,使用以下工具分析: 1. **`iotop`**:实时监控进程级I/O[^3] ```bash iotop -o # 显示正在执行I/O的进程 ``` 2. **`iostat`**:看设备级I/O统计 ```bash iostat -x 1 # 每秒刷新一次详细I/O数据 ``` #### 七、关键配置文件检 **`/etc/fstab`** 是否配置异常,或使用 **`mount`** 命令确认挂载参数: ```bash mount | grep -i noquota # 检是否未启用磁盘配额 ``` --- ###
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值