5

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!

user2273364
  • 65
  • 1
  • 7
  • Why do you want to do it without SDL? What do you want to use instead? – olevegard May 13 '13 at 08:48
  • I don't want to show the video. I only want to use LibVLC to write the frames to a file. I found that `libvlc_video_set_callbacks` can be used for that which is shown in this tutorial, but I think I don't need SDL for my purpose. – user2273364 May 13 '13 at 08:52
  • Maybe you don't need it, but it will make it easier. You can easily grab pixel information from the SDL_Surface. If you want to remove the video you can easily do it by commenting out the following code. `SDL_LockMutex(ctx.mutex); SDL_BlitSurface(ctx.surf, NULL, screen, &rect); SDL_UnlockMutex(ctx.mutex);` – olevegard May 13 '13 at 09:11

1 Answers1

8

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.

AdmiralJonB
  • 2,038
  • 3
  • 23
  • 27
  • Try changing your line 136 on the pastebin to only have SDL_INIT_VIDEO in the if statement. If you aren't displaying it to the screen, you might be able to remove that whole if statement as I think it's only needed for displaying video. – AdmiralJonB May 15 '13 at 18:27