#include "mpvplayer.h"

// 唤醒函数
static void wakeup(void *ctx)
{
    // 此回调可从任何mpv线程调用（但也可以从调用mpv API的线程递归地返回）
    // 只是需要通知要唤醒的Qt GUI线程（以便它可以使用mpv_wait_event（）），并尽快返回
    MpvPlayer *mvpPlayer = (MpvPlayer *)ctx;
    emit mvpPlayer->mpv_events();
}

MpvPlayer::MpvPlayer(QWidget *parent) :
    QWidget(parent)
{
    // 创建mvpPlayer
    create_mvpPlayer(parent);
}

MpvPlayer::~MpvPlayer()
{
    if (mpv)
        mpv_terminate_destroy(mpv);
}

// 创建mvpPlayer
void MpvPlayer::create_mvpPlayer(QWidget *videoWin)
{
    // 创建mpv实例
    mpv = mpv_create();
    if (!mpv)
        throw std::runtime_error("can't create mpv instance");

    // 将视频子窗口的窗口ID传递给mpv wid选项

    int64_t wid = videoWin->winId();
    mpv_set_option(mpv, "wid", MPV_FORMAT_INT64, &wid);

    // 让我们通过MPV_EVENT_PROPERTY_CHANGE接收属性更改事件，如果这属性更改了
    mpv_observe_property(mpv, 0, "time-pos", MPV_FORMAT_DOUBLE);

    // 从这里开始，将调用唤醒功能。 回调可以来自任何线程，因此我们使用QueuedConnection机制以线程安全的方式中继唤醒
    connect(this, &MpvPlayer::mpv_events, this, &MpvPlayer::on_mpv_events,
            Qt::QueuedConnection);
    mpv_set_wakeup_callback(mpv, wakeup, this);

    // 判断mpv实例是否成功初始化
    if (mpv_initialize(mpv) < 0)
        throw std::runtime_error("mpv failed to initialize");
}

// 设置mpv属性
void MpvPlayer::setProperty(const QString &name, const QString &value)
{
    mpv_set_option_string(mpv, name.toLatin1().data(), value.toLatin1().data());
}

// 获得mpv属性
QString MpvPlayer::getProperty(const QString &name) const
{
    return (QString)mpv_get_property_string(mpv, name.toLatin1().data());
}

// 播放视频
void MpvPlayer::play(QString filename)
{
    if (mpv)
    {
        const QByteArray c_filename = filename.toUtf8();
        const char *args[] = {"loadfile", c_filename.data(), NULL};
        // 与mpv_command相同，但异步运行命令来避免阻塞，直到进程终止
        mpv_command_async(mpv, 0, args);
    }
}

// 这个槽函数由 wakeup()调用（通过mpv_events信号）
void MpvPlayer::on_mpv_events()
{
    // 处理所有事件，直到事件队列为空
    while (mpv)
    {
        mpv_event *event = mpv_wait_event(mpv, 0);
        if (event->event_id == MPV_EVENT_NONE)
            break;
        handle_mpv_event(event);
    }
}

// 处理mpv事件
void MpvPlayer::handle_mpv_event(mpv_event *event)
{
    switch (event->event_id)
    {
        // 属性改变事件发生
        case MPV_EVENT_PROPERTY_CHANGE:
        {
            mpv_event_property *prop = (mpv_event_property *)event->data;

            if (strcmp(prop->name, "time-pos") == 0)
            {
                if (prop->format == MPV_FORMAT_DOUBLE)
                {
                    // 获得播放时间
                    double time = *(double *)prop->data;
                    qDebug() << "播放时间: " << QString::number(time, 10, 2);
                }
                else if (prop->format == MPV_FORMAT_NONE)
                {
                    // 该属性不可用，可能意味着播放已停止
                    emit mpv_palyEnd();
                    qDebug() << "播放结束";
                }
            }
        }
        break;

        // palyer退出事件发生
        case MPV_EVENT_SHUTDOWN:
        {
            mpv_terminate_destroy(mpv);
            mpv = NULL;
        }
        break;

        default: ;
    }
}
