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

Esa es otra, claro...
En principio si la Wiz usa ALSA o algo así no debería haber problema, ¿no?.

Por cierto que la lista de dependencias (para VLC) se reduciría si sólo quisieramos integrar soporte para Theora+Vorbis, claro.

josebita

#31
He estado trabajando un poquito en esto. He limpiado un poco el código y le he dicho a la libVLC que use los subtítulos para los vídeos, si los encuentra. De momento sólo puede reproducir un vídeo cada vez.
No debería romperse en caso de que se le pida reproducir más (antes sí se rompía) pero se negará a reproducir.

House!


PD: Si saco un rato, la intentaré compilar para Windows.

FreeYourMind

Heeheh, parece que mis opiniones dan resultado, sólo hay que inventarme que voy hacer algo al respecto y os pongo automaticamente a trabajar como locos para sacarlo antes :)

El truquillo parece que ha vuelto a funcionar, con este ya van dos (DCElso ha picado antes  ;)).

Que malo soy con mis técnicas de poneros a currar para Bennu  ;D
Venga, karma up, sólo por hacer que vuelvas a tocarlo (y si dices que no ha sido por eso, me pongo a jugar al euromillones que seguro que me sale).

josebita

#33
El código, por si alguien lo qiuere:
[code language="c"]/* libVLC module for BennuGD
* Heavily based on the libVLC+libSDL example by Sam Hocevar <sam@zoy.org>
* Copyright © 2010 Joseba García Etxebarria <joseba.gar@gmail.com>
*
*  This program is free software: you can redistribute it and/or modify
*  it under the terms of the GNU General Public License as published by
*  the Free Software Foundation, either version 3 of the License, or
*  (at your option) any later version.
*
*  This program is distributed in the hope that it will be useful,
*  but WITHOUT ANY WARRANTY; without even the implied warranty of
*  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
*  GNU General Public License for more details.
*
*  You should have received a copy of the GNU General Public License
*  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/


#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>

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=NULL;
static struct ctx video;
static int playing_video=0;
static char const *vlc_argv[] =
{
   "-q",
//    "-vvvvv",
   "--ignore-config", /* Don't use VLC's config files */
   "--no-video-title-show",
   "--sub-autodetect-file",
   "--vout", "vmem",
   "--plugin-path", "vlc" /* For win32 */
   "--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);
}

/*********************************************/
/* Plays the given video with libVLC         */
/* Must be given:                            */
/*    filename to be played                  */
/*    width  of the video to render          */
/*    height of the video to render          */
/*********************************************/
static int play_video(INSTANCE *my, int * params)
{
   /* Ensure we're not playing a video already */
   if(playing_video == 1)
       return -1;

   /* Start the graphics mode, if not initialized yet */
   if(! scr_initialized) gr_init(320, 240);

   /* Create the 16bpp surface that will hold the video          */
   /* We don't yet support 32bpp surfaces, but this'll work fine */
   /* in bennugd's 32bpp video mode.                             */
   video.surf = SDL_CreateRGBSurface(SDL_SWSURFACE, params[1],
           params[2], 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", params[1]);
   sprintf(height, "%i", params[2]);
   sprintf(pitch, "%i", params[1] * 2);

   /* This could really be done earlier, but we need to know the      */
   /* video width/height before doing it and we'd have to use default */
   /* values for them.                                                */
   libvlc_exception_init(&ex);
   libvlc = libvlc_new(vlc_argc, vlc_argv, &ex);
   catch(&ex);

   /* The name of the file to play */
   GRAPH *gr = NULL;

   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);

   /* Discard the file path, as we don't need it */
   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);

   /* Lock the video playback */
   playing_video = 1;
   
   return gr->code;
}

static int stop_video(INSTANCE *my, int * params)
{
   if(! playing_video)
       return 0;

   /* Stop the playback and release the media */
   if(mp) {
       libvlc_media_player_stop(mp, &ex);
       catch(&ex);
   
       libvlc_media_player_release(mp);
   }
   
   /* Clean up SDL */
   if(video.mutex) SDL_DestroyMutex(video.mutex);

   if(video.surf)  SDL_FreeSurface(video.surf);

   if(libvlc)      libvlc_release(libvlc);

   /* Release the video playback lock */
   playing_video = 0;        

   return 0;
}

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

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

void __bgdexport( mod_vlc, module_finalize )()
{
   stop_video(NULL, NULL);
}[/code]
[code language="bennu"]import "mod_key"
import "mod_vlc"
import "mod_video"
import "mod_mouse"
import "mod_say"
import "mod_map"
import "mod_file"
import "mod_proc"

#define SCR_WIDTH  640
#define SCR_HEIGHT 480

/* Player main window */
Process main()
Private
    string fname="";
Begin
    // Handle the command line
    if(argc != 2)
        say("Must be given file to play, quitting.");
        exit();
    end;

    // Try to find the file that the user wants us to play, or die
    fname = argv[1];
    if(! fexists(fname))
        say("Couldn't find "+fname+" to be played, quitting.");
        exit();
    end

    /* This is required to ensure Bennu redraws every frame */
    dump_type=complete_dump;
    restore_type=complete_restore;

    /* Start the graphics subsystem */
    set_mode(SCR_WIDTH, SCR_HEIGHT, 16);

    /* Finally play the video and place it in the middle of the screen */
    graph = play_video(fname, SCR_WIDTH, SCR_HEIGHT);
    x = SCR_WIDTH/2;
    y = SCR_HEIGHT/2;
    while(! key(_esc))
       // Uncomment to dump frames
        //save_png(0, graph, "shot.png");
        FRAME;
    end;

    stop_video();
End;[/code]


@FreeYourMind: Fue en parte por tus comentarios, sí. Pero tenía ganas de tocarlo de todas formas. Qudan muchas cosas por hacer (seeking, por ejemplo) pero lo básico está ahí.
Ahora, cuando me ponga otra vez con la fmodex, no te apunets el tanto :P

josebita

Parece ser que hoy no sé escribir. Me niego a arreglar todas las letras que he puesto en sitios que no son...

FreeYourMind

Heeheheh, lo sabia! Lo sabia!  ;D
Suerte con ello, yo ya estoy sobrao de proyectos, pero si necesitas que pruebe algo en Windows se puede echar una mano.

josebita

Venga, he añadido un montón de funciones y he renombrado unas pocas. Perdón por ponerlo en inglés, pero así se queda ya de documentación del módulo.
[code language="bennu"]
/* Plays a video file with the given width/height
* Will play the video with subtitles, if found */
int video_play(string filename, int width, int height);

/* Stop a currently playing video.*/
int video_stop();

/* Pause/unpause the currently playing video*/
int video_pause();

/* Check if the video is currently playing */
int video_is_playing();

/* Get total length of the currentyl playing video, in centisecs */
int video_get_length();

/* Get current seeking position in the video, in centiseconds */
int video_get_time();

/* Seek through the video, must be given a time
* in centiseconds (what the bennu timer's use) */
int video_set_time(int time);

/* Get the width of the currently playing video */
int video_get_width();

/* Get the height of the currently playing video */
int video_get_height();

/* Get the muted/unmuted status */
int video_get_mute();

/* Mute/unmute the currently being played video */
int video_mute();

/* Get the volume of the currently playing video
* Will be 0<=volume<=200 */
int video_get_volume();

/* Set the volume of the currently playing video
* Must be 0<=volume<=200 */
int video_set_volume(int volume);

/* Get the number of available tracks in the video
* The first track (track number 0) is used for disabling audio */
int video_get_tracks();

/* Get the number of the currently being played track */
int video_get_track();

/* Set the audio track for a currently being played video */
int video_set_track(int track);

/* Get the description for an audio track.
* Not sure if it works correctly, must test it. */
string video_get_track_description();
[/code]

Os adjunto el código fuente con un programa de ejemplo (para Linux) que se llama desde la consola como;
bgdi main.dcb fichero_a_reproducir
Las teclas del programa son:

  • Space bar: Pauses/unpauses the video.
  • Right: Seek the video to the right.
  • Left: Seek left.
  • m: Mute/Unmute the video.
  • up: Volume Up.
  • down: Volume down.
  • enter: Switch audio track.
  • escape: Stop+quit.

PD: Renombrad el adjunto a .tar.bz2, cosas del foro y los adjuntos.

l1nk3rn3l

PODRIAS pasarme la version con la que compilas y la direccion de
los binarios .. para compilar en win32..

es que la compilo en windows y me vota un error en la consola ..

me dice que los parametros :


   "--vout", "vmem",
   "--vmem-width", width,
   "--vmem-height", height,
   "--vmem-pitch", pitch,
   "--vmem-chroma", "RV16",
   "--vmem-lock", clock,
   "--vmem-unlock", cunlock,
   "--vmem-data", cdata,

no son soportados por esta version de VLC..

lo raro es que lo compilo con la version 1.0 como dice la nota

NOTE: this requires the "vmem" video output which was checked in on March 21st, 2008. Update Nov 28th, 2008 to work with vlc-1.0.0(git).

podrias pasarme las dlls y include de win32 de donde lo bajaste ..
no me funciona

josebita

Pues la verdad es que no lo he compilado en Windows.
En linux estoy usando la versión 1.0.5 de VLC que viene con Ubuntu y las cabeceras son tb. las que vienen con él (paquete vlc, libvlc-dev, libvlccore-dev y sus dependencias, que son unas cuantas).

Mañana por la mañana saco un rato y la compilo para Windows, ¿ok?.

josebita

Se me ocurre una cosa: hay un parámetro de la lista llamado "--plugin-path" que tiene -en mi código- el valor "vlc".
Se trata de la ruta donde deben estar los plugins de vlc. Prueba a copiar todo el contenido del directorio del VLC (aunque no hagan falta todos lo ficheros, eso lo miramos luego) al directorio donde estés ejecutando el ejemplo. Renombra el directorio de plugins a "vlc" y mira a ver si entonces funciona.

Otra forma de intentarlo: Entiendo por lo que dices que has sido capaz de compilarlo para windows, ¿no?.
Si quieres, deja el fichero del módulo compilado para windows en el foro y te intento mirar hoy a ver si puedo con un ordenador muy viejo que tengo con windows.

josebita

#40
Quote from: josebita on March 16, 2010, 10:09:48 PM
Se me ocurre una cosa: hay un parámetro de la lista llamado "--plugin-path" que tiene -en mi código- el valor "vlc".
Se trata de la ruta donde deben estar los plugins de vlc. Prueba a copiar todo el contenido del directorio del VLC (aunque no hagan falta todos lo ficheros, eso lo miramos luego) al directorio donde estés ejecutando el ejemplo. Renombra el directorio de plugins a "vlc" y mira a ver si entonces funciona.

[...]

Efectivamente era eso.
Os pongo la librería compilada para Windows contra el Bennu RC11 con el código del reproductor de ejemplo. Las librerías del VLC que incluyen son las del VLC 1.0.5. Además, incluye el script de compilación modificado para compilar en mingw32 y el código fuente.
Un par de cosas importantes:
* No renombrar el directorio "vlc" porque si no, no podrá encontrar los módulos y no se reproducirán los vídeos. Habría que recompilar el módulo.

* Casi seguro que sobran módulos de la carpeta "vlc" podeis quitar los que no os hagan falta. He metido todos por si a alguien le hace falta soporte para ver su webcam o cosas así.
Si quitais módulos inútiles, se os queda en un tamaño decente.

* El tamaño a que se quiere renderizar el vídeo no es automático. Se fija cuando se le da a play_video. Una vez que el vídeo está en reproducción, ya se puede averiguar cuál es el tamaño real. Si quereis poner un vídeo con el aspect-ratio correcto, debeis reproducirlo (si quereis ponerle el mute, seguro que no hace daño), averiguar sus dimensiones con video_get_width y video_get_height y pararlo. Depués volver a echarlo a andar con el aspecto correcto.

Espero que os sea útil. No está acabada pero ya es más que funcional.
http://www.mediafire.com/?yijlmwyzcly

l1nk3rn3l


Prg

la he probado en windows con un flv y esta genial me encanta que tenga controles, pausa y todas las opciones que le has puesto :) gracias y karma++
en humos puedes mover la camara con los cursores. es necesario para los niveles a partir del dos :)

josebita

Lo único que creo que me falta respecto de las capacidades que da la libvlc (y que son directamente aplicables a un módulo Bennu de esta clase) es poder controlar los subtítulos.
Ahora mismo los subtítulos se activan si hay un fichero .srt con el mismo nombre que el .avi y en la misma carpeta, pero estaría bien que se pudiera elegir desde el propio Bennu.

Espero que os sea útil. Si alguien se encuentra con un error que dice algo como "Exception: video playback not started" que lo avise y le digo como arreglarlo :)

SplinterGU

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