Vlad: Home:   Demo User Mon, 15 Mar 2010 10:52:19
Home
About
    Reading
    Shooting
    Pictures
Forums
Software
    vTranslator
    OSSWEB
    OSSMON
    Maverix
    LMBOX
    Naviserver
News
Weather

  1. Insert USB stick, check dmesg for device, for example /dev/sga
  2. Run fdisk and create FAT16 bootable partition
  3. Downloa bootable MSDOS floppy image from http://www.bootdisk.com/, save as msdos.img
  4. Run qemu -fda msdos.img -hda /dev/sga -boot a
  5. When MSDOS booted, in the DOS prompt execute format /s c:
  6. The bootable disk is created on USB flash


Due to lack of small dockable volume control app, here it is one. This is simple GTK mixer app that runs in the background exposing icon in system tray. It works similar to Windows volume or Mac OSX volume but just adjust volume, nothing else.

ftp://ftp.crystalballinc.com/pub/vlad/mixer.tar.gz

 



This is a little modules that makes embedding VLc with SDL applications much easier. The basic idea is to have VLc perform decoding and rendering video and pass final frames to us as RGB pictures. Our applicarton will just blit those pictures with our screen or other surfaces. Currently VLC already has SDL module but this module assume full control but we want just little embedded video window without implementing full media player functionality.

First is VLC vout module, the only thing it does is to register itself as vout plugin and take output picture parameters from our application. With parameters we pass display callback function which will be called by VLc for every frame, then it is up to us where and how we want that frame displayed.

Source code for the plugin follows below:


/*****************************************************************************
* vlc_vout_embed.c: Embedded video output display method
*****************************************************************************
* Copyright (C) 1998-2001 the VideoLAN team
* $Id: embed.c 16987 2006-10-08 12:54:12Z vlad $
*
* Authors: Vlad Seryakov 
*
* 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 2 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, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301, USA.
*****************************************************************************/
/*****************************************************************************
* Preamble
*****************************************************************************/
#include                                                  /* ENOMEM */
#include                                                 /* free() */
#include                                             /* strerror() */
#include 
#include 
#include 
#include 
#define MAX_DIRECTBUFFERS 3
/*****************************************************************************
* vout_sys_t: video output method descriptor
*****************************************************************************
* This structure is part of the video output thread descriptor.
* It describes the video picture properties of an output thread.
*****************************************************************************/
struct vout_sys_t
{
int changed;             // needs to be set to 0 after init
int x;                   // x position of the video picture
int y;                   // y position of the video picture
int w;                   // width of the target surface
int h;                   // height of the target surface
int bpp;                 // bits per pixel
int pitch;               // target image pitch (size of one line)
int aspect;              // final aspect ratio
unsigned int rmask;
unsigned int gmask;
unsigned int bmask;
// This routine will be called with rendered picture for actual display,
// arg is pointer to this structure which may have more fields below
// If pixels == NULL, it means end of stream
int (*callback)(void *arg, void *pixels);
};
/*****************************************************************************
* Local prototypes
*****************************************************************************/
static int  Open      (vlc_object_t *);
static void Close     (vlc_object_t *);
static int  Init      (vout_thread_t *);
static void End       (vout_thread_t *);
static void Display   (vout_thread_t *, picture_t *);
/*****************************************************************************
* Module descriptor
*****************************************************************************/
vlc_module_begin();
set_shortname("Embed");
set_category(CAT_VIDEO);
set_subcategory(SUBCAT_VIDEO_VOUT);
set_description(_("Embedded RGB video output"));
set_capability("video output", 200);
add_shortcut("embed");
set_callbacks(Open, Close);
var_Create(p_module->p_libvlc, "embed", VLC_VAR_MUTEX);
vlc_module_end();
/*****************************************************************************
* OpenVideo: allocate video thread output method
*****************************************************************************/
static int Open (vlc_object_t *p_this)
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
vlc_value_t lockval, val;
var_Get(p_this->p_libvlc, "embed", &lockval);
vlc_mutex_lock(lockval.p_address);
p_vout->pf_init = Init;
p_vout->pf_end = End;
p_vout->pf_manage = NULL;
p_vout->pf_render = NULL;
p_vout->pf_display = Display;
var_Get(p_vout->p_vlc, "drawable", &val);
p_vout->p_sys = (void*)val.i_int;
p_vout->p_sys->changed = 0;
vlc_mutex_unlock(lockval.p_address);
msg_Warn(p_vout, "open: %dx%d, bpp=%d, pitch=%d", 
p_vout->p_sys->w, p_vout->p_sys->h, p_vout->p_sys->bpp, p_vout->p_sys->pitch);
return VLC_SUCCESS;
}
/*****************************************************************************
* Init: initialize video thread output method
*****************************************************************************/
static int Init(vout_thread_t *p_vout)
{
int i, x, y, w, h;
picture_t *p_pic;
I_OUTPUTPICTURES = 0;
switch (p_vout->p_sys->bpp) {
case 15:
p_vout->output.i_chroma = VLC_FOURCC('R','V','1','5');
break;
case 16:
p_vout->output.i_chroma = VLC_FOURCC('R','V','1','6');
break;
case 24:
p_vout->output.i_chroma = VLC_FOURCC('R','V','2','4');
break;
case 32:
p_vout->output.i_chroma = VLC_FOURCC('R','V','3','2');
break;
default:
msg_Err(p_vout, "unknown screen depth %i", p_vout->p_sys->bpp);
return VLC_EGENERIC;
}
p_vout->output.i_width  = p_vout->p_sys->w;
p_vout->output.i_height = p_vout->p_sys->h;
p_vout->output.i_aspect = p_vout->render.i_aspect;
p_vout->output.i_rmask = p_vout->p_sys->rmask;
p_vout->output.i_gmask = p_vout->p_sys->gmask;
p_vout->output.i_bmask = p_vout->p_sys->bmask;
// Calculate picture size and correct aspect ratio
vout_PlacePicture(p_vout, p_vout->p_sys->w, p_vout->p_sys->h, &x, &y, &w, &h);
p_vout->fmt_out.i_x_offset = p_vout->p_sys->x = x;
p_vout->fmt_out.i_y_offset = p_vout->p_sys->y = y;
p_vout->output.i_width = p_vout->fmt_out.i_width = p_vout->p_sys->w = p_vout->fmt_out.i_visible_width = w;
p_vout->output.i_height = p_vout->fmt_out.i_height = p_vout->p_sys->h = p_vout->fmt_out.i_visible_height = h;
p_vout->output.i_aspect = p_vout->fmt_out.i_aspect = p_vout->p_sys->aspect = 
p_vout->fmt_out.i_width * VOUT_ASPECT_FACTOR / p_vout->fmt_out.i_height;
msg_Info(p_vout, "init: %dx%d, bpp=%d, pitch=%d, orig=%dx%d/%d, out=%dx%d/%d, vis=%dx%d pos=%d/%d",
p_vout->p_sys->w, p_vout->p_sys->h, p_vout->p_sys->bpp, p_vout->p_sys->pitch,
p_vout->render.i_width, p_vout->render.i_height, p_vout->render.i_aspect,
p_vout->output.i_width, p_vout->output.i_height, p_vout->output.i_aspect,
p_vout->fmt_out.i_visible_width, p_vout->fmt_out.i_visible_height,
p_vout->fmt_out.i_x_offset, p_vout->fmt_out.i_y_offset);
while (I_OUTPUTPICTURES < MAX_DIRECTBUFFERS) {
p_pic = NULL;
/* Find an empty picture slot */
for (i = 0; i < VOUT_MAX_PICTURES; i++) {
if (p_vout->p_picture[i].i_status == FREE_PICTURE) {
p_pic = p_vout->p_picture + i;
break;
}
}
if (p_pic == NULL) {
break;
}
switch (p_vout->p_sys->bpp) {
case 15:
case 16:
p_pic->p->i_pixel_pitch = 2;
break;
case 24:
case 32:
p_pic->p->i_pixel_pitch = 4;
break;
}
p_pic->p->i_pitch = p_vout->p_sys->pitch;
p_pic->p->p_pixels = malloc(p_vout->p_sys->h * p_vout->p_sys->pitch);
p_pic->p->i_lines = p_vout->p_sys->h;
p_pic->p->i_visible_lines = p_vout->p_sys->h;
p_pic->p->i_visible_pitch = p_pic->p->i_pixel_pitch * p_vout->p_sys->w;
p_pic->i_planes = 1;
p_pic->i_status = DESTROYED_PICTURE;
p_pic->i_type = DIRECT_PICTURE;
PP_OUTPUTPICTURE[I_OUTPUTPICTURES] = p_pic;
I_OUTPUTPICTURES++;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* End: terminate video thread output method
*****************************************************************************/
static void End(vout_thread_t *p_vout)
{
int i;
for (i = 0; i <= I_OUTPUTPICTURES - 1; i++) {
free(PP_OUTPUTPICTURE[i]->p->p_pixels);
}
msg_Warn(p_vout, "end: %dx%d, bpp=%d, pitch=%d", 
p_vout->p_sys->w, p_vout->p_sys->h, p_vout->p_sys->bpp, p_vout->p_sys->pitch);
}
/*****************************************************************************
* CloseVideo: destroy video thread output method
*****************************************************************************/
static void Close (vlc_object_t *p_this)
{
vout_thread_t *p_vout = (vout_thread_t *)p_this;
msg_Info(p_vout, "close: %dx%d, bpp=%d, pitch=%d", 
p_vout->p_sys->w, p_vout->p_sys->h, p_vout->p_sys->bpp, p_vout->p_sys->pitch);
(*p_vout->p_sys->callback)(p_vout->p_sys, NULL);
}
/*****************************************************************************
* Display: displays previously rendered output
*****************************************************************************/
static void Display(vout_thread_t *p_vout, picture_t *p_pic)
{
switch ((*p_vout->p_sys->callback)(p_vout->p_sys, p_pic->p->p_pixels)) {
case 1:
p_vout->i_changes |= (VOUT_SIZE_CHANGE|VOUT_ASPECT_CHANGE);
p_vout->i_window_width = p_vout->p_sys->w;
p_vout->i_window_height = p_vout->p_sys->h;
msg_Info(p_vout, "changed: %dx%dx%dx%d, bpp=%d, pitch=%d, aspect=%d", 
p_vout->p_sys->x, p_vout->p_sys->y, p_vout->p_sys->w, p_vout->p_sys->h, 
p_vout->p_sys->bpp, p_vout->p_sys->pitch, p_vout->output.i_aspect);
break;
}
}

To show how this plugin can be used, small SDL example is provided as well, this is very basic video player. When it registers VLC object, it passes plugin path as current directory, this trick will allow VLC to load our new plugin without installing it into VLC system directory.

In this example we render video frames directly into screen but it is very easy to create another SDL surface and blit video frames there and then do some overlays and finaly blit everything into the screen surface. I only show how resize works by changing surface on the fly and telling VLC to re-open itself with new dimensions.


 
/*
*  Author: Vlad Seryakov vlad@mpowermedia.net
*  April 2007
*
*/
#include "SDL.h"
#include "SDL_thread.h"
#include "SDL_mutex.h"
#include "SDL_syswm.h"
#include "SDL_error.h"
#include "SDL_video.h"
#include "SDL_endian.h"
#include 
// Param structure for custom embed VLC vout module which renders RGB frames
// directly into pixel buffer
typedef struct voutEmbed {
int changed;                           // To signal changes to the window or dimensions
int x;                                 // Where to place frame
int y;
int w;                                 // Dimensions of the frame
int h;
int bpp;                               // Bits per pixel
int pitch;                             // Size of one frame line
int aspect;                            // Picture aspect
unsigned int rmask;
unsigned int gmask;
unsigned int bmask;
int (*display)(void *arg, void *pixels);
} voutEmbed;
static void setup(voutEmbed *param);
static int display(void *arg, void *pixels);
SDL_Surface *screen;
SDL_mutex *lock;
voutEmbed param;
int running = 1;
int vlc;
// Supply input parametyers to the vout module, we need to pass primary
// output picture charasteristics only, vout module will update other fields with
// calculated values
static void setup(voutEmbed *param)
{
vlc_value_t val;
SDL_LockMutex(lock);
memset(param, 0, sizeof(voutEmbed));
param->changed = 1;
param->w = screen->w;
param->h = screen->h;
param->pitch = screen->pitch;
param->bpp = screen->format->BitsPerPixel;
param->rmask = screen->format->Rmask;
param->gmask = screen->format->Gmask;
param->bmask = screen->format->Bmask;
param->display = display;
val.i_int = (int)param;
VLC_VariableSet(vlc, "drawable", val);
SDL_UnlockMutex(lock);
}
// Display callback is called by vlc vout module with ready frame
static int display(void *arg, void *pixels)
{
voutEmbed *param = (voutEmbed*)arg;
unsigned char *pos;
// We are being called on playback stop, VLC calls one last time with empty pixel buffer
if (running == 0 || pixels == NULL) {
running = 0;
return 0;
}
SDL_LockMutex(lock);
// Environment changed, send new parameters to the vout module
if (param->changed) {
param->changed = 0;
SDL_UnlockMutex(lock);
return 1;
}
// Output provided frame, make sure frame properly aligned inside the window
if (param->h <= screen->h && param->w <= screen->w) {
if (param->h < screen->h && param->y == 0) {
param->y = (screen->h - param->h) / 2;
} 
if (param->w < screen->w && param->x == 0) {
param->x = (screen->w - param->w) / 2;
}
pos = ((unsigned char*)screen->pixels) + param->y * screen->pitch + param->x * screen->format->BytesPerPixel;
SDL_LockSurface(screen);
memcpy(pos, pixels, param->h * param->pitch);
SDL_UnlockSurface(screen);
SDL_Flip(screen);
}
SDL_UnlockMutex(lock);
return 0;
}
int main(int argc, char *argv[])
{
SDL_Event ev;
SDL_SysWMinfo wm;
static char const *args[] = { argv[0], "-I", "dummy", "-v1", "--vout", "embed", "--plugin-path", "./" };
if (argc < 2) {
fprintf(stderr, "%s filename\n", argv[0]);
exit(0);
}
if (SDL_Init(SDL_INIT_NOPARACHUTE|SDL_INIT_VIDEO|SDL_INIT_EVENTTHREAD) < 0) {
fprintf(stderr, "Failed to init SDL library");
return 0;
}
// Primary screen surface
screen = SDL_SetVideoMode(640, 480, 0, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_RESIZABLE);
if (screen == NULL) {
fprintf(stderr, "Unable to initialise SDL video mode");
SDL_Quit();
return 0;
}
SDL_EnableKeyRepeat(SDL_DEFAULT_REPEAT_DELAY, SDL_DEFAULT_REPEAT_INTERVAL);
SDL_GetWMInfo(&wm);
SDL_WM_SetCaption("vlc", "vlc");
lock = SDL_CreateMutex();
// VLC player
vlc = VLC_Create();
VLC_Init(vlc, 8, (char**)args);
// Initialize vout module
setup(&param);
VLC_AddTarget(vlc, argv[1], 0, 0, PLAYLIST_APPEND, PLAYLIST_END);
VLC_Play(vlc);
// Handle events from SDL
while (running) {
if (SDL_PollEvent(&ev)) {
switch (ev.type) {
case SDL_QUIT:
running = 0;
break;
case SDL_VIDEORESIZE: {
int w = screen->w, h = screen->h;
SDL_LockMutex(lock);
screen = SDL_SetVideoMode(ev.resize.w, ev.resize.h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_RESIZABLE);
if (screen == NULL) {
screen = SDL_SetVideoMode(w, h, 16, SDL_HWSURFACE | SDL_DOUBLEBUF | SDL_HWACCEL | SDL_RESIZABLE);
}
if (screen == NULL) {
running = 0;
}
SDL_UnlockMutex(lock);
setup(&param);
break;
}
case SDL_KEYDOWN:
switch (ev.key.keysym.sym) {
case SDLK_SPACE:
VLC_Pause(vlc);
break;
case SDLK_RIGHT:
VLC_SpeedFaster(vlc);
break;
case SDLK_LEFT:
VLC_SpeedSlower(vlc);
break;
}
break;
}
} else {
SDL_Delay(50);
}
}
VLC_CleanUp(vlc);
VLC_Destroy(vlc);
SDL_ShowCursor(1);
SDL_Quit();
return 0;
}

The whole archive with makefile and additional headers from VLC-0.8.6d is available for download, make sure VLC, SDL and other required packages are installed. Unpack the tar and type make. It will tell you what is missing.

Full sources for the plugin: Download


Other Postings:

Create USB MSDOS bootable disk in Linux
Simple GTK mixer
Emdedding VLC into SDL application
Reverse engineering PostgreSQL with Visio
Benchmarking Web Frameworks
Naviserver site
Streaming with NaviServer and Flash player
Future TV service
Naviserver project
LMBOX project is out
New demo of OSSWEB