我正在尝试逐帧地将视频写入* .yuv文件,并找到有关将视频渲染到SDL表面的this教程。
现在我不确定如何在没有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
的情况下编写此功能?
你可以想象,我不是一个非常有经验的程序员,所以请耐心等待我;)
提前谢谢!
答案 0 :(得分:7)
我真的不知道libvlc,但是你可以根据这个特例去除SDL。
在此示例中,您必须将几个不同的函数传递给libvlc callback function ...
libvlc_video_set_callbacks(mp, lock, unlock, display, &ctx);
现在,要完全了解此锁定功能的作用,您需要了解一些多线程以及图像如何存储在内存中。
本质上,为了确保没有任何内容访问libvlc在写入时所使用的内存区域,它会“锁定”一种称为互斥锁的内容。如果您尝试锁定已被其他内容锁定的互斥锁,则当前执行将一直等到它被解锁。
如果你在半边写的时候访问了这些像素,你能想象它会有多可怕吗?它可能是半写的,然后你会用它来保存你的yuv文件。这将是灾难性的。
锁定功能所做的第二件事是指定内存中vlc可用于加载图像帧的区域。此示例使用SDL_Surface,但如果您小心 ,则可以创建自己的 。
所以,如果你只使用libvlc,你会想要找到这些东西的替代品。
我将从上面的列表中按相反的顺序排列。在示例中,它们使用SDL_Surface但是如果您无法使用它,则必须在内存中创建自己的结构以存储像素数据(如果您想要提取它)。一种简单的方法是创建一个正确大小的char数组。我会使用ctx结构,因为它很方便:我知道你问过不使用它,但在这种情况下它非常有用,因为我们需要将多条信息传递给锁定函数。
struct ctx
{
unsigned char *pixeldata;
};
现在,在主函数的某处,您需要在内存中创建区域。如果您知道视频大小和每像素使用的位数(bpp):这非常简单。但要非常小心,如果你没有正确地做到这一点:你可能最终会导致内存损坏。
ctx.pixeldata = new unsigned char[width * height * bpp];
确保在程序结束时正确删除...
delete[] ctx.pixeldata;
接下来是互斥体。这不是严格需要的,但是你可以遇到我上面提到的问题。如果您确实想使用互斥锁,则需要在libvlc_video_set_callbacks中指定解锁函数(如果您不想使用互斥锁,可以指定NULL解锁)。
问题是你将为此目的使用互斥锁(如果你想使用它,我建议你这样做)?如果您使用的是较新的C ++ 11标准,则可以使用std::mutex。如果你不是,那么你必须找到像boost threading library这样的东西,或者写一些类似你自己的东西。如果您使用的是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并删除示例中的显示代码。它在这个例子中为你处理内存,所以如果你不知道如何,它比编写你自己的安全代码容易一些。