ryou1128
@ryou1128

Are you sure you want to delete the question?

Leaving a resolved question undeleted may help others!

mpv でVapoursynthが使えない

MSYS2とVS2022でビルドしたMPV プレイヤーでVapoursynthが使えません。

Vapoursynth付きのコンパイルをしているのですがログファイルには[cplayer] Option vf-toggle: 'vapoursynth' isn't supported. となってしまいます。

普通のMPVプレイヤーなら動きます。 どなたか動いた方、知っている方いましたら回答お願いいたします。

Vapoursynth R69

libmpv バージョン  mpv v0.38.0-623-ged77616f29 Copyright ツゥ 2000-2024 mpv/MPlayer/mplayer2 projects

#include <iostream>
#include <thread>
#include <chrono>
#include <stdexcept>
#include <windows.h>
#include <mpv/client.h>
#include <mpv/render.h>
#include <ctime>
#include <string>
#include <codecvt>
#include <locale>

// グローバル変数
mpv_handle* g_mpv = nullptr;
mpv_render_context* g_mpv_ctx = nullptr;
bool g_running = true;
HWND g_hwnd = nullptr;
bool vapoursynth_enabled = false;  // VapourSynthの有効/無効状態を追跡

// UTF-8変換関数
std::string utf8_encode(const std::wstring& wstr) {
    if (wstr.empty()) return std::string();
    int size_needed = WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), NULL, 0, NULL, NULL);
    std::string strTo(size_needed, 0);
    WideCharToMultiByte(CP_UTF8, 0, &wstr[0], (int)wstr.size(), &strTo[0], size_needed, NULL, NULL);
    return strTo;
}

// ログ関数
void log(const std::string& msg) {
    std::time_t now = std::time(nullptr);
    char buf[20];
    std::strftime(buf, sizeof(buf), "%Y-%m-%d %H:%M:%S", std::localtime(&now));
    std::cerr << "[" << buf << "] " << msg << std::endl;
    OutputDebugStringA((msg + "\n").c_str());
}

// 例外ハンドラ
void handle_exception(const std::exception& e) {
    log("Exception caught: " + std::string(e.what()));
    MessageBoxA(NULL, e.what(), "Error", MB_OK | MB_ICONERROR);
}

// VapourSynthフィルターのトグル関数
void debug_vapoursynth_toggle(mpv_handle* mpv) {
    char* vf_string = nullptr;
    int error = mpv_get_property(mpv, "vf", MPV_FORMAT_STRING, &vf_string);
    if (error >= 0 && vf_string) {
        log("Current video filters: " + std::string(vf_string));
        mpv_free(vf_string);
    }
    else {
        log("Failed to get current video filters: " + std::string(mpv_error_string(error)));
    }

    // VapourSynthフィルターの状態を確認
    char* vs_script = nullptr;
    error = mpv_get_property(mpv, "vf-metadata/vapoursynth/file", MPV_FORMAT_STRING, &vs_script);
    if (error >= 0 && vs_script) {
        log("VapourSynth script: " + std::string(vs_script));
        mpv_free(vs_script);
    }
    else {
        log("No VapourSynth script currently active");
    }

    // フィルターの切り替えを試みる
    const char* cmd[] = { "vf", "toggle", "vapoursynth=~~/vs/MDegrain3.vpy", NULL };
    error = mpv_command(mpv, cmd);
    if (error < 0) {
        log("Failed to toggle VapourSynth filter: " + std::string(mpv_error_string(error)));
    }
    else {
        vapoursynth_enabled = !vapoursynth_enabled;
        log("VapourSynth filter toggled successfully. New state: " + std::string(vapoursynth_enabled ? "Enabled" : "Disabled"));
    }

    // 切り替え後の状態を再度確認
    error = mpv_get_property(mpv, "vf", MPV_FORMAT_STRING, &vf_string);
    if (error >= 0 && vf_string) {
        log("Video filters after toggle: " + std::string(vf_string));
        mpv_free(vf_string);
    }
}

// MPVイベントハンドラ
void handle_mpv_event(mpv_event* event) {
    switch (event->event_id) {
    case MPV_EVENT_LOG_MESSAGE: {
        mpv_event_log_message* msg = (mpv_event_log_message*)event->data;
        log(std::string(msg->prefix) + ": " + std::string(msg->text));
        break;
    }
    case MPV_EVENT_PROPERTY_CHANGE: {
        mpv_event_property* prop = (mpv_event_property*)event->data;
        if (strcmp(prop->name, "video-params") == 0) {
            log("Video parameters changed");
        }
        break;
    }
    default:
        break;
    }
}

// MPV初期化関数
bool init_mpv(HWND hwnd) {
    try {
        log("Initializing MPV");
        g_mpv = mpv_create();
        if (!g_mpv) throw std::runtime_error("Failed to create MPV handle");

        mpv_set_option_string(g_mpv, "vo", "gpu");
        mpv_set_option_string(g_mpv, "vf", "");
        mpv_set_option_string(g_mpv, "ao", "wasapi");
        mpv_set_option_string(g_mpv, "hwdec", "no");
        mpv_set_option_string(g_mpv, "video-sync", "audio");
        mpv_set_option_string(g_mpv, "input-default-bindings", "yes");
        mpv_set_option_string(g_mpv, "input-vo-keyboard", "yes");
        mpv_set_option_string(g_mpv, "osc", "yes");
        mpv_set_option_string(g_mpv, "osd-bar-align-y", "0.8");
        mpv_set_option_string(g_mpv, "osd-bar-h", "2");
        mpv_set_option_string(g_mpv, "osd-bar-w", "75");
        mpv_set_option_string(g_mpv, "framedrop", "vo");
        mpv_set_option_string(g_mpv, "osd-bar", "yes");
        mpv_set_option_string(g_mpv, "osd-color", "FFFFFF");
        mpv_set_option_string(g_mpv, "osd-back-color", "000000");
        mpv_set_option_string(g_mpv, "osd-font-size", "30");
        mpv_set_option_string(g_mpv, "osd-on-seek", "bar");
        mpv_set_option_string(g_mpv, "osd-duration", "1000");
        mpv_set_option_string(g_mpv, "osd-level", "1");
        mpv_set_option_string(g_mpv, "config", "yes");
        wchar_t exePath[MAX_PATH];
        GetModuleFileNameW(NULL, exePath, MAX_PATH);
        std::wstring exeDir = std::wstring(exePath);
        exeDir = exeDir.substr(0, exeDir.find_last_of(L"\\/"));
        std::string utf8ExeDir = utf8_encode(exeDir);

        std::string inputConfPath = utf8ExeDir + "\\input.conf";
        std::string mpvConfPath = utf8ExeDir + "\\mpv.conf";

        mpv_set_option_string(g_mpv, "input-conf", inputConfPath.c_str());
        mpv_set_option_string(g_mpv, "config-dir", utf8ExeDir.c_str());


        int64_t yes = 1;
        mpv_set_option(g_mpv, "osc", MPV_FORMAT_FLAG, &yes);

        mpv_request_log_messages(g_mpv, "v");

        if (mpv_initialize(g_mpv) < 0)
            throw std::runtime_error("Failed to initialize MPV");

        log("MPV initialized successfully");

        mpv_render_param params[] = {
            {MPV_RENDER_PARAM_API_TYPE, const_cast<char*>(MPV_RENDER_API_TYPE_SW)},
            {MPV_RENDER_PARAM_INVALID, nullptr}
        };

        int render_status = mpv_render_context_create(&g_mpv_ctx, g_mpv, params);
        if (render_status < 0) {
            const char* error = mpv_error_string(render_status);
            throw std::runtime_error("Failed to create MPV render context: " + std::string(error));
        }

        log("MPV render context created successfully");

        mpv_observe_property(g_mpv, 0, "video-params", MPV_FORMAT_NODE);
        mpv_observe_property(g_mpv, 0, "audio-params", MPV_FORMAT_NODE);

        const char* version = mpv_get_property_string(g_mpv, "mpv-version");
        const char* config = mpv_get_property_string(g_mpv, "libmpv-config");
        log("MPV Version: " + std::string(version ? version : "unknown"));
        log("MPV Config: " + std::string(config ? config : "unknown"));
        mpv_free((void*)version);
        mpv_free((void*)config);

        return true;
    }

catch (const std::exception& e) {
    handle_exception(e);
    return false;
}
}
// ファイル再生関数
void play_file(const wchar_t* filepath) {
    if (!g_mpv) {
        log("MPV not initialized");
        return;
    }

    try {
        std::string utf8_path = utf8_encode(filepath);
        log("Attempting to play file: " + utf8_path);
        const char* cmd[] = { "loadfile", utf8_path.c_str(), NULL };
        int error = mpv_command(g_mpv, cmd);
        if (error < 0) {
            throw std::runtime_error("Error playing file: " + std::string(mpv_error_string(error)));
        }
        log("File loaded successfully");

        mpv_observe_property(g_mpv, 0, "pause", MPV_FORMAT_FLAG);
    }
    catch (const std::exception& e) {
        handle_exception(e);
    }
}

// レンダリングループ
void render_loop() {
    while (g_running) {
        try {
            if (g_mpv_ctx) {
                mpv_event* event = mpv_wait_event(g_mpv, 0);
                if (event->event_id == MPV_EVENT_SHUTDOWN) {
                    g_running = false;
                    break;
                }

                handle_mpv_event(event);

                uint64_t flags = mpv_render_context_update(g_mpv_ctx);

                if (flags & MPV_RENDER_UPDATE_FRAME) {
                    RECT rect;
                    GetClientRect(g_hwnd, &rect);
                    int width = rect.right - rect.left;
                    int height = rect.bottom - rect.top;

                    HDC hdc = GetDC(g_hwnd);
                    BITMAPINFO bmi = { 0 };
                    bmi.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
                    bmi.bmiHeader.biWidth = width;
                    bmi.bmiHeader.biHeight = -height;
                    bmi.bmiHeader.biPlanes = 1;
                    bmi.bmiHeader.biBitCount = 32;
                    bmi.bmiHeader.biCompression = BI_RGB;

                    void* pixels = nullptr;
                    HBITMAP hBitmap = CreateDIBSection(hdc, &bmi, DIB_RGB_COLORS, &pixels, NULL, 0);

                    if (hBitmap && pixels) {
                        int size[2] = { width, height };
                        mpv_render_param params[] = {
                            {MPV_RENDER_PARAM_SW_SIZE, size},
                            {MPV_RENDER_PARAM_SW_FORMAT, const_cast<char*>(MPV_RENDER_API_TYPE_SW)},
                            {MPV_RENDER_PARAM_SW_STRIDE, &width},
                            {MPV_RENDER_PARAM_SW_POINTER, pixels},
                            {MPV_RENDER_PARAM_INVALID, nullptr}
                        };
                        mpv_render_context_render(g_mpv_ctx, params);

                        HDC hdcMem = CreateCompatibleDC(hdc);
                        HBITMAP hbmOld = (HBITMAP)SelectObject(hdcMem, hBitmap);
                        BitBlt(hdc, 0, 0, width, height, hdcMem, 0, 0, SRCCOPY);
                        SelectObject(hdcMem, hbmOld);
                        DeleteDC(hdcMem);
                        DeleteObject(hBitmap);
                    }

                    ReleaseDC(g_hwnd, hdc);
                }
            }
        }
        catch (const std::exception& e) {
            handle_exception(e);
        }

        std::this_thread::sleep_for(std::chrono::milliseconds(16));
    }
}

// ウィンドウプロシージャ
LRESULT CALLBACK WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam) {
    switch (uMsg) {
    case WM_CLOSE:
        g_running = false;
        PostQuitMessage(0);
        return 0;
    case WM_LBUTTONDOWN:
    {
        wchar_t filepath[MAX_PATH] = { 0 };
        OPENFILENAMEW ofn = { 0 };
        ofn.lStructSize = sizeof(ofn);
        ofn.hwndOwner = hwnd;
        ofn.lpstrFile = filepath;
        ofn.nMaxFile = sizeof(filepath) / sizeof(wchar_t);
        ofn.lpstrFilter = L"All\0*.*\0";
        ofn.nFilterIndex = 1;
        ofn.Flags = OFN_PATHMUSTEXIST | OFN_FILEMUSTEXIST;

        if (GetOpenFileNameW(&ofn)) {
            play_file(filepath);
        }
    }
    return 0;
    case WM_KEYDOWN:
        if (wParam == '1') {  // '1'キーでVapourSynthフィルターをトグル
            debug_vapoursynth_toggle(g_mpv);
        }
        return 0;
    default:
        return DefWindowProc(hwnd, uMsg, wParam, lParam);
    }
}

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nCmdShow) {
    try {
        log("Application started");

        WNDCLASSW wc = { 0 };
        wc.lpfnWndProc = WindowProc;
        wc.hInstance = hInstance;
        wc.lpszClassName = L"MPVPlayerClass";
        if (!RegisterClassW(&wc))
            throw std::runtime_error("Failed to register window class");

        g_hwnd = CreateWindowExW(
            0, L"MPVPlayerClass", L"MPV Player",
            WS_OVERLAPPEDWINDOW, CW_USEDEFAULT, CW_USEDEFAULT, 800, 600,
            nullptr, nullptr, hInstance, nullptr
        );

        if (!g_hwnd) throw std::runtime_error("Failed to create window");

        ShowWindow(g_hwnd, nCmdShow);

        if (!init_mpv(g_hwnd))
            throw std::runtime_error("Failed to initialize MPV");

        std::thread render_thread(render_loop);

        MSG msg;
        while (GetMessageW(&msg, nullptr, 0, 0)) {
            TranslateMessage(&msg);
            DispatchMessageW(&msg);
        }

        g_running = false;
        render_thread.join();

        if (g_mpv_ctx) mpv_render_context_free(g_mpv_ctx);
        if (g_mpv) mpv_destroy(g_mpv);

        log("Application ended normally");
        return 0;
    }
    catch (const std::exception& e) {
        handle_exception(e);
        log("Application ended with an error");
        return 1;
    }
}

0

No Answers yet.

Your answer might help someone💌