Учебник LibVLC без SDL?

Я пытаюсь записать видео кадр за кадром в файл *.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?

Как вы понимаете, я не очень опытный программист, так что будьте терпеливы со мной ;)
Заранее спасибо!


person user2273364    schedule 13.05.2013    source источник
comment
Почему вы хотите сделать это без SDL? Что вы хотите использовать вместо этого?   -  person olevegard    schedule 13.05.2013
comment
Я не хочу показывать видео. Я хочу использовать LibVLC только для записи кадров в файл. Я обнаружил, что libvlc_video_set_callbacks можно использовать для того, что показано в этом руководстве, но я думаю, что для моей цели мне не нужен SDL.   -  person user2273364    schedule 13.05.2013
comment
Может быть, вам это и не нужно, но так будет проще. Вы можете легко получить информацию о пикселях из SDL_Surface. Если вы хотите удалить видео, вы можете легко сделать это, закомментировав следующий код. SDL_LockMutex(ctx.mutex); SDL_BlitSurface(ctx.surf, NULL, screen, &rect); SDL_UnlockMutex(ctx.mutex);   -  person olevegard    schedule 13.05.2013


Ответы (1)


Я действительно не знаю libvlc, но вот как вы можете удалить SDL на основе этого конкретного примера.

Удаление SDL

В этом примере есть несколько различных функций, которые вы должны передать в функция обратного вызова libvlc...

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

Теперь, чтобы полностью понять, что делает эта функция блокировки, вам нужно немного разобраться в многопоточности и в том, как изображение хранится в памяти.

  • По сути, чтобы убедиться, что ничто не обращается к области памяти, которую libvlc использует во время записи в нее, он «блокирует» нечто, известное как мьютекс. Если вы попытаетесь заблокировать мьютекс, который уже заблокирован чем-то другим, текущее выполнение будет ждать, пока он не будет разблокирован.

    Если бы вы получили доступ к этим пикселям, пока он был наполовину написан, можете ли вы представить, насколько это было бы ужасно? Он может быть написан наполовину, и вы затем будете использовать его для сохранения в файл yuv. Это было бы весьма катастрофично.

  • Второе, что делает функция блокировки, — указывает область памяти, которую vlc может использовать для загрузки кадра изображения. В этом примере для этого используется SDL_Surface, но вы можете создать свою собственную если будете осторожны.

Итак, если вы используете только libvlc, вам нужно найти альтернативу этим вещам.


Я пойду в обратном порядке от списка выше. В примере они используют SDL_Surface, однако, если вы не можете его использовать, вам придется создать свою собственную структуру в памяти для хранения данных пикселей, если вы хотите их извлечь. Простой способ — создать массив символов правильного размера. Я буду использовать структуру 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. Если это не так, вам придется найти что-то еще, например библиотеку многопоточности. или написать что-то подобное самостоятельно. Если вы используете С++ 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 и удалить код отображения далее в примере. В этом примере он обрабатывает память за вас, поэтому это немного проще, чем писать собственный безопасный код, если вы не знаете, как это сделать.

person AdmiralJonB    schedule 13.05.2013
comment
Попробуйте изменить строку 136 в pastebin, чтобы в операторе if был только SDL_INIT_VIDEO. Если вы не отображаете его на экране, вы можете удалить весь этот оператор if, поскольку я думаю, что он нужен только для отображения видео. - person AdmiralJonB; 15.05.2013