Commit 5f65eb66 authored by Jean-Paul Saman's avatar Jean-Paul Saman

Refactor dynamic overlays from Google Summer of Code project.

parent f1dd920e
SOURCES_dynamicoverlay = dynamicoverlay.c dynamicoverlay_buffer.c dynamicoverlay_queue.c
noinst_HEADERS = dynamicoverlay.h dynamicoverlay_commands.h
This diff is collapsed.
/*****************************************************************************
* dynamicoverlay.h : dynamic overlay plugin for vlc
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id$
*
* Author: Jean-Paul Saman <jpsaman@videolan.org>
*
* 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.
*****************************************************************************/
#ifndef DYNAMIC_OVERLAY_H
#define DYNAMIC_OVERLAY_H 1
/*****************************************************************************
* buffer_t: Command and response buffer
*****************************************************************************/
typedef struct buffer_t
{
size_t i_size; /**< Size of the allocated memory */
size_t i_length; /**< Length of the stored data */
char *p_memory; /**< Start of the allocated memory */
char *p_begin; /**< Start of the stored data */
} buffer_t;
int BufferInit( buffer_t *p_buffer );
int BufferDestroy( buffer_t *p_buffer );
int BufferAdd( buffer_t *p_buffer, const char *p_data, size_t i_len );
int BufferPrintf( buffer_t *p_buffer, const char *p_fmt, ... );
int BufferDel( buffer_t *p_buffer, int i_len );
/*****************************************************************************
* Command structures
*****************************************************************************/
#define INT( name ) int name;
#define CHARS( name, count ) char name[count];
#define COMMAND( name, param, ret, atomic, code ) \
struct commandparams##name##_t \
{ \
param \
};
#include "dynamicoverlay_commands.h"
#undef COMMAND
#undef INT
#undef CHARS
union commandparams_t
{
#define COMMAND( name, param, ret, atomic, code ) struct commandparams##name##_t name;
#include "dynamicoverlay_commands.h"
#undef COMMAND
};
typedef union commandparams_t commandparams_t;
#define INT( name ) int name;
#define CHARS( name, count ) char name[count];
#define COMMAND( name, param, ret, atomic, code ) \
struct commandresults##name##_t \
{ \
ret \
};
#include "dynamicoverlay_commands.h"
#undef COMMAND
#undef INT
#undef CHARS
union commandresults_t {
#define COMMAND( name, param, ret, atomic, code ) struct commandresults##name##_t name;
#include "dynamicoverlay_commands.h"
#undef COMMAND
};
typedef union commandresults_t commandresults_t;
typedef struct commanddesc_t
{
const char *psz_command;
vlc_bool_t b_atomic;
int ( *pf_parser ) ( const char *psz_command, const char *psz_end,
commandparams_t *p_params );
int ( *pf_execute ) ( filter_t *p_filter, const commandparams_t *p_params,
commandresults_t *p_results,
struct filter_sys_t *p_sys );
int ( *pf_unparser ) ( const commandresults_t *p_results,
buffer_t *p_output );
} commanddesc_t;
typedef struct command_t
{
struct commanddesc_t *p_command;
int i_status;
commandparams_t params;
commandresults_t results;
struct command_t *p_next;
} command_t;
/*****************************************************************************
* queue_t: Command queue
*****************************************************************************/
typedef struct queue_t
{
command_t *p_head; /**< Head (first entry) of the queue */
command_t *p_tail; /**< Tail (last entry) of the queue */
} queue_t;
int QueueInit( queue_t *p_queue );
int QueueDestroy( queue_t *p_queue );
int QueueEnqueue( queue_t *p_queue, command_t *p_cmd );
command_t *QueueDequeue( queue_t *p_queue );
int QueueTransfer( queue_t *p_sink, queue_t *p_source );
#endif
/*****************************************************************************
* dynamicoverlay_commands.def : dynamic overlay plugin commands
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id$
*
* Author: Søren Bøg <avacore@videolan.org>
* Jean-Paul Saman <jpsaman@videolan.org>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc/vlc.h>
#include "dynamicoverlay.h"
/*****************************************************************************
* buffer_t: Command and response buffer
*****************************************************************************/
int BufferInit( buffer_t *p_buffer )
{
memset( p_buffer, 0, sizeof( buffer_t ) );
p_buffer->p_memory = NULL;
p_buffer->p_begin = NULL;
return VLC_SUCCESS;
}
int BufferDestroy( buffer_t *p_buffer )
{
if( p_buffer->p_memory != NULL )
{
free( p_buffer->p_memory );
}
p_buffer->p_memory = NULL;
p_buffer->p_begin = NULL;
return VLC_SUCCESS;
}
int BufferAdd( buffer_t *p_buffer, const char *p_data, size_t i_len )
{
if( ( p_buffer->i_size - p_buffer->i_length -
( p_buffer->p_begin - p_buffer->p_memory ) ) < i_len )
{
/* We'll have to do some rearranging to fit the new data. */
if( ( p_buffer->i_size - p_buffer->i_length ) >= i_len )
{
/* We have room in the current buffer, just need to move it */
memmove( p_buffer->p_memory, p_buffer->p_begin,
p_buffer->i_length );
p_buffer->p_begin = p_buffer->p_memory;
}
else
{
// We need a bigger buffer
size_t i_newsize = 1024;
while( i_newsize < p_buffer->i_length + i_len )
i_newsize *= 2;
/* TODO: Should I handle wrapping here? */
/* I'm not using realloc here, as I can avoid a memcpy/memmove in
some (most?) cases, and reset the start of the buffer. */
char *p_newdata = malloc( i_newsize );
if( p_newdata == NULL )
return VLC_ENOMEM;
if( p_buffer->p_begin != NULL )
{
memcpy( p_newdata, p_buffer->p_begin, p_buffer->i_length );
free( p_buffer->p_memory );
}
p_buffer->p_memory = p_buffer->p_begin = p_newdata;
p_buffer->i_size = i_newsize;
}
}
/* Add the new data to the end of the current */
memcpy( p_buffer->p_begin + p_buffer->i_length, p_data, i_len );
p_buffer->i_length += i_len;
return VLC_SUCCESS;
}
int BufferPrintf( buffer_t *p_buffer, const char *p_fmt, ... )
{
int i_len;
int status;
char *psz_data;
va_list va_list1, va_list2;
va_start( va_list1, p_fmt );
va_copy( va_list2, va_list1 );
i_len = vsnprintf( NULL, 0, p_fmt, va_list1 );
if( i_len < 0 )
return VLC_EGENERIC;
va_end( va_list1 );
psz_data = malloc( i_len + 1 );
if( psz_data == NULL ) {
return VLC_ENOMEM;
}
if( vsnprintf( psz_data, i_len + 1, p_fmt, va_list2 ) != i_len )
{
return VLC_EGENERIC;
}
va_end( va_list2 );
status = BufferAdd( p_buffer, psz_data, i_len );
free( psz_data );
return status;
}
int BufferDel( buffer_t *p_buffer, int i_len )
{
p_buffer->i_length -= i_len;
if( p_buffer->i_length == 0 )
{
/* No data, we can reset the buffer now. */
p_buffer->p_begin = p_buffer->p_memory;
}
else
{
p_buffer->p_begin += i_len;
}
return VLC_SUCCESS;
}
/*****************************************************************************
* dynamicoverlay_commands.def : dynamic overlay plugin commands
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id$
*
* Author: Søren Bøg <avacore@videolan.org>
* Jean-Paul Saman <jpsaman@videolan.org>
*
* 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.
*****************************************************************************/
#include <sys/shm.h>
/* Commands must be sorted alphabetically.
I haven't found out how to implement quick sort in cpp */
COMMAND( DataSharedMem, INT( i_id ) INT( i_width ) INT( i_height )
CHARS( p_fourcc, 4 ) INT( i_shmid ), , VLC_TRUE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
msg_Err( p_filter, "Invalid overlay: %d", p_params->i_id );
return VLC_EGENERIC;
}
struct shmid_ds shminfo;
if( shmctl( p_params->i_shmid, IPC_STAT, &shminfo ) == -1 ) {
msg_Err( p_filter, "Unable to access shared memory" );
return VLC_EGENERIC;
}
size_t i_size = shminfo.shm_segsz;
if( strncmp( p_params->p_fourcc, "TEXT", 4 ) == 0 ) {
if( p_params->i_height != 1 || p_params->i_width < 1 ) {
msg_Err( p_filter,
"Invalid width and/or height. when specifing text height "
"must be 1 and width the number of bytes in the string, "
"including the null terminator" );
return VLC_EGENERIC;
}
if( p_params->i_width > i_size ) {
msg_Err( p_filter,
"Insufficient data in shared memory. need %d, got %d",
p_params->i_width, i_size );
return VLC_EGENERIC;
}
p_ovl->data.p_text = malloc( p_params->i_width );
if( p_ovl->data.p_text == NULL )
{
msg_Err( p_filter, "Unable to allocate string storage" );
return VLC_ENOMEM;
}
vout_InitFormat( &p_ovl->format, VLC_FOURCC( 'T', 'E', 'X', 'T' ), 0, 0,
0 );
char *p_data = shmat( p_params->i_shmid, NULL, SHM_RDONLY );
if( p_data == NULL )
{
msg_Err( p_filter, "Unable to attach to shared memory" );
free( p_ovl->data.p_text );
p_ovl->data.p_text = NULL;
return VLC_ENOMEM;
}
memcpy( p_ovl->data.p_text, p_data, p_params->i_width );
shmdt( p_data );
} else {
p_ovl->data.p_pic = malloc( sizeof( picture_t ) );
if( p_ovl->data.p_pic == NULL )
{
msg_Err( p_filter, "Unable to allocate picture structure" );
return VLC_ENOMEM;
}
vout_InitFormat( &p_ovl->format, VLC_FOURCC( p_params->p_fourcc[0],
p_params->p_fourcc[1],
p_params->p_fourcc[2],
p_params->p_fourcc[3] ),
p_params->i_width, p_params->i_height,
VOUT_ASPECT_FACTOR );
if( vout_AllocatePicture( p_filter, p_ovl->data.p_pic,
p_ovl->format.i_chroma, p_params->i_width,
p_params->i_height, p_ovl->format.i_aspect ) )
{
msg_Err( p_filter, "Unable to allocate picture" );
free( p_ovl->data.p_pic );
p_ovl->data.p_pic = NULL;
return VLC_ENOMEM;
}
size_t i_neededsize = 0;
for( size_t i_plane = 0; i_plane < p_ovl->data.p_pic->i_planes;
++i_plane ) {
i_neededsize += p_ovl->data.p_pic->p[i_plane].i_visible_lines *
p_ovl->data.p_pic->p[i_plane].i_visible_pitch;
}
if( i_neededsize > i_size ) {
msg_Err( p_filter,
"Insufficient data in shared memory. need %d, got %d",
i_neededsize, i_size );
p_ovl->data.p_pic->pf_release( p_ovl->data.p_pic );
free( p_ovl->data.p_pic );
p_ovl->data.p_pic = NULL;
return VLC_EGENERIC;
}
char *p_data = shmat( p_params->i_shmid, NULL, SHM_RDONLY );
if( p_data == NULL )
{
msg_Err( p_filter, "Unable to attach to shared memory" );
p_ovl->data.p_pic->pf_release( p_ovl->data.p_pic );
free( p_ovl->data.p_pic );
p_ovl->data.p_pic = NULL;
return VLC_ENOMEM;
}
char *p_in = p_data;
for( size_t i_plane = 0; i_plane < p_ovl->data.p_pic->i_planes;
++i_plane ) {
char *p_out = p_ovl->data.p_pic->p[i_plane].p_pixels;
for( size_t i_line = 0;
i_line < p_ovl->data.p_pic->p[i_plane].i_visible_lines;
++i_line ) {
p_filter->p_libvlc->pf_memcpy( p_out, p_in,
p_ovl->data.p_pic->p[i_plane].i_visible_pitch );
p_out += p_ovl->data.p_pic->p[i_plane].i_pitch;
p_in += p_ovl->data.p_pic->p[i_plane].i_visible_pitch;
}
}
shmdt( p_data );
}
p_sys->b_updated = p_ovl->b_active;
return VLC_SUCCESS;
} )
COMMAND( DeleteImage, INT( i_id ), , VLC_TRUE, {
p_sys->b_updated = VLC_TRUE;
return ListRemove( &p_sys->overlays, p_params->i_id );
} )
COMMAND( EndAtomic, , , VLC_FALSE, {
QueueTransfer( &p_sys->pending, &p_sys->atomic );
p_sys->b_atomic = VLC_FALSE;
return VLC_SUCCESS;
} )
COMMAND( GenImage, , INT( i_newid ), VLC_FALSE, {
overlay_t *p_ovl = OverlayCreate();
if( p_ovl == NULL ) {
return VLC_ENOMEM;
}
ssize_t i_idx = ListAdd( &p_sys->overlays, p_ovl );
if( i_idx < 0 ) {
return i_idx;
}
p_results->i_newid = i_idx;
return VLC_SUCCESS;
} )
COMMAND( GetAlpha, INT( i_id ), INT( i_alpha ), VLC_FALSE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_results->i_alpha = p_ovl->i_alpha;
return VLC_SUCCESS;
} )
COMMAND( GetPosition, INT( i_id ), INT( i_x ) INT( i_y ), VLC_FALSE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_results->i_x = p_ovl->i_x;
p_results->i_y = p_ovl->i_y;
return VLC_SUCCESS;
} )
COMMAND( GetVisibility, INT( i_id ), INT( i_vis ), VLC_FALSE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_results->i_vis = ( p_ovl->b_active == VLC_TRUE ) ? 1 : 0;
return VLC_SUCCESS;
} )
COMMAND( SetAlpha, INT( i_id ) INT( i_alpha ), , VLC_TRUE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_ovl->i_alpha = p_params->i_alpha;
p_sys->b_updated = p_ovl->b_active;
return VLC_SUCCESS;
} )
COMMAND( SetPosition, INT( i_id ) INT( i_x ) INT( i_y ), , VLC_TRUE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_ovl->i_x = p_params->i_x;
p_ovl->i_y = p_params->i_y;
p_sys->b_updated = p_ovl->b_active;
return VLC_SUCCESS;
} )
COMMAND( SetVisibility, INT( i_id ) INT( i_vis ), , VLC_TRUE, {
overlay_t *p_ovl = ListGet( &p_sys->overlays, p_params->i_id );
if( p_ovl == NULL ) {
return VLC_EGENERIC;
}
p_ovl->b_active = ( p_params->i_vis == 0 ) ? VLC_FALSE : VLC_TRUE;
p_sys->b_updated = VLC_TRUE;
return VLC_SUCCESS;
} )
COMMAND( StartAtomic, , , VLC_FALSE, {
p_sys->b_atomic = VLC_TRUE;
return VLC_SUCCESS;
} )
/*****************************************************************************
* dynamicoverlay_commands.c : dynamic overlay plugin commands
*****************************************************************************
* Copyright (C) 2008 the VideoLAN team
* $Id$
*
* Author: Søren Bøg <avacore@videolan.org>
* Jean-Paul Saman <jpsaman@videolan.org>
*
* 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.
*****************************************************************************/
#ifdef HAVE_CONFIG_H
# include "config.h"
#endif
#include <vlc/vlc.h>
#include "dynamicoverlay.h"
/*****************************************************************************
* queue_t: Command queue
*****************************************************************************/
int QueueInit( queue_t *p_queue )
{
memset( p_queue, 0, sizeof( queue_t ) );
p_queue->p_head = NULL;
p_queue->p_tail = NULL;
return VLC_SUCCESS;
}
int QueueDestroy( queue_t *p_queue )
{
command_t *p_cur = p_queue->p_head, *p_temp;
while( p_cur != NULL )
{
p_temp = p_cur;
p_cur = p_cur->p_next;
free( p_temp );
}
p_queue->p_head = NULL;
p_queue->p_tail = NULL;
return VLC_SUCCESS;
}
int QueueEnqueue( queue_t *p_queue, command_t *p_cmd )
{
if( p_queue->p_tail != NULL )
{
p_queue->p_tail->p_next = p_cmd;
}
if( p_queue->p_head == NULL )
{
p_queue->p_head = p_cmd;
}
p_queue->p_tail = p_cmd;
p_cmd->p_next = NULL;
return VLC_SUCCESS;
}
command_t *QueueDequeue( queue_t *p_queue )
{
if( p_queue->p_head == NULL )
{
return NULL;
}
else
{
command_t *p_ret = p_queue->p_head;
if( p_queue->p_head == p_queue->p_tail )
{
p_queue->p_head = p_queue->p_tail = NULL;
}
else
{
p_queue->p_head = p_queue->p_head->p_next;
}
return p_ret;
}
}
int QueueTransfer( queue_t *p_sink, queue_t *p_source )
{
if( p_source->p_head == NULL ) {
return VLC_SUCCESS;
}
if( p_sink->p_head == NULL ) {
p_sink->p_head = p_source->p_head;
p_sink->p_tail = p_source->p_tail;
} else {
p_sink->p_tail->p_next = p_source->p_head;
p_sink->p_tail = p_source->p_tail;
}
p_source->p_head = p_source->p_tail = NULL;
return VLC_SUCCESS;
}
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment