5

我正在尝试将视频逐帧写入 *.yuv 文件,并找到有关将视频渲染到 SDL 表面的本教程。

现在我不确定如何在没有 SDL 库的情况下使用此代码。比如锁功能:

static void *lock(void *data, void **p_pixels)
{
    struct ctx *ctx = data;

    SDL_LockMutex(ctx->mutex);
    SDL_LockSurface(ctx->surf);
    *p_pixels = ctx->surf->pixels;
    return NULL; /* picture identifier, not needed here */
}

struct ctx没有,SDL_LockMutex和怎么写这个函数SDL_LockSurface

你可以想象,我不是一个非常有经验的程序员,所以请耐心等待我;)
提前谢谢!

4

1 回答 1

7

我真的不知道 libvlc,但这里是您可以如何根据该特定示例删除 SDL。

删除 SDL

在此示例中,您必须将几个不同的函数传递给libvlc 回调函数......

libvlc_video_set_callbacks(mp, lock, unlock, display, &ctx);

现在,要完全理解这个锁函数在做什么,你需要了解一点多线程以及图像是如何存储在内存中的。

  • 本质上,为了确保在写入时 libvlc 正在使用的内存区域没有任何访问,它“锁定”了称为互斥体的东西。如果您尝试锁定已被其他东西锁定的互斥锁,则当前执行将等待直到它被解锁。

    如果你在写一半的时候访问这些像素,你能想象它会有多可怕吗?它可能写了一半,然后您将使用它保存到您的 yuv 文件中。这将是非常灾难性的。

  • lock 函数所做的第二件事是指定内存中的一个区域,vlc 可以使用它来加载图像帧。此示例为此使用了 SDL_Surface,但如果您小心的话,您可以创建自己的 SDL_Surface 。

所以,如果你只使用 libvlc,你会想找到这些东西的替代品。


我将从上面的列表中按相反的顺序进行。在示例中,他们使用 SDL_Surface 但是如果您无法使用它,则必须在内存中创建自己的结构来存储像素数据,如果您想提取它。一个简单的方法是创建一个正确大小的 char 数组。我将使用 ctx 结构,因为它很方便:我知道你问过不使用它,但在这种情况下它非常有用,因为我们需要将多条信息传递给 lock 函数。

struct ctx
{
    unsigned char *pixeldata;
};

现在,在您的 main 函数的某个地方,您需要在内存中创建该区域。如果您知道视频大小以及每像素使用多少位 (bpp):这非常简单。但是要非常小心,如果您没有正确执行此操作:您最终可能会导致内存损坏。

ctx.pixeldata = new unsigned char[width * height * bpp];

确保在程序结束时正确删除它...

delete[] ctx.pixeldata;

接下来是互斥体。这不是绝对需要的,但是您可能会遇到我上面提到的问题。如果您确实想使用互斥锁,则需要在 libvlc_video_set_callbacks 中指定解锁函数(如果您不想使用互斥锁,可以指定 NULL 进行解锁)。

问题是您将为此目的使用什么互斥锁(如果您想使用一个,我建议您这样做)?如果您使用较新的 C++11 标准,则可以使用std::mutex。如果你不是,那么你将不得不找到其他东西,比如boost 线程库,或者自己写一些类似的东西。如果您使用的是 C++11,则将其添加到 ctx 结构中...

#include <mutex>

struct ctx
{
    unsigned char *pixeldata;
    std::mutex imagemutex;
};

现在来看看实际的锁定功能本身。

static void *lock(void *data, void **p_pixels)
{
    struct ctx *ctx = data;

    ctx->imagemutex.lock()
    *p_pixels = ctx->pixeldata;

    return NULL;
}

您的解锁功能将是这样的......

static void unlock(void *data, void *id, void *const *p_pixels)
{
    struct ctx *ctx = data;

    ctx->unlock();

    assert(id == NULL);
}

每当您想安全地访问该像素数据时...

ctx->imagemutex.lock();
/* Access Data Here */
ctx->imagemutex.unlock();

使用 SDL

我想简单地添加一些关于 SDL 的内容。虽然它可用于将视频显示到屏幕上,但您不需要这样做。就个人而言,如果您不是那么有经验,我建议您继续使用 SDL 并在示例下方删除显示代码。在本例中,它会为您处理内存,因此如果您不知道如何编写安全代码,它比编写自己的安全代码要容易一些。

于 2013-05-13T20:58:32.390 回答