Módulo de vídeo basado en VLC

Started by josebita, February 03, 2010, 07:40:39 PM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

josebita

¿Hay alguna forma de convertir esto en una librería de vídeo para Bennu?
He intentado cambiar el código (de forma muy cerda y rápida, sólo estaba mirando si funcionaba o no) con el siguiente código:[code language="c"]/* libSDL and libVLC sample code
* Copyright © 2008 Sam Hocevar <sam@zoy.org>
* license: [http://en.wikipedia.org/wiki/WTFPL WTFPL] */

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>

#include <SDL.h>
#include <SDL_mutex.h>
#include <vlc/vlc.h>

/* BennuGD stuff */
#include <bgddl.h>
#include <xstrings.h>
#include <libgrbase.h>
#include <g_video.h>

#define WIDTH 640
#define HEIGHT 480

#define VIDEOWIDTH 320
#define VIDEOHEIGHT 240

struct ctx
{
    SDL_Surface *surf;
    SDL_mutex *mutex;
};

static char clock[64], cunlock[64], cdata[64];
static char width[32], height[32], pitch[32];
static int w=0,h=0;
static libvlc_exception_t ex;
static libvlc_instance_t *libvlc;
static libvlc_media_t *m;
static libvlc_media_player_t *mp;
static struct ctx video;
static char const *vlc_argv[] =
{
    "-q",
//    "-vvvvv",
    "--ignore-config", /* Don't use VLC's config files */
    "--vout", "vmem",
    "--vmem-width", width,
    "--vmem-height", height,
    "--vmem-pitch", pitch,
    "--vmem-chroma", "RV16",
    "--vmem-lock", clock,
    "--vmem-unlock", cunlock,
    "--vmem-data", cdata,
};
static int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);

static void catch (libvlc_exception_t *ex)
{
    if(libvlc_exception_raised(ex))
    {
        fprintf(stderr, "Exception: %s\n", libvlc_exception_get_message(ex));
        exit(1);
    }

    libvlc_exception_clear(ex);
}

#ifdef VLC09X
static void * lock(struct ctx *ctx)
{
    SDL_LockMutex(ctx->mutex);
    SDL_LockSurface(ctx->surf);
    return ctx->surf->pixels;
}
#else
static void lock(struct ctx *ctx, void **pp_ret)
{
    printf("Called lock\n");
   
    SDL_LockMutex(ctx->mutex);
    SDL_LockSurface(ctx->surf);
    *pp_ret = ctx->surf->pixels;
    printf("Done lock\n");
}
#endif

static void unlock(struct ctx *ctx)
{
    printf ("Called unlock\n");
    /* VLC just rendered the video, but we can also render stuff */
    SDL_UnlockSurface(ctx->surf);
    SDL_UnlockMutex(ctx->mutex);
}

/* Init VLC stuff */
static void vlc_init()
{
    printf("Initializing\n");
    fflush(stdout);

   if(! scr_initialized) gr_init(320, 240);

    /* Create the 16bpp surface that will hold the video */
    video.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, w, h, 16,
            (((Uint32)0xff) >> 3) << 11, (((Uint32)0xff) >> 2) << 5 ,
            ((Uint32)0xff) >> 3, 0);

    sprintf(clock, "%lld", (long long int)(intptr_t)lock);
    sprintf(cunlock, "%lld", (long long int)(intptr_t)unlock);
    sprintf(cdata, "%lld", (long long int)(intptr_t)&video);
    sprintf(width, "%i", VIDEOWIDTH);
    sprintf(height, "%i", VIDEOHEIGHT);
    sprintf(pitch, "%i", VIDEOWIDTH * 2);
   
    printf("Done initializing\n");
    fflush(stdout);
}

/* Stop the VLC lib */
static void vlc_finalize()
{
    /*
     * Stop stream and clean up libVLC
     */
    libvlc_media_player_stop(mp, &ex);
    catch(&ex);

    libvlc_media_player_release(mp);
    libvlc_release(libvlc);

    /*
     * Close window and clean up libSDL
     */
    SDL_DestroyMutex(video.mutex);
    SDL_FreeSurface(video.surf);
}

static int play_video(INSTANCE *my, int * params)
{
    /* The name of the file to play */
    GRAPH *gr = NULL;

    libvlc_exception_init(&ex);
    libvlc = libvlc_new(vlc_argc, vlc_argv, &ex);
    catch(&ex);
    m = libvlc_media_new(libvlc, string_get(params[0]), &ex);
    catch(&ex);
    mp = libvlc_media_player_new_from_media(m, &ex);
    catch(&ex);
    libvlc_media_release(m);
    libvlc_media_player_play(mp, &ex);
    catch(&ex);
    fflush(stdout);
   
    string_discard(params[0]);

    // Create the graphic that will hold the video surface data
    gr = bitmap_new_ex(0, video.surf->w, video.surf->h,
        video.surf->format->BitsPerPixel, video.surf->pixels,
        video.surf->pitch);
    gr->code = bitmap_next_code();
    grlib_add_map(0, gr);
    return gr->code;
}

DLSYSFUNCS __bgdexport( mod_vlc, functions_exports )[] =
{
   {"PLAY_VIDEO", "S"  , TYPE_DWORD , play_video      },
   { NULL        , NULL , 0         , NULL            }
};

char * __bgdexport( mod_vlc, modules_dependency )[] =
{
   "libgrbase",
   "libvideo",
   NULL
};

void __bgdexport( mod_vlc, module_initialize )()
{
    vlc_init();
}

void __bgdexport( mod_vlc, module_finalize )()
{
    vlc_finalize();
}[/code]

Pero me salta siempre con un segfault. ¿Alguna idea de por qué puede ser?. ¿Alguien con más pericia que yo puede echarlo a andar?.

He conseguido que reproduzca el sonido si pongo los punteros a las funciones clock y cunlock como NULL, pero eso no tiene gracia, claro, porque no hay video.

SplinterGU

pone "fflush(stdout);" tras cada printf
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

josebita

En realidad el segmentation fault lo da antes de llamar por primera vez a unlock, el código de inicialización parece funcionar bien.
El código de ejemplo es el siguiente:[code language="bennu"]import "mod_key"
import "mod_vlc"
import "mod_video"
import "mod_mouse"
import "mod_say"

Process main()
Begin
    set_mode(640, 480, 16);
    mouse.graph = play_video("big_buck_bunny_480p_stereo.ogg");
    while(! key(_esc))
        say("Looping!");
        FRAME;
    end;
End;[/code]Y por la consola sale:Initializing
Done initializing
Looping!
[...]
Looping!
TagLib: Vorbis::File::read() - Could not find the Vorbis comment header.
Looping!
[...]
Looping!
Called lock
Done lock
Fallo de segmentación

Se me ocurre que puede ser un problema de bloqueos (VLC es multihilo) o que símplemente estoy haciendo una chapuza con algo que no entiendo del todo.

PD: He actualizado el código del principio para cambiar los printfs de sitio a donde da error.

josebita

Por cierto, la versión de la función de lock que se usa es la segunda. Vamos, que VLC09X NO está definida.

Es más curiosidad que otra cosa, en realidad no estoy pensando usarla -de momento- para nada en particular. Me he cruzado con la página y he pensado si sería capaz de echarlo a andar en Bennu fácilmente... Parece que no :(

SplinterGU

no, no se cae en el lock... da "Done lock" o sea, que salio de la funcion...

creo que el bug lo debes tener en las direcciones de memoria que le pasas...

probaste lanzar uno sin todo eso de la memoria?
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

por otro lado


libvlc_instance_t* libvlc_new     (     int      ,
      const char *const *     ,
      libvlc_exception_t *        
   )          

Create and initialize a libvlc instance.

Parameters:
      argc    the number of arguments
      argv    command-line-type arguments. argv[0] must be the path of the calling program.
      p_e    an initialized exception pointer

Returns:
   the libvlc instance

Todo:
   Look for interface settings. If we don't have any, add -I dummy

References i, libvlc_instance_t::instance_lock, libvlc_deinit_threads(), libvlc_init_threads(), libvlc_InternalCreate(), libvlc_InternalDestroy(), libvlc_InternalInit(), libvlc_instance_t::libvlc_vlm, libvlc_instance_t::p_callback_list, libvlc_vlm_t::p_event_manager, libvlc_instance_t::p_libvlc_int, libvlc_vlm_t::p_vlm, libvlc_vlm_t::pf_release, RAISENULL, libvlc_instance_t::ref_count, libvlc_instance_t::verbosity, VLC_EEXITSUCCESS, and vlc_mutex_init().

Referenced by mediacontrol_new().
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

Windgate

Quotepone "fflush(stdout);" tras cada printf

Anda que no sufrí yo con unas prácticas de C hasta que descubrí eso, porque el profesor no dijo nada :S

Era printf sobre fichero, pero vamos... Recuerdo noches sin dormir para presentar la cosa funcionando y a tiempo.

Perdón por el offtopic, habéis escrito muchísimo, lo miraré con más tiempo.
Iván García Subero. Programador, profesor de informática, monitor de actividades culturales y presidente de TRINIT Asociación de Informáticos de Zaragoza. http://trinit.es

osk

Ostras, qué bueno sería poderlo hacer funcionar!!
Por fin una librería de video completa para Bennu!!

josebita

#8
Puede que la dirección que le paso esté mal, es lo que me estaba temiendo (¿o quizás la dirección cambia cada vez que se llama a alguna función de la lib y por eso falla?. ¿Podría ser que -si ese es el problema- eso se arreglara con alguna opción de compilación?.).

Además libvlc usa esa función para obtener el puntero a los píxeles donde escribe, así que tengo que poder acceder a esos datos de alguna forma.

A ver si mañana busco un poco más y encuentro la forma de hacerlo más simple que como lo hago ahora, gracias por la ayuda.

DCelso

puedes usar mod_smpeg como base, no creo que haya mucha dificultad en adaptarlo
Monstruos Diabólicos

"A PAck of classic GAMEs For BennuGD" en desarrollo
http://code.google.com/p/apagame4be/

josebita

#10
Soy un yonki. No me he podido aguantar hasta mañana. ¡Pero ya funciona!.
El problema era que estaba poniendo la altura y anchura de la SDL_Surface a 0 y se quejaba.
[code language="c"]/* libSDL and libVLC sample code
* Copyright © 2008 Sam Hocevar <sam@zoy.org>
* license: [http://en.wikipedia.org/wiki/WTFPL WTFPL] */

#include <stdio.h>
#include <stdint.h>
#include <math.h>
#include <stdlib.h>

#include <SDL.h>
#include <SDL_mutex.h>
#include <vlc/vlc.h>

/* BennuGD stuff */
#include <bgddl.h>
#include <xstrings.h>
#include <libgrbase.h>
#include <g_video.h>

#define WIDTH 640
#define HEIGHT 480

#define VIDEOWIDTH 320
#define VIDEOHEIGHT 240

struct ctx
{
   SDL_Surface *surf;
   SDL_mutex *mutex;
};

static char clock[64], cunlock[64], cdata[64];
static char width[32], height[32], pitch[32];
static libvlc_exception_t ex;
static libvlc_instance_t *libvlc;
static libvlc_media_t *m;
static libvlc_media_player_t *mp;
static struct ctx video;
static char const *vlc_argv[] =
{
   "-q",
//    "-vvvvv",
   "--ignore-config", /* Don't use VLC's config files */
   "--vout", "vmem",
   "--vmem-width", width,
   "--vmem-height", height,
   "--vmem-pitch", pitch,
   "--vmem-chroma", "RV16",
   "--vmem-lock", clock,
   "--vmem-unlock", cunlock,
   "--vmem-data", cdata,
};
static int vlc_argc = sizeof(vlc_argv) / sizeof(*vlc_argv);

static void catch (libvlc_exception_t *ex)
{
   if(libvlc_exception_raised(ex))
   {
       fprintf(stderr, "Exception: %s\n", libvlc_exception_get_message(ex));
       exit(1);
   }

   libvlc_exception_clear(ex);
}

#ifdef VLC09X
static void * lock(struct ctx *ctx)
{
   SDL_LockMutex(ctx->mutex);
   SDL_LockSurface(ctx->surf);
   return ctx->surf->pixels;
}
#else
static void lock(struct ctx *ctx, void **pp_ret)
{
   SDL_LockMutex(ctx->mutex);
   SDL_LockSurface(ctx->surf);
   *pp_ret = ctx->surf->pixels;
}
#endif

static void unlock(struct ctx *ctx)
{
   /* VLC just rendered the video, but we can also render stuff */
   SDL_UnlockSurface(ctx->surf);
   SDL_UnlockMutex(ctx->mutex);
}

/* Init VLC stuff */
static void vlc_init()
{
   printf("Initializing\n");
   fflush(stdout);

   if(! scr_initialized) gr_init(320, 240);

   /* Create the 16bpp surface that will hold the video */
   video.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, VIDEOWIDTH, VIDEOHEIGHT, 16,
           (((Uint32)0xff) >> 3) << 11, (((Uint32)0xff) >> 2) << 5 ,
           ((Uint32)0xff) >> 3, 0);
   video.mutex = SDL_CreateMutex();

   sprintf(clock, "%lld", (long long int)(intptr_t)lock);
   sprintf(cunlock, "%lld", (long long int)(intptr_t)unlock);
   sprintf(cdata, "%lld", (long long int)(intptr_t)&video);
   sprintf(width, "%i", VIDEOWIDTH);
   sprintf(height, "%i", VIDEOHEIGHT);
   sprintf(pitch, "%i", VIDEOWIDTH * 2);
   
   printf("Done initializing\n");
   fflush(stdout);
}

/* Stop the VLC lib */
static void vlc_finalize()
{
   /*
    * Stop stream and clean up libVLC
    */
   libvlc_media_player_stop(mp, &ex);
   catch(&ex);

   libvlc_media_player_release(mp);
   libvlc_release(libvlc);

   /*
    * Close window and clean up libSDL
    */
   SDL_DestroyMutex(video.mutex);
   SDL_FreeSurface(video.surf);
}

static int play_video(INSTANCE *my, int * params)
{
   /* The name of the file to play */
   GRAPH *gr = NULL;

   libvlc_exception_init(&ex);
   libvlc = libvlc_new(vlc_argc, vlc_argv, &ex);
   catch(&ex);
   m = libvlc_media_new(libvlc, string_get(params[0]), &ex);
   catch(&ex);
   mp = libvlc_media_player_new_from_media(m, &ex);
   catch(&ex);
   libvlc_media_release(m);
   libvlc_media_player_play(mp, &ex);
   catch(&ex);
   
   string_discard(params[0]);

   // Create the graphic that will hold the video surface data
   gr = bitmap_new_ex(0, video.surf->w, video.surf->h,
       video.surf->format->BitsPerPixel, video.surf->pixels,
       video.surf->pitch);
   gr->code = bitmap_next_code();
   grlib_add_map(0, gr);
   return gr->code;
}

DLSYSFUNCS __bgdexport( mod_vlc, functions_exports )[] =
{
   {"PLAY_VIDEO", "S"  , TYPE_DWORD , play_video      },
   { NULL        , NULL , 0         , NULL            }
};

char * __bgdexport( mod_vlc, modules_dependency )[] =
{
   "libgrbase",
   "libvideo",
   NULL
};

void __bgdexport( mod_vlc, module_initialize )()
{
   vlc_init();
}

void __bgdexport( mod_vlc, module_finalize )()
{
   vlc_finalize();
}[/code]El código de ejemplo que he usado es:[code language="bennu"]import "mod_key"
import "mod_vlc"
import "mod_video"
import "mod_mouse"
import "mod_say"
import "mod_map"

Process main()
Begin
   dump_type=complete_dump; restore_type=complete_restore;
   set_mode(640, 480, 16);
   mouse.graph = play_video("big_buck_bunny_480p_stereo.ogg");
   graph = mouse.graph;
   flags = B_HMIRROR;
   x = 320;
   y = 240;
   while(! key(_esc))
   // Uncomment to take screenshots
       //save_png(0, mouse.graph, "shot.png");
       angle += 50;
       FRAME;
   end;
End;[/code]Lo que más mola es que además de para vídeos vale para webcams, DVDs y en general cualquier cosa que VLC pueda reproducir...

Splinter, si te mola esto y quisieras convertirlo en un módulo oficial, yo más contento que unas pascuas. Si no, con tiempo lo intentaré limpiar y mejorar (pero seguro que tú eres capaz de hacerlo mucho mejor y dejarlo muy limpito).

¡Ah! ¡y el rendimiento parece bastante bueno!.

[Edito] He cambiado el código de ejemplo por uno un poquito más complejo que muestra que realmente funciona.
¡Screenshot!.


Prg

se ve increible, y mejor que funciona también en linux :)
funcionará en windows vd?
wow, como leí en otro post: atáquenlo con karmas  :D
en humos puedes mover la camara con los cursores. es necesario para los niveles a partir del dos :)

josebita

Debe funcionar en todos los sitios en que funcione VLC, así que sí, funcionará en Windows.

SplinterGU

jo, jo... lo incluire... muchas gracias... voy a investigar que plataformas estan incluidas...

mañana le echo un ojo... gracias...


ahi fue un karma, obvio.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2

SplinterGU

tambien estaba el de dcelso si mal no recuerdo... voy a pegar revision y ver que necesitan modificar cada 1, y luego veo si incluyo a los 2...

gracias.
Download Lastest BennuGD Release: http://www.bennugd.org/node/2