Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

LibVLC tutorial without SDL?

I am trying to write a video frame by frame to a *.yuv file and found this tutorial about rendering a video into an SDL surface.

Now I'm not exactly sure how to use this code without the SDL library. For example, the lock function:

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 */
}

How can I write this function without struct ctx, SDL_LockMutex and SDL_LockSurface?

As you can imagine, I am not a very experienced programmer so please be patient with me ;)
Thanks in advance!

like image 979
user2273364 Avatar asked May 13 '13 08:05

user2273364


1 Answers

I don't really know libvlc, but here is how you could go about removing SDL based on that particular example.

Removing SDL

In this example, there are a couple of different functions you have to pass through to the libvlc callback function...

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

Now, to fully understand what this lock function is doing, you need to understand a little of multi-threading and how an image is stored in memory.

  • Essentially, to make sure nothing accesses the area of memory libvlc is using while it is writing to it, it 'locks' something known as a mutex. If you try to lock a mutex that is already locked by something else, the current execution will wait until it has been unlocked.

    If you accessed these pixels while it was half-written, can you imagine how horrible it would be? It could be half-written, and you would then use it to save to your yuv file. It would be quite disastrous.

  • The second thing the lock function does is specify an area in memory that vlc can use to load the image frame. This example uses an SDL_Surface for this, but you can create your own if you're careful.

So, if you are only using libvlc, you'll want to find an alternative to these things.


I'll go in reverse order from the list above. In the example, they use an SDL_Surface however if you are unable to use that, you would have to create your own structure in memory to store the pixel data if you are wanting to extract it. A simple way is to create a char array of the correct size. I'll use the ctx struct as it's convenient: I know you asked about not using it, but it is quite useful in this case as we need to pass multiple pieces of information through to the lock function.

struct ctx
{
    unsigned char *pixeldata;
};

Now, somewhere in your main function you will need to create the area in memory. If you know the video size and how many bits per pixel (bpp) are used: this is pretty simple. But be very careful, if you don't do this correctly: you could end up with memory corruption.

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

Make sure to delete this properly at the end of the program...

delete[] ctx.pixeldata;

The next thing is the mutex. This isn't strictly needed, however you can come across problems as I mentioned above. If you do want to use a mutex, you will need to specify an unlock function in the libvlc_video_set_callbacks (you can specify NULL for unlock if you don't want to use a mutex).

The problem is what mutex will you use for this purpose (if you want to use one, which I suggest you do)? If you are using the newer C++11 standard you can use std::mutex. If you aren't, then you'll have to find something else like the boost threading library or write something similar of your own. If you are using C++11, you'd add this to the ctx struct...

#include <mutex>

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

Now for the actual lock function itself.

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

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

    return NULL;
}

Your unlock function would be something like this...

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

    ctx->unlock();

    assert(id == NULL);
}

And whenever you want to access that pixel data safely...

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

Using SDL

I wanted to add something briefly about SDL. While it can be used to display the video to the screen, you don't need to. Personally, if you're not that experienced, I would suggest you continue to use SDL and remove the display code further down the example. It handles the memory for you in this example, so it's a bit easier than writing your own safe code if you don't know how.

like image 165
AdmiralJonB Avatar answered Oct 04 '22 04:10

AdmiralJonB