[PD-cvs] externals/pdp/modules/image_io Makefile, 1.2, 1.3 README, 1.2, 1.3 pdp_glx.c, 1.2, 1.3 pdp_qt.c, 1.2, 1.3 pdp_sdl.c, 1.2, 1.3 pdp_v4l.c, 1.2, 1.3 pdp_xv.c, 1.2, 1.3
Hans-Christoph Steiner
eighthave at users.sourceforge.net
Fri Dec 16 02:05:35 CET 2005
- Previous message: [PD-cvs] externals/pdp/modules/image_special Makefile, 1.2, 1.3 README, 1.2, 1.3 pdp_array.c, 1.2, 1.3 pdp_chrot.c, 1.2, 1.3 pdp_cog.c, 1.2, 1.3 pdp_grey2mask.c, 1.2, 1.3 pdp_histo.c, 1.2, 1.3 pdp_scale.c, 1.2, 1.3 pdp_scan.c, 1.2, 1.3 pdp_scanxy.c, 1.2, 1.3 pdp_scope.c, 1.2, 1.3
- Next message: [PD-cvs] externals/pdp/opengl Makefile, 1.2, 1.3 Makefile.config, 1.2, 1.3 README, 1.2, 1.3 TODO, 1.2, 1.3
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
Update of /cvsroot/pure-data/externals/pdp/modules/image_io
In directory sc8-pr-cvs1.sourceforge.net:/tmp/cvs-serv6756/modules/image_io
Added Files:
Makefile README pdp_glx.c pdp_qt.c pdp_sdl.c pdp_v4l.c
pdp_xv.c
Log Message:
checking in pdp 0.12.4 from http://zwizwa.fartit.com/pd/pdp/pdp-0.12.4.tar.gz
--- NEW FILE: pdp_glx.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp at zzz.kotnet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
// gl stuff
#include <GL/gl.h>
#include <GL/glx.h>
#include <GL/glu.h>
//#include <GL/glut.h>
// pdp stuff
#include "pdp.h"
#include "pdp_base.h"
// some x window glue code
#include "pdp_xwindow.h"
// pdp stuff
#include "pdp.h"
#include "pdp_llconv.h"
//#include "pdp_opengl.h"
/* initial image dimensions */
#define PDP_OGL_W 320
#define PDP_OGL_H 240
#define PDP_OGL_AUTOCREATE_RETRY 10
typedef struct pdp_glx_struct
{
t_object x_obj;
t_pdp_xwindow *x_xwin;
t_outlet *x_outlet;
int x_packet0;
int x_queue_id;
t_symbol *x_display;
t_pdp_xdisplay *x_xdpy;
XVisualInfo *x_vis_info;
GLXContext x_glx_context;
GLuint x_texture;
u32 x_tex_width;
u32 x_tex_height;
unsigned char *x_data;
unsigned int x_width;
unsigned int x_height;
int x_last_encoding;
int x_initialized;
int x_autocreate;
} t_pdp_glx;
static void pdp_glx_cursor(t_pdp_glx *x, t_floatarg f)
{
if (x->x_initialized)
pdp_xwindow_cursor(x->x_xwin, f);
}
static void pdp_glx_destroy(t_pdp_glx* x)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
XEvent e;
if (x->x_initialized){
pdp_procqueue_finish(q, x->x_queue_id);
x->x_queue_id = -1;
glXDestroyContext(x->x_xdpy->dpy, x->x_glx_context);
pdp_xwindow_free(x->x_xwin);
pdp_xdisplay_free(x->x_xdpy);
x->x_xwin = 0;
x->x_xdpy = 0;
x->x_initialized = false;
}
}
static void pdp_glx_fullscreen(t_pdp_glx *x)
{
if (x->x_initialized)
pdp_xwindow_fullscreen(x->x_xwin);
}
static void pdp_glx_resize(t_pdp_glx* x, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_resize(x->x_xwin, width, height);
}
static void pdp_glx_move(t_pdp_glx* x, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_move(x->x_xwin, width, height);
}
static void pdp_glx_moveresize(t_pdp_glx* x, t_floatarg xoff, t_floatarg yoff, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_moveresize(x->x_xwin, xoff, yoff, width, height);
}
static void pdp_glx_tile(t_pdp_glx* x, t_floatarg xtiles, t_floatarg ytiles, t_floatarg i, t_floatarg j)
{
if (x->x_initialized)
pdp_xwindow_tile(x->x_xwin, xtiles, ytiles, i, j);
}
void pdp_glx_generate_texture(t_pdp_glx *x)
{
u32 width = x->x_tex_width;
u32 height = x->x_tex_height;
u32 depth = 4;
u32 i;
u8 *dummydata = 0;
while (x->x_width > width) width <<= 1;
while (x->x_height > height) height <<= 1;
dummydata = (u8 *)pdp_alloc(width*height*depth);
for (i=0; i<width*height*depth; i++){dummydata[i] = random(); }
/* set window context current */
glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context);
/* generate texture if necessary */
if (!glIsTexture(x->x_texture)) glGenTextures(1, &(x->x_texture));
glBindTexture(GL_TEXTURE_2D, x->x_texture);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, dummydata);
pdp_dealloc(dummydata);
x->x_tex_width = width;
x->x_tex_height = height;
}
void pdp_glx_regenerate_texture(t_pdp_glx *x)
{
if ((x->x_width > x->x_tex_width) || (x->x_height > x->x_tex_height)) pdp_glx_generate_texture(x);
}
static void pdp_glx_create(t_pdp_glx* x)
{
unsigned int *uintdata = (unsigned int *)(x->x_data);
XEvent e;
unsigned int i;
static int vis_attr[] = {GLX_RGBA, GLX_RED_SIZE, 4, GLX_GREEN_SIZE, 4, GLX_BLUE_SIZE, 4,
GLX_DEPTH_SIZE, 16, GLX_DOUBLEBUFFER, None};
if (x->x_initialized) return;
/* manually open a display */
if (NULL == (x->x_xdpy = pdp_xdisplay_new(x->x_display->s_name))){
post("pdp_glx: cant open display %s\n",x->x_display->s_name);
x->x_initialized = false;
return;
}
/* create a window on the display */
x->x_xwin = pdp_xwindow_new();
if (!(x->x_initialized = pdp_xwindow_create_on_display(x->x_xwin, x->x_xdpy)))
goto exit_error;
/* create a glx visual */
if (!(x->x_vis_info = glXChooseVisual(x->x_xdpy->dpy, x->x_xdpy->screen, vis_attr))){
post("pdp_glx: can't create visual");
goto exit_error;
}
//post("visual: %x", x->x_vis_info);
/* create the rendering context */
if (!(x->x_glx_context = glXCreateContext(x->x_xdpy->dpy, x->x_vis_info, 0 /*share list*/, GL_TRUE))){
post("pdp_glx: can't create render context");
goto exit_error;
}
//post("context: %x", x->x_glx_context);
/* create texture */
pdp_glx_generate_texture(x);
/* we're done initializing */
x->x_initialized = true;
/* disable/enable cursor */
//pdp_glx_cursor(x, x->x_cursor);
return;
exit_error:
if (x->x_xwin){
pdp_xwindow_free(x->x_xwin);
x->x_xwin = 0;
}
if (x->x_xdpy){
pdp_xdisplay_free(x->x_xdpy);
x->x_xdpy = 0;
}
x->x_initialized = false;
return;
}
static int pdp_glx_try_autocreate(t_pdp_glx *x)
{
if (x->x_autocreate){
post("pdp_glx: autocreate window");
pdp_glx_create(x);
if (!(x->x_initialized)){
x->x_autocreate--;
if (!x->x_autocreate){
post ("pdp_glx: autocreate failed %d times: disabled", PDP_OGL_AUTOCREATE_RETRY);
post ("pdp_glx: send [autocreate 1] message to re-enable");
return 0;
}
}
else return 1;
}
return 0;
}
static void pdp_glx_bang(t_pdp_glx *x);
static void pdp_glx_fill_texture(t_pdp_glx *x)
{
t_pdp *header = pdp_packet_header(x->x_packet0);
void *data = pdp_packet_data (x->x_packet0);
int i = header->info.image.width;
/* ensure image buffer is correct dim */
if ((header->info.image.width != x->x_width)
|| (header->info.image.height != x->x_height)) {
if (x->x_data) pdp_dealloc (x->x_data);
x->x_width = header->info.image.width;
x->x_height = header->info.image.height;
x->x_data = pdp_alloc(4*x->x_width*x->x_height);
}
/* ensure texture is correct dim */
pdp_glx_regenerate_texture(x);
/* set window context current */
glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context);
glBindTexture(GL_TEXTURE_2D, x->x_texture);
switch (header->info.image.encoding){
case PDP_IMAGE_GREY:
/* convert image to greyscale 8 bit */
pdp_llconv(data,RIF_GREY______S16, x->x_data, RIF_GREY______U8, x->x_width, x->x_height);
/* upload grey subtexture */
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x->x_width, x->x_height, GL_LUMINANCE, GL_UNSIGNED_BYTE, x->x_data);
break;
case PDP_IMAGE_YV12:
/* convert image to rgb 8 bit */
pdp_llconv(data,RIF_YVU__P411_S16, x->x_data, RIF_RGB__P____U8, x->x_width, x->x_height);
/* upload subtexture */
glTexSubImage2D(GL_TEXTURE_2D, 0, 0, 0, x->x_width, x->x_height, GL_RGB, GL_UNSIGNED_BYTE, x->x_data);
break;
default:
break;
}
}
static void pdp_glx_process(t_pdp_glx *x)
{
t_pdp *header = pdp_packet_header(x->x_packet0);
void *data = pdp_packet_data (x->x_packet0);
if (-1 != x->x_queue_id) return;
/* check if window is initialized */
if (!(x->x_initialized)){
if (!pdp_glx_try_autocreate(x)) return;
}
/* check data packet */
if (!(header)) {
post("pdp_glx: invalid packet header");
return;
}
if (PDP_IMAGE != header->type) {
post("pdp_glx: packet is not a PDP_IMAGE");
return;
}
if ((PDP_IMAGE_YV12 != header->info.image.encoding)
&& (PDP_IMAGE_GREY != header->info.image.encoding)) {
post("pdp_glx: packet is not a PDP_IMAGE_YV12/GREY");
return;
}
/* fill the texture with the data in the packet */
pdp_glx_fill_texture(x);
/* display the new image */
pdp_glx_bang(x);
}
static void pdp_glx_display_texture(t_pdp_glx *x)
{
float fx = (float)x->x_width / x->x_tex_width;
float fy = (float)x->x_height / x->x_tex_height;
if (!x->x_initialized) return;
/* set window context current */
glXMakeCurrent(x->x_xdpy->dpy, x->x_xwin->win, x->x_glx_context);
/* setup viewport, projection and modelview */
glViewport(0, 0, x->x_xwin->winwidth, x->x_xwin->winheight);
glMatrixMode(GL_PROJECTION);
glLoadIdentity();
gluOrtho2D(0.0, x->x_xwin->winwidth, 0.0, x->x_xwin->winheight);
glMatrixMode(GL_MODELVIEW);
glLoadIdentity();
/* enable default texture */
glEnable(GL_TEXTURE_2D);
glBindTexture(GL_TEXTURE_2D, x->x_texture);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameterf(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MIN_FILTER,GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D,GL_TEXTURE_MAG_FILTER,GL_LINEAR);
glTexEnvi(GL_TEXTURE_ENV, GL_TEXTURE_ENV_MODE, GL_MODULATE);
/* display texture */
glBegin(GL_QUADS);
glTexCoord2f(fx, fy);
glVertex2i(x->x_xwin->winwidth,0);
glTexCoord2f(fx, 0);
glVertex2i(x->x_xwin->winwidth, x->x_xwin->winheight);
glTexCoord2f(0.0, 0.0);
glVertex2i(0, x->x_xwin->winheight);
glTexCoord2f(0, fy);
glVertex2i(0,0);
glEnd();
glFlush();
glXSwapBuffers(x->x_xdpy->dpy,x->x_xwin->win);
}
/* redisplays image */
static void pdp_glx_bang_thread(t_pdp_glx *x)
{
pdp_glx_display_texture(x);
XFlush(x->x_xdpy->dpy);
}
static void pdp_glx_bang_callback(t_pdp_glx *x)
{
/* receive events + send to outputs */
t_pdp_list *eventlist = pdp_xwindow_get_eventlist(x->x_xwin);
t_pdp_atom *a;
for (a=eventlist->first; a; a=a->next){
//pdp_list_print(a->w.w_list);
outlet_pdp_list(x->x_outlet, a->w.w_list);
}
/* free list */
pdp_tree_free(eventlist);
/* release the packet if there is one */
pdp_packet_mark_unused(x->x_packet0);
x->x_packet0 = -1;
}
static void pdp_glx_bang(t_pdp_glx *x)
{
/* check if window is initialized */
if (!(x->x_initialized)){
if (!pdp_glx_try_autocreate(x)) return;
}
/* if previous queued method returned
schedule a new one, else ignore */
/*
if (-1 == x->x_queue_id) {
pdp_queue_add(x, pdp_glx_bang_thread, pdp_glx_bang_callback, &x->x_queue_id);
}
*/
/* don't process in thread */
pdp_glx_bang_thread(x);
pdp_glx_bang_callback(x);
}
static void pdp_glx_input_0(t_pdp_glx *x, t_symbol *s, t_floatarg f)
{
if (s == gensym("register_ro")) pdp_packet_copy_ro_or_drop(&x->x_packet0, (int)f);
if (s == gensym("process")) pdp_glx_process(x);
}
static void pdp_glx_vga(t_pdp_glx *x)
{
pdp_glx_resize(x, 640, 480);
}
static void pdp_glx_autocreate(t_pdp_glx *x, t_floatarg f)
{
if (f != 0.0f) x->x_autocreate = PDP_OGL_AUTOCREATE_RETRY;
else x->x_autocreate = 0;
}
static void pdp_glx_display(t_pdp_glx *x, t_symbol *s)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
pdp_procqueue_finish(q, x->x_queue_id);
x->x_queue_id = -1;
x->x_display = s;
if (x->x_initialized){
pdp_glx_destroy(x);
pdp_glx_create(x);
}
}
static void pdp_glx_free(t_pdp_glx *x)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
pdp_procqueue_finish(q, x->x_queue_id);
pdp_glx_destroy(x);
if (x->x_data) pdp_dealloc (x->x_data);
pdp_packet_mark_unused(x->x_packet0);
}
t_class *pdp_glx_class;
void *pdp_glx_new(void)
{
t_pdp_glx *x = (t_pdp_glx *)pd_new(pdp_glx_class);
x->x_xwin = 0;
x->x_xdpy = 0;
x->x_outlet = outlet_new(&x->x_obj, &s_anything);
x->x_packet0 = -1;
x->x_queue_id = -1;
x->x_display = gensym(":0");
x->x_width = PDP_OGL_W;
x->x_height = PDP_OGL_H;
x->x_data = pdp_alloc(4*PDP_OGL_W*PDP_OGL_H);
x->x_initialized = 0;
pdp_glx_autocreate(x,1);
x->x_last_encoding = -1;
x->x_tex_width = 64;
x->x_tex_height = 64;
//pdp_glx_create(x);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_glx_setup(void)
{
pdp_glx_class = class_new(gensym("pdp_glx"), (t_newmethod)pdp_glx_new,
(t_method)pdp_glx_free, sizeof(t_pdp_glx), 0, A_NULL);
/* add creator for pdp_tex_win */
class_addmethod(pdp_glx_class, (t_method)pdp_glx_bang, gensym("bang"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_create, gensym("open"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_create, gensym("create"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_autocreate, gensym("autocreate"), A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_destroy, gensym("destroy"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_destroy, gensym("close"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_move, gensym("move"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_move, gensym("pos"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_display, gensym("display"), A_SYMBOL, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_cursor, gensym("cursor"), A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_fullscreen, gensym("fullscreen"), A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_moveresize, gensym("posdim"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_glx_class, (t_method)pdp_glx_tile, gensym("tile"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
/* accept both pdp and pdp_tex packets */
class_addmethod(pdp_glx_class, (t_method)pdp_glx_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
/* some shortcuts for the lazy */
class_addmethod(pdp_glx_class, (t_method)pdp_glx_vga, gensym("vga"), A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_v4l.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp at zzz.kotnet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include "pdp_config.h"
#include "pdp.h"
#include "pdp_llconv.h"
#include "pdp_imageproc.h"
#include <stdio.h>
#include <stdlib.h>
#include <stdarg.h>
#include <unistd.h>
#include <string.h>
#include <ctype.h>
#include <fcntl.h>
#include <errno.h>
#include <sys/ioctl.h>
#include <sys/types.h>
#include <sys/time.h>
#include <linux/types.h>
#include <linux/videodev.h>
#include <sys/mman.h>
#include <sched.h>
#include <pthread.h>
// dont open any more after a set number
// of failed attempts
// this is to prevent locks on auto-open
// is reset when manually opened or closed
#define PDP_XV_RETRIES 10
//include it anyway
//#ifdef HAVE_PWCV4L
#include "pwc-ioctl.h"
//#endif
#define DEVICENO 0
#define NBUF 2
#define COMPOSITEIN 1
typedef struct pdp_v4l_struct
{
t_object x_obj;
t_float x_f;
t_outlet *x_outlet0;
int x_format; // 0 means autodetect
bool x_initialized;
bool x_auto_open;
unsigned int x_width;
unsigned int x_height;
int x_channel;
unsigned int x_norm;
int x_freq;
unsigned int x_framerate;
struct video_tuner x_vtuner;
struct video_picture x_vpicture;
struct video_buffer x_vbuffer;
struct video_capability x_vcap;
struct video_channel x_vchannel;
struct video_audio x_vaudio;
struct video_mbuf x_vmbuf;
struct video_mmap x_vmmap[NBUF];
struct video_window x_vwin;
int x_tvfd;
int x_frame;
unsigned char *x_videobuf;
int x_skipnext;
int x_mytopmargin, x_mybottommargin;
int x_myleftmargin, x_myrightmargin;
t_symbol *x_device;
t_symbol *x_image_type;
//int x_pdp_image_type;
int x_v4l_palette;
pthread_t x_thread_id;
int x_continue_thread;
int x_frame_ready;
int x_only_new_frames;
int x_last_frame;
int x_open_retry;
u32 x_minwidth;
u32 x_maxwidth;
u32 x_minheight;
u32 x_maxheight;
} t_pdp_v4l;
static void pdp_v4l_audio(t_pdp_v4l *x, t_floatarg f)
{
int i = 0;
if (x->x_initialized){
fprintf(stderr," audios : %d\n",x->x_vcap.audios);
x->x_vaudio.audio = 0;
ioctl(x->x_tvfd,VIDIOCGAUDIO, &x->x_vaudio);
fprintf(stderr," %d (%s): ",i,x->x_vaudio.name);
if (x->x_vaudio.flags & VIDEO_AUDIO_MUTABLE)
fprintf(stderr,"muted=%s ",
(x->x_vaudio.flags & VIDEO_AUDIO_MUTE) ? "yes":"no");
if (x->x_vaudio.flags & VIDEO_AUDIO_VOLUME)
fprintf(stderr,"volume=%d ",x->x_vaudio.volume);
if (x->x_vaudio.flags & VIDEO_AUDIO_BASS)
fprintf(stderr,"bass=%d ",x->x_vaudio.bass);
if (x->x_vaudio.flags & VIDEO_AUDIO_TREBLE)
fprintf(stderr,"treble=%d ",x->x_vaudio.treble);
fprintf(stderr,"\n");
}
}
static void pdp_v4l_close(t_pdp_v4l *x)
{
/* close the v4l device and dealloc buffer */
void *dummy;
/* terminate thread if there is one */
if(x->x_continue_thread){
x->x_continue_thread = 0;
pthread_join (x->x_thread_id, &dummy);
}
if (x->x_tvfd >= 0)
{
close(x->x_tvfd);
x->x_tvfd = -1;
}
if (x->x_initialized){
munmap(x->x_videobuf, x->x_vmbuf.size);
x->x_initialized = false;
}
}
static void pdp_v4l_close_manual(t_pdp_v4l *x)
{
x->x_open_retry = PDP_XV_RETRIES;
pdp_v4l_close(x);
}
static void pdp_v4l_close_error(t_pdp_v4l *x)
{
pdp_v4l_close(x);
if(x->x_open_retry) x->x_open_retry--;
}
static void pdp_v4l_pwc_init(t_pdp_v4l *x)
{
struct pwc_probe probe;
int isPhilips = 0;
#ifdef HAVE_PWCV4L
/* skip test */
isPhilips = 1;
#else
/* test for pwc */
if (ioctl(x->x_tvfd, VIDIOCPWCPROBE, &probe) == 0)
if (!strcmp(x->x_vcap.name, probe.name))
isPhilips = 1;
#endif
/* don't do pwc specific stuff */
if (!isPhilips) return;
post("pdp_v4l: detected pwc");
if(ioctl(x->x_tvfd, VIDIOCPWCRUSER)){
perror("pdp_v4l: pwc: VIDIOCPWCRUSER");
goto closit;
}
if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
perror("pdp_v4l: pwc: VIDIOCGWIN");
goto closit;
}
if (x->x_vwin.flags & PWC_FPS_MASK){
//post("pdp_v4l: pwc: camera framerate: %d", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
//post("pdp_v4l: pwc: setting camera framerate to %d", x->x_framerate);
x->x_vwin.flags &= PWC_FPS_MASK;
x->x_vwin.flags |= (x->x_framerate << PWC_FPS_SHIFT);
if (ioctl(x->x_tvfd, VIDIOCSWIN, &x->x_vwin)){
perror("pdp_v4l: pwc: VIDIOCSWIN");
goto closit;
}
if (ioctl(x->x_tvfd, VIDIOCGWIN, &x->x_vwin)){
perror("pdp_v4l: pwc: VIDIOCGWIN");
goto closit;
}
post("pdp_v4l: camera framerate set to %d fps", (x->x_vwin.flags & PWC_FPS_MASK) >> PWC_FPS_SHIFT);
}
return;
closit:
pdp_v4l_close_error(x);
return;
}
static void pdp_v4l_sync_frame(t_pdp_v4l* x){
/* grab frame */
if (ioctl(x->x_tvfd, VIDIOCSYNC, &x->x_vmmap[x->x_frame].frame) < 0){
perror("pdp_v4l: VIDIOCSYNC");
pdp_v4l_close(x);
return;
}
}
static void pdp_v4l_capture_frame(t_pdp_v4l* x){
if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0){
if (errno == EAGAIN)
post("pdp_v4l: can't sync (no video source?)\n");
else
perror("pdp_v4l: VIDIOCMCAPTURE");
if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0)
perror("pdp_v4l: VIDIOCMCAPTURE2");
post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
pdp_v4l_close(x);
return;
}
}
static void *pdp_v4l_thread(void *voidx)
{
t_pdp_v4l *x = ((t_pdp_v4l *)voidx);
/* flip buffers */
x->x_frame ^= 0x1;
/* capture with a double buffering scheme */
while (x->x_continue_thread){
/* schedule capture command for next frame */
pdp_v4l_capture_frame(x);
/* wait until previous capture is ready */
x->x_frame ^= 0x1;
pdp_v4l_sync_frame(x);
/* setup pointers for main thread */
x->x_frame_ready = 1;
x->x_last_frame = x->x_frame;
}
return 0;
}
static void pdp_v4l_setlegaldim(t_pdp_v4l *x, int xx, int yy);
static void pdp_v4l_open(t_pdp_v4l *x, t_symbol *name)
{
/* open a v4l device and allocate a buffer */
unsigned int size;
int i;
unsigned int width, height;
/* if already opened -> close */
if (x->x_initialized) pdp_v4l_close(x);
/* exit if retried too much */
if (!x->x_open_retry){
post("pdp_v4l: retry count reached zero for %s", name->s_name);
post("pdp_v4l: try to open manually");
return;
}
post("pdp_v4l: opening %s", name->s_name);
x->x_device = name;
if ((x->x_tvfd = open(name->s_name, O_RDWR)) < 0)
{
post("pdp_v4l: error:");
perror(name->s_name);
goto closit;
}
if (ioctl(x->x_tvfd, VIDIOCGCAP, &x->x_vcap) < 0)
{
perror("get capabilities");
goto closit;
}
post("pdp_v4l: cap: name %s type %d channels %d maxw %d maxh %d minw %d minh %d",
x->x_vcap.name, x->x_vcap.type, x->x_vcap.channels, x->x_vcap.maxwidth, x->x_vcap.maxheight,
x->x_vcap.minwidth, x->x_vcap.minheight);
x->x_minwidth = pdp_imageproc_legalwidth(x->x_vcap.minwidth);
x->x_maxwidth = pdp_imageproc_legalwidth_round_down(x->x_vcap.maxwidth);
x->x_minheight = pdp_imageproc_legalheight(x->x_vcap.minheight);
x->x_maxheight = pdp_imageproc_legalheight_round_down(x->x_vcap.maxheight);
if (ioctl(x->x_tvfd, VIDIOCGPICT, &x->x_vpicture) < 0)
{
perror("VIDIOCGCAP");
goto closit;
}
post("pdp_v4l: picture: brightness %d depth %d palette %d",
x->x_vpicture.brightness, x->x_vpicture.depth, x->x_vpicture.palette);
/* get channel info */
for (i = 0; i < x->x_vcap.channels; i++)
{
x->x_vchannel.channel = i;
if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
{
perror("VDIOCGCHAN");
goto closit;
}
post("pdp_v4l: channel %d name %s type %d flags %d",
x->x_vchannel.channel, x->x_vchannel.name,
x->x_vchannel.type, x->x_vchannel.flags);
}
/* switch to the desired channel */
if (x->x_channel < 0) x->x_channel = 0;
if (x->x_channel >= x->x_vcap.channels) x->x_channel = x->x_vcap.channels - 1;
x->x_vchannel.channel = x->x_channel;
if (ioctl(x->x_tvfd, VIDIOCGCHAN, &x->x_vchannel) < 0)
{
perror("pdp_v4l: warning: VDIOCGCHAN");
post("pdp_v4l: cant change to channel %d",x->x_channel);
// ignore error
// goto closit;
}
else{
post("pdp_v4l: switched to channel %d", x->x_channel);
}
/* set norm */
x->x_vchannel.norm = x->x_norm;
if (ioctl(x->x_tvfd, VIDIOCSCHAN, &x->x_vchannel) < 0)
{
perror("pdp_v4l: warning: VDIOCSCHAN");
post("pdp_v4l: cant change to norm %d",x->x_norm);
// ignore error
// goto closit;
}
else {
post("pdp_v4l: set norm to %u", x->x_norm);
}
if (x->x_freq > 0){
if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
perror ("couldn't set frequency :");
}
/* get mmap numbers */
if (ioctl(x->x_tvfd, VIDIOCGMBUF, &x->x_vmbuf) < 0)
{
perror("pdp_v4l: VIDIOCGMBUF");
goto closit;
}
post("pdp_v4l: buffer size %d, frames %d, offset %d %d", x->x_vmbuf.size,
x->x_vmbuf.frames, x->x_vmbuf.offsets[0], x->x_vmbuf.offsets[1]);
if (!(x->x_videobuf = (unsigned char *)
mmap(0, x->x_vmbuf.size, PROT_READ|PROT_WRITE, MAP_SHARED, x->x_tvfd, 0)))
{
perror("pdp_v4l: mmap");
goto closit;
}
pdp_v4l_setlegaldim(x, x->x_width, x->x_height);
width = x->x_width;
height = x->x_height;
for (i = 0; i < NBUF; i++)
{
//x->x_vmmap[i].format = VIDEO_PALETTE_YUV420P;
//x->x_vmmap[i].format = VIDEO_PALETTE_UYVY;
x->x_vmmap[i].width = width;
x->x_vmmap[i].height = height;
x->x_vmmap[i].frame = i;
}
/* fallthrough macro for case statement */
#define TRYPALETTE(palette) \
x->x_v4l_palette = palette; \
for (i = 0; i < NBUF; i++) x->x_vmmap[i].format = x->x_v4l_palette; \
if (ioctl(x->x_tvfd, VIDIOCMCAPTURE, &x->x_vmmap[x->x_frame]) < 0) \
{ \
if (errno == EAGAIN) \
post("pdp_v4l: can't sync (no video source?)"); \
if (x->x_format) break; /* only break if not autodetecting */ \
} \
else{ \
post("pdp_v4l: using " #palette); \
goto capture_ok; \
}
switch(x->x_format){
default:
case 0:
case 1: TRYPALETTE(VIDEO_PALETTE_YUV420P);
case 2: TRYPALETTE(VIDEO_PALETTE_YUV422);
case 3: TRYPALETTE(VIDEO_PALETTE_RGB24);
case 4: TRYPALETTE(VIDEO_PALETTE_RGB32);
}
// none of the formats are supported
perror("pdp_v4l: VIDIOCMCAPTURE: format not supported");
goto closit;
capture_ok:
post("pdp_v4l: frame %d %d, format %d, width %d, height %d",
x->x_frame, x->x_vmmap[x->x_frame].frame, x->x_vmmap[x->x_frame].format,
x->x_vmmap[x->x_frame].width, x->x_vmmap[x->x_frame].height);
x->x_width = width;
x->x_height = height;
post("pdp_v4l: Opened video connection (%dx%d)",x->x_width,x->x_height);
/* do some pwc specific inits */
pdp_v4l_pwc_init(x);
x->x_initialized = true;
/* create thread */
x->x_continue_thread = 1;
x->x_frame_ready = 0;
pthread_create(&x->x_thread_id, 0, pdp_v4l_thread, x);
return;
closit:
pdp_v4l_close_error(x);
}
static void pdp_v4l_open_manual(t_pdp_v4l *x, t_symbol *name)
{
x->x_open_retry = PDP_XV_RETRIES;
pdp_v4l_open(x, name);
}
static void pdp_v4l_channel(t_pdp_v4l *x, t_float f)
{
int channel = (float)f;
if (x->x_initialized){
pdp_v4l_close(x);
x->x_channel = channel;
pdp_v4l_open(x, x->x_device);
}
else
x->x_channel = channel;
}
static void pdp_v4l_norm(t_pdp_v4l *x, t_symbol *s)
{
unsigned int norm;
if (gensym("PAL") == s) norm = VIDEO_MODE_PAL;
else if (gensym("NTSC") == s) norm = VIDEO_MODE_NTSC;
else if (gensym("SECAM") == s) norm = VIDEO_MODE_SECAM;
else norm = VIDEO_MODE_AUTO;
if (x->x_initialized){
pdp_v4l_close(x);
x->x_norm = norm;
pdp_v4l_open(x, x->x_device);
}
else
x->x_norm = norm;
}
static void pdp_v4l_freq(t_pdp_v4l *x, t_float f)
{
int freq = (int)f;
x->x_freq = freq;
if (x->x_freq > 0){
if (ioctl(x->x_tvfd, VIDIOCSFREQ, &x->x_freq) < 0)
perror ("couldn't set frequency :");
//else {post("pdp_v4l: tuner frequency: %f MHz", f / 16.0f);}
}
}
static void pdp_v4l_freqMHz(t_pdp_v4l *x, t_float f)
{
pdp_v4l_freq(x, f*16.0f);
}
static void pdp_v4l_bang(t_pdp_v4l *x)
{
/* if initialized, grab a frame and output it */
unsigned int w,h,nbpixels,packet_size,plane1,plane2;
unsigned char *newimage;
int object,length,pos,i,encoding;
t_pdp* header;
t_image* image;
short int * data;
static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
if (!(x->x_initialized)){
post("pdp_v4l: no device opened");
if (x->x_auto_open){
post("pdp_v4l: attempting auto open");
pdp_v4l_open(x, x->x_device);
if (!(x->x_initialized)){
post("pdp_v4l: auto open failed");
return;
}
}
else return;
}
/* do nothing if there is no frame ready */
if((!x->x_frame_ready) && (x->x_only_new_frames)) return;
x->x_frame_ready = 0;
/* get the address of the "other" frame */
newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_last_frame];
/* create new packet */
w = x->x_width;
h = x->x_height;
//nbpixels = w * h;
/*
switch(x->x_pdp_image_type){
case PDP_IMAGE_GREY:
packet_size = nbpixels << 1;
break;
case PDP_IMAGE_YV12:
packet_size = (nbpixels + (nbpixels >> 1)) << 1;
break;
default:
packet_size = 0;
post("pdp_v4l: internal error");
}
*/
//packet_size = (nbpixels + (nbpixels >> 1)) << 1;
//plane1 = nbpixels;
//plane2 = nbpixels + (nbpixels>>2);
object = pdp_packet_new_image(PDP_IMAGE_YV12, w, h);
header = pdp_packet_header(object);
image = pdp_packet_image_info(object);
if (!header){
post("pdp_v4l: ERROR: can't allocate packet");
return;
}
data = (short int *) pdp_packet_data(object);
newimage = x->x_videobuf + x->x_vmbuf.offsets[x->x_frame ^ 0x1];
/* convert data to pdp packet */
switch(x->x_v4l_palette){
case VIDEO_PALETTE_YUV420P:
pdp_llconv(newimage, RIF_YUV__P411_U8, data, RIF_YVU__P411_S16, w, h);
break;
/* long live standards. v4l's rgb is in fact ogl's bgr */
case VIDEO_PALETTE_RGB24:
pdp_llconv(newimage, RIF_BGR__P____U8, data, RIF_YVU__P411_S16, w, h);
break;
case VIDEO_PALETTE_RGB32:
pdp_llconv(newimage, RIF_BGRA_P____U8, data, RIF_YVU__P411_S16, w, h);
break;
case VIDEO_PALETTE_YUV422:
pdp_llconv(newimage, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, w, h);
break;
default:
post("pdp_v4l: unsupported palette");
break;
}
/*
if (PDP_IMAGE_YV12 == x->x_pdp_image_type){
pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
pixel_unpack_u8s16_uv(&newimage[plane1], &data[plane2], nbpixels>>5, x->x_state_data->gain);
pixel_unpack_u8s16_uv(&newimage[plane2], &data[plane1], nbpixels>>5, x->x_state_data->gain);
}
*/
//x->x_v4l_palette = VIDEO_PALETTE_YUV420P;
//x->x_v4l_palette = VIDEO_PALETTE_RGB24;
/*
else if(PDP_IMAGE_GREY == x->x_pdp_image_type){
pixel_unpack_u8s16_y(&newimage[0], data, nbpixels>>3, x->x_state_data->gain);
}
*/
//post("pdp_v4l: mark unused %d", object);
pdp_packet_pass_if_valid(x->x_outlet0, &object);
}
static void pdp_v4l_setlegaldim(t_pdp_v4l *x, int xx, int yy)
{
unsigned int w,h;
w = pdp_imageproc_legalwidth((int)xx);
h = pdp_imageproc_legalheight((int)yy);
w = (w < x->x_maxwidth) ? w : x->x_maxwidth;
w = (w > x->x_minwidth) ? w : x->x_minwidth;
h = (h < x->x_maxheight) ? h : x->x_maxheight;
h = (h > x->x_minheight) ? h : x->x_minheight;
x->x_width = w;
x->x_height = h;
}
static void pdp_v4l_dim(t_pdp_v4l *x, t_floatarg xx, t_floatarg yy)
{
if (x->x_initialized){
pdp_v4l_close(x);
pdp_v4l_setlegaldim(x, (int)xx, (int)yy);
pdp_v4l_open(x, x->x_device);
}
else{
pdp_v4l_setlegaldim(x, (int)xx, (int)yy);
}
}
static void pdp_v4l_format(t_pdp_v4l *x, t_symbol *s)
{
if (s == gensym("YUV420P")) x->x_format = 1;
else if (s == gensym("YUV422")) x->x_format = 2;
else if (s == gensym("RGB24")) x->x_format = 3;
else if (s == gensym("RGB32")) x->x_format = 4;
else if (s == gensym("auto")) x->x_format = 0;
else {
post("pdp_v4l: format %s unknown, using autodetect", s->s_name);
x->x_format = 0;
}
if (x->x_initialized){
pdp_v4l_close(x);
pdp_v4l_open(x, x->x_device);
}
}
static void pdp_v4l_free(t_pdp_v4l *x)
{
pdp_v4l_close(x);
}
t_class *pdp_v4l_class;
void *pdp_v4l_new(t_symbol *vdef, t_symbol *format)
{
t_pdp_v4l *x = (t_pdp_v4l *)pd_new(pdp_v4l_class);
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
x->x_initialized = false;
x->x_tvfd = -1;
x->x_frame = 0;
x->x_last_frame = 0;
x->x_framerate = 27;
x->x_auto_open = true;
if (vdef != gensym("")){
x->x_device = vdef;
}
else{
x->x_device = gensym("/dev/video0");
}
if (format != gensym("")){
pdp_v4l_format(x, format);
}
else {
x->x_format = 0; // default is autodetect
}
x->x_continue_thread = 0;
x->x_only_new_frames = 1;
x->x_width = 320;
x->x_height = 240;
// pdp_v4l_type(x, gensym("yv12"));
x->x_open_retry = PDP_XV_RETRIES;
x->x_channel = 0;
x->x_norm = 0; // PAL
x->x_freq = -1; //don't set freq by default
x->x_minwidth = pdp_imageproc_legalwidth(0);
x->x_maxwidth = pdp_imageproc_legalwidth_round_down(0x7fffffff);
x->x_minheight = pdp_imageproc_legalheight(0);
x->x_maxheight = pdp_imageproc_legalheight_round_down(0x7fffffff);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_v4l_setup(void)
{
pdp_v4l_class = class_new(gensym("pdp_v4l"), (t_newmethod)pdp_v4l_new,
(t_method)pdp_v4l_free, sizeof(t_pdp_v4l), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_bang, gensym("bang"), A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_audio, gensym("audio"), A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_close_manual, gensym("close"), A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_open_manual, gensym("open"), A_SYMBOL, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_channel, gensym("channel"), A_FLOAT, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_norm, gensym("norm"), A_SYMBOL, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_dim, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freq, gensym("freq"), A_FLOAT, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_freqMHz, gensym("freqMHz"), A_FLOAT, A_NULL);
class_addmethod(pdp_v4l_class, (t_method)pdp_v4l_format, gensym("captureformat"), A_SYMBOL, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: Makefile ---
current: all_modules
include ../../Makefile.config
# build optional modules
all_modules: $(PDP_OPTMOD)
clean:
rm -f *~
rm -f *.o
--- NEW FILE: pdp_xv.c ---
/*
* Pure Data Packet module. Xvideo image packet output
* Copyright (c) by Tom Schouten <pdp at zzz.kotnet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
// pdp stuff
#include "pdp.h"
#include "pdp_base.h"
// some x window glue code
#include "pdp_xwindow.h"
#include "pdp_xvideo.h"
#define PDP_XV_AUTOCREATE_RETRY 10
typedef struct pdp_xv_struct
{
t_object x_obj;
t_pdp_xdisplay *x_xdpy;
t_pdp_xwindow *x_xwin;
t_pdp_xvideo *x_xvid;
t_outlet *x_outlet;
int x_packet0;
int x_queue_id;
t_symbol *x_display;
//Display *x_dpy;
int x_initialized;
int x_autocreate;
} t_pdp_xv;
static void pdp_xv_cursor(t_pdp_xv *x, t_floatarg f)
{
if (x->x_xwin) pdp_xwindow_cursor(x->x_xwin, f);
}
/* delete all submodules */
static void _pdp_xv_cleanup(t_pdp_xv *x)
{
if (x->x_xwin) pdp_xwindow_free(x->x_xwin);
if (x->x_xvid) pdp_xvideo_free(x->x_xvid);
if (x->x_xdpy) pdp_xdisplay_free(x->x_xdpy);
x->x_xwin = 0;
x->x_xvid = 0;
x->x_xdpy = 0;
x->x_initialized = 0;
}
/* wait for thread to finish */
static void _pdp_xv_waitforthread(t_pdp_xv *x)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
pdp_procqueue_finish(q, x->x_queue_id); // wait for thread to finish
x->x_queue_id = -1;
}
// this destroys the window and all the x connections
static void pdp_xv_destroy(t_pdp_xv* x)
{
if (x->x_initialized){
_pdp_xv_waitforthread(x); // wait for thread
_pdp_xv_cleanup(x); // delete all objects
pdp_packet_mark_unused(x->x_packet0); // delete packet
x->x_packet0 = -1;
x->x_initialized = 0;
}
}
/* this creates a window (opens a dpy connection, creates xvideo and xwinow objects) */
static void pdp_xv_create(t_pdp_xv* x)
{
int i;
if(x->x_initialized) return;
/* open a display */
if (!(x->x_xdpy = pdp_xdisplay_new(x->x_display->s_name))) goto exit;
/* open an xv port on the display */
x->x_xvid = pdp_xvideo_new();
if (!pdp_xvideo_open_on_display(x->x_xvid, x->x_xdpy)) goto exit;
/* create a window on the display */
x->x_xwin = pdp_xwindow_new();
if (!pdp_xwindow_create_on_display(x->x_xwin, x->x_xdpy)) goto exit;
/* done */
x->x_initialized = 1;
return;
/* cleanup exits */
exit:
post("pdp_xv: cant open display %s\n",x->x_display->s_name);
_pdp_xv_cleanup(x);
}
static int pdp_xv_try_autocreate(t_pdp_xv *x)
{
if (x->x_autocreate){
post("pdp_xv: autocreate window");
pdp_xv_create(x);
if (!(x->x_initialized)){
x->x_autocreate--;
if (!x->x_autocreate){
post ("pdp_xv: autocreate failed %d times: disabled", PDP_XV_AUTOCREATE_RETRY);
post ("pdp_xv: send [autocreate 1] message to re-enable");
return 0;
}
}
else return 1;
}
return 0;
}
static void pdp_xv_bang(t_pdp_xv *x);
static void pdp_xv_bang_thread(t_pdp_xv *x)
{
pdp_xvideo_display_packet(x->x_xvid, x->x_xwin, x->x_packet0);
}
static void pdp_xv_bang_callback(t_pdp_xv *x)
{
/* receive events + send to outputs */
t_pdp_list *eventlist = pdp_xwindow_get_eventlist(x->x_xwin);
t_pdp_atom *a;
for (a=eventlist->first; a; a=a->next){
//pdp_list_print(a->w.w_list);
outlet_pdp_list(x->x_outlet, a->w.w_list);
}
/* free list */
pdp_tree_free(eventlist);
/* release the packet if there is one */
pdp_packet_mark_unused(x->x_packet0);
x->x_packet0 = -1;
}
/* manually poll for events */
static void pdp_xv_poll(t_pdp_xv *x)
{
if (x->x_initialized)
pdp_xv_bang_callback(x);
}
static void pdp_xv_bang(t_pdp_xv *x)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
/* check if window is initialized */
if (!(x->x_initialized)){
if (!pdp_xv_try_autocreate(x)) return;
}
/* check if we can proceed */
if (-1 != x->x_queue_id) return;
if (-1 == x->x_packet0) return;
/* if previous queued method returned
schedule a new one, else ignore */
if (-1 == x->x_queue_id) {
pdp_procqueue_add(q, x, pdp_xv_bang_thread, pdp_xv_bang_callback, &x->x_queue_id);
}
}
static void pdp_xv_input_0(t_pdp_xv *x, t_symbol *s, t_floatarg f)
{
if (s == gensym("register_ro")) pdp_packet_convert_ro_or_drop(&x->x_packet0, (int)f, pdp_gensym("bitmap/yv12/*"));
if (s == gensym("process")) pdp_xv_bang(x);
}
static void pdp_xv_autocreate(t_pdp_xv *x, t_floatarg f)
{
if (f != 0.0f) x->x_autocreate = PDP_XV_AUTOCREATE_RETRY;
else x->x_autocreate = 0;
}
static void pdp_xv_display(t_pdp_xv *x, t_symbol *s)
{
_pdp_xv_waitforthread(x);
x->x_display = s;
/* only create if already active */
if (x->x_initialized){
pdp_xv_destroy(x);
pdp_xv_create(x);
}
}
static void pdp_xv_movecursor(t_pdp_xv *x, float cx, float cy)
{
if (x->x_initialized){
cx *= x->x_xwin->winwidth;
cy *= x->x_xwin->winheight;
pdp_xwindow_warppointer(x->x_xwin, cx, cy);
}
}
static void pdp_xv_fullscreen(t_pdp_xv *x)
{
if (x->x_initialized)
pdp_xwindow_fullscreen(x->x_xwin);
}
static void pdp_xv_resize(t_pdp_xv* x, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_resize(x->x_xwin, width, height);
}
static void pdp_xv_move(t_pdp_xv* x, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_move(x->x_xwin, width, height);
}
static void pdp_xv_moveresize(t_pdp_xv* x, t_floatarg xoff, t_floatarg yoff, t_floatarg width, t_floatarg height)
{
if (x->x_initialized)
pdp_xwindow_moveresize(x->x_xwin, xoff, yoff, width, height);
}
static void pdp_xv_tile(t_pdp_xv* x, t_floatarg xtiles, t_floatarg ytiles, t_floatarg i, t_floatarg j)
{
if (x->x_initialized)
pdp_xwindow_tile(x->x_xwin, xtiles, ytiles, i, j);
}
static void pdp_xv_vga(t_pdp_xv *x)
{
pdp_xv_resize(x, 640, 480);
}
static void pdp_xv_free(t_pdp_xv *x)
{
pdp_xv_destroy(x);
}
t_class *pdp_xv_class;
void *pdp_xv_new(void)
{
t_pdp_xv *x = (t_pdp_xv *)pd_new(pdp_xv_class);
x->x_outlet = outlet_new(&x->x_obj, &s_anything);
x->x_xwin = 0;
x->x_xvid = 0;
x->x_xdpy = 0;
x->x_packet0 = -1;
x->x_queue_id = -1;
x->x_display = gensym(":0");
x->x_xdpy = 0;
pdp_xv_autocreate(x,1);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_xv_setup(void)
{
pdp_xv_class = class_new(gensym("pdp_xv"), (t_newmethod)pdp_xv_new,
(t_method)pdp_xv_free, sizeof(t_pdp_xv), 0, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_bang, gensym("bang"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("open"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_create, gensym("create"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_autocreate, gensym("autocreate"), A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("destroy"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_destroy, gensym("close"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("dim"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_move, gensym("move"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_move, gensym("pos"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_display, gensym("display"), A_SYMBOL, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_cursor, gensym("cursor"), A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_movecursor, gensym("movecursor"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_fullscreen, gensym("fullscreen"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_poll, gensym("poll"), A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_moveresize, gensym("posdim"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_xv_class, (t_method)pdp_xv_tile, gensym("tile"), A_FLOAT, A_FLOAT, A_FLOAT, A_FLOAT, A_NULL);
/* some shortcuts for the lazy */
class_addmethod(pdp_xv_class, (t_method)pdp_xv_vga, gensym("vga"), A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: README ---
This directory contains input/output modules for image packets.
Most of this is platform dependent stuff, and will be conditionally compiled.
--- NEW FILE: pdp_sdl.c ---
/*
* Pure Data Packet module.
* Copyright (c) 2003 by martin pi <pi at attacksyour.net>
* Copyright (c) by Tom Schouten <pdp at zzz.kotnet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
/*
pdp sdl output
DONE:
TODO:
* close window (event)
* fullscreen chose resolution
* event handling in different object (and look at mplayer for that!)
*/
#include <stdio.h>
#include <SDL/SDL.h>
#include "pdp.h"
#include "pdp_llconv.h"
/* initial image dimensions */
#define WINWIDTH 640
#define WINHEIGHT 480
#define OVERLAYWIDTH 320
#define OVERLAYHEIGHT 240
typedef struct pdp_sdl_struct {
t_object x_obj;
SDL_Surface *x_surface;
SDL_Overlay *x_overlay;
int x_surface_flags;
int x_surface_width;
int x_surface_height;
unsigned int x_overlay_width;
unsigned int x_overlay_height;
t_outlet *x_outlet;
} t_pdp_sdl;
static t_pdp_sdl *sdl_singleton; // only one instance allowed
static void destroy_overlay(t_pdp_sdl *x) {
if (x->x_overlay){
SDL_FreeYUVOverlay(x->x_overlay);
x->x_overlay = 0;
}
}
static void create_overlay(t_pdp_sdl *x, int width, int height) {
if (x->x_surface){
if (x->x_overlay = SDL_CreateYUVOverlay(width, height, SDL_YV12_OVERLAY, x->x_surface)){
x->x_overlay_width = width;
x->x_overlay_height = height;
return;
}
}
pdp_post("SDL: can't create overlay.");
}
static void check_overlay(t_pdp_sdl *x, unsigned int width, unsigned int height){
if (!x->x_overlay
|| (x->x_overlay_width != width)
|| (x->x_overlay_height != height)){
destroy_overlay(x);
create_overlay(x, width, height);
}
}
static void create_surface(t_pdp_sdl *x, int width, int height, int flags)
{
flags |= SDL_HWSURFACE|SDL_ANYFORMAT|SDL_RESIZABLE; // add default flags
// flags |= SDL_HWSURFACE|SDL_ANYFORMAT; // add default flags
// flags |= SDL_SWSURFACE|SDL_ANYFORMAT; // add default flags
/* flags:
SDL_HWSURFACE use hardware surface
SDL_ANYFORMAT return current surface, even if it doesn't match
SDL_OPENGL|SDL_DOUBLEBUF double buffer and opengl
SDL_RLEACCEL rle accelleration for blitting
SDL_FULLSCREEN fullscreen window
*/
//pdp_post("create_surface %d %d %d", width, height, flags);
/* check args */
if (width < 1) width = 1;
if (height < 1) height = 1;
/* free old stuff */
if (x->x_overlay) destroy_overlay(x);
/* form manpage:
The framebuffer surface, or NULL if it fails. The surface returned
is freed by SDL_Quit() and should nt be freed by the caller. */
if (x->x_surface) { /*SDL_FreeSurface(surface);*/ }
/* create new surface */
if (!(x->x_surface = SDL_SetVideoMode(width, height, 16, flags))){
pdp_post("SDL: Couldn't create a surface: %s", SDL_GetError());
return;
}
/* setup surface */
SDL_WM_SetCaption("pdp", "pdp");
SDL_ShowCursor(0);
/* set event mask to something conservative
and add a word to ask for some types of events */
x->x_surface_width = width;
x->x_surface_height = height;
x->x_surface_flags = flags;
}
static void poll_events(t_pdp_sdl *x){
SDL_Event event;
static t_symbol *keydown=0, *keyup, *quit, *motion;
t_atom atom;
/* cache symbols */
if (!keydown){
keydown = gensym("keypress");
keyup = gensym("keyrelease");
quit = gensym("quit");
}
if (!x->x_surface) return;
/* poll events */
while(SDL_PollEvent(&event)){
switch(event.type){
case SDL_KEYDOWN:
SETFLOAT(&atom, (float)event.key.keysym.scancode);
outlet_anything(x->x_outlet, keydown, 1, &atom);
break;
case SDL_KEYUP:
SETFLOAT(&atom, (float)event.key.keysym.scancode);
outlet_anything(x->x_outlet, keyup, 1, &atom);
break;
case SDL_QUIT:
outlet_symbol(x->x_outlet, quit);
break;
case SDL_VIDEORESIZE:
create_surface(x, event.resize.w, event.resize.h, x->x_surface_flags);
break;
}
}
}
static void fullscreen(t_pdp_sdl *x, t_floatarg f)
{
post("fullscreen not implemented");
}
static void resize(t_pdp_sdl *x, t_floatarg fw, t_floatarg fh)
{
create_surface(x, (int)fw, (int)fh, 0);
}
static void input_0(t_pdp_sdl *x, t_symbol *s, t_floatarg f) {
int input_packet = (int)f;
if (s == gensym("register_ro")){
int p = pdp_packet_convert_ro(input_packet, pdp_gensym("bitmap/yv12/*"));
/* poll anyway. */
//poll_events(x);
/* check packet */
if (-1 == p){
post("SDL: can't convert image to bitmap/yv12/*");
return;
}
else {
t_bitmap *bitmap = pdp_packet_subheader(p);
unsigned char *data = pdp_packet_data(p);
int planesize = bitmap->width * bitmap->height;
check_overlay(x, bitmap->width, bitmap->height);
if (x->x_overlay){
SDL_Rect rect = {0, 0, x->x_surface_width, x->x_surface_height};
/* copy */
SDL_LockYUVOverlay(x->x_overlay);
memcpy(x->x_overlay->pixels[0], data, planesize); data += planesize;
memcpy(x->x_overlay->pixels[1], data, planesize >> 2); data += (planesize >> 2);
memcpy(x->x_overlay->pixels[2], data, planesize >> 2);
SDL_UnlockYUVOverlay(x->x_overlay);
/* display */
if (SDL_DisplayYUVOverlay(x->x_overlay, &rect)){
pdp_post("SDL: can't display overlay");
return;
}
}
else {
pdp_post("SDL: error creating overlay");
}
pdp_packet_mark_unused(p);
return;
}
}
}
static void pdp_sdl_free(t_pdp_sdl *x)
{
destroy_overlay(x);
sdl_singleton = 0;
SDL_Quit();
}
t_class *pdp_sdl_class;
void *pdp_sdl_new(t_floatarg width, t_floatarg height) {
t_pdp_sdl *x;
int w = (int)width;
int h = (int)height;
if (sdl_singleton) {
post("Only one sdl object allowed.");
return 0;
}
if( SDL_Init(SDL_INIT_VIDEO) < 0 ) {
pdp_post("Could not initialize SDL: %s", SDL_GetError());
return 0;
}
atexit(SDL_Quit);
x = (t_pdp_sdl *)pd_new(pdp_sdl_class);
sdl_singleton = x;
x->x_surface = NULL;
x->x_overlay = NULL;
x->x_outlet = outlet_new(&x->x_obj, &s_anything);
/* try to create a surface */
create_surface(x, w ? w : WINWIDTH, h ? h : WINHEIGHT, 0);
if (!x->x_surface){
pdp_post("Can't create surface");
goto error_cleanup;
}
/* try to create overlay */
check_overlay(x, 320, 240);
if (!x->x_overlay){
pdp_post("Can't create overlay");
goto error_cleanup;
}
return (void *)x;
error_cleanup:
pdp_sdl_free(x);
return (void *)0;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_sdl_setup(void)
{
sdl_singleton = 0;
pdp_sdl_class = class_new(gensym("pdp_sdl"), (t_newmethod)pdp_sdl_new,
(t_method)pdp_sdl_free, sizeof(t_pdp_sdl), 0, A_NULL);
class_addmethod(pdp_sdl_class, (t_method)resize, gensym("size"), A_FLOAT, A_FLOAT, A_NULL);
class_addmethod(pdp_sdl_class, (t_method)poll_events, gensym("poll"), A_NULL);
class_addmethod(pdp_sdl_class, (t_method)fullscreen, gensym("fullscreen"), A_FLOAT, A_NULL);
class_addmethod(pdp_sdl_class, (t_method)input_0, gensym("pdp"), A_SYMBOL, A_DEFFLOAT, A_NULL);
}
#ifdef __cplusplus
}
#endif
--- NEW FILE: pdp_qt.c ---
/*
* Pure Data Packet module.
* Copyright (c) by Tom Schouten <pdp at zzz.kotnet.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., 675 Mass Ave, Cambridge, MA 02139, USA.
*
*/
#include <quicktime/lqt.h>
#include <quicktime/colormodels.h>
#include "pdp.h"
#include "pdp_llconv.h"
#define min(x,y) ((x<y)?(x):(y))
#define FREE(x) {if (x) {pdp_dealloc(x); x=0;} else post("free null pointer");}
/* debug macro */
//#define DEBUG_MSG_ENABLED
#ifdef DEBUG_MSG_ENABLED
#define DEBUG_MSG(EXP)\
fprintf (stderr, "mark start: [" #EXP "], on line %d\n", __LINE__);\
EXP \
fprintf (stderr, "mark end: [" #EXP "], on line %d\n", __LINE__);
#else
#define DEBUG_MSG(EXP) EXP
#endif
typedef struct pdp_qt_struct
{
t_object x_obj;
t_float x_f;
float x_gain;
t_symbol *x_name; // this is our name
int x_istilde; // 0==pdp_qt / 1==pdp_qt~
int x_syncaudio;
/* clock object */
t_clock *x_clock;
int x_counter;
int x_queue_id;
/* audio outlets */
t_outlet *x_outleft;
t_outlet *x_outright;
/* message outlets */
t_outlet *x_outlet0;
t_outlet *x_outlet1;
t_outlet *x_outlet2;
/* pdp data */
int x_packet0;
/* toggles */
int x_loop;
int x_autoplay;
/* qt data */
unsigned char ** x_qt_rows; // pointer array to rows / colour planes
float ** x_qt_audiochans; // pointer array to audio channel buffers
unsigned char * x_qt_frame;
quicktime_t *x_qt;
int x_qt_cmodel;
//t_pdp_qt_data *x_state_data;
/* audio data */
int x_chunk_current;
float *x_chunk_buf;
float *x_chunk[2][2];
int x_chunk_used[2]; // marks if chunk is used or not
int x_chunk_size;
int x_chunk_pos;
/* global state */
int x_initialized;
int x_frame;
int x_frame_thread;
int x_process_in_thread;
/* audio info */
int x_audio_tracks; // ==0 means audio not available
int x_audio_channels;
long x_audio_samplerate;
long x_audio_length;
/* video info */
int x_video_tracks; // ==0 means video not available
float x_video_framerate;
long x_video_length;
unsigned int x_video_width;
unsigned int x_video_height;
} t_pdp_qt;
static void pdp_qt_bang(t_pdp_qt *x);
static void pdp_qt_close(t_pdp_qt *x)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
/* disable clock */
clock_unset(x->x_clock);
pdp_procqueue_finish(q, x->x_queue_id);
if (x->x_initialized){
/* close file */
quicktime_close(x->x_qt);
x->x_initialized = 0;
/* free video data */
if (x->x_video_tracks){
FREE(x->x_qt_frame);
FREE(x->x_qt_rows);
x->x_video_tracks = 0;
//x->x_qt_rows = 0;
//x->x_qt_frame = 0;
}
/* free audio data */
if (x->x_audio_tracks){
x->x_chunk_used[0] = 0;
x->x_chunk_used[1] = 0;
FREE(x->x_chunk_buf);
FREE(x->x_qt_audiochans);
x->x_audio_tracks = 0;
//x->x_qt_audiochans = 0;
//x->x_chunk_buf = 0;
x->x_chunk[0][0] = 0;
x->x_chunk[0][1] = 0;
x->x_chunk[1][0] = 0;
x->x_chunk[1][1] = 0;
}
}
}
void pdp_qt_create_pdp_packet(t_pdp_qt *x)
{
t_pdp *header;
t_image *image;
/* round to next legal size */
/* if size is illegal, image distortion will occur */
u32 w = pdp_imageproc_legalwidth(x->x_video_width);
u32 h = pdp_imageproc_legalheight(x->x_video_height);
int nbpixels = w * h;
int packet_size = (nbpixels + (nbpixels >> 1)) << 1;
pdp_packet_mark_unused(x->x_packet0);
x->x_packet0 = pdp_packet_new_image_YCrCb(w, h);
header = pdp_packet_header(x->x_packet0);
image = pdp_packet_image_info(x->x_packet0);
if (!header){
post("%s: ERROR: can't create new packet", x->x_name->s_name);
return;
}
//header->info.image.encoding = (x->x_qt_cmodel == BC_RGB888) ? PDP_IMAGE_GREY : PDP_IMAGE_YV12;
//image->encoding = PDP_IMAGE_YV12;
//image->width = w;
//image->height = h;
}
static void pdp_qt_open(t_pdp_qt *x, t_symbol *name)
{
unsigned int size;
unsigned int i;
unsigned int chunk_bytesize;
post("%s: opening %s", x->x_name->s_name, name->s_name);
/* close previous one */
pdp_qt_close(x);
/* check if qt file */
if(0 == quicktime_check_sig(name->s_name)){
post("%s: ERROR: not a quicktime file", x->x_name->s_name);
goto exit;
}
/* open */
DEBUG_MSG(x->x_qt = quicktime_open(name->s_name, 1, 0);)
if (!(x->x_qt)){
post("%s: ERROR: can't open file", x->x_name->s_name);
goto exit;
}
/* check video */
x->x_video_tracks = 0;
if (quicktime_has_video(x->x_qt)) {
x->x_video_framerate = quicktime_frame_rate (x->x_qt, 0);
x->x_video_length = quicktime_video_length (x->x_qt, 0);
x->x_video_width = quicktime_video_width (x->x_qt, 0);
x->x_video_height = quicktime_video_height (x->x_qt, 0);
post("%s: video stream found (%dx%d pixels, %0.00f fps, %d frames, %s codec)",
x->x_name->s_name, x->x_video_width, x->x_video_height, x->x_video_framerate,
x->x_video_length, quicktime_video_compressor(x->x_qt, 0));
x->x_video_tracks = quicktime_video_tracks(x->x_qt);
}
/* check audior */
x->x_audio_tracks = 0;
if (quicktime_has_audio(x->x_qt)) {
x->x_audio_tracks = quicktime_audio_tracks (x->x_qt);
//x->x_audio_channels = quicktime_track_channels (x->x_qt, 0);
x->x_audio_channels = lqt_total_channels (x->x_qt);
x->x_audio_samplerate = quicktime_sample_rate (x->x_qt, 0);
x->x_audio_length = quicktime_audio_length (x->x_qt, 0);
x->x_chunk_size = (int)((float)x->x_audio_samplerate / x->x_video_framerate);
post("%s: audio stream found (%d channels, %d Hz, %d samples, chunksize %d)",
x->x_name->s_name, x->x_audio_channels, x->x_audio_samplerate, x->x_audio_length, x->x_chunk_size);
}
/* check if video codec is supported */
if (x->x_video_tracks){
if (!quicktime_supported_video(x->x_qt,0)) {
post("%s: WARNING: unsupported video codec",x->x_name->s_name);
x->x_video_tracks = 0;
}
}
/* check if audio codec is supported */
if (x->x_audio_tracks){
if (!quicktime_supported_audio(x->x_qt,0)) {
post("%s: WARNING: unsupported audio codec", x->x_name->s_name);
x->x_audio_tracks = 0;
}
}
/* check which colormodel to use */
if (x->x_video_tracks){
if (quicktime_reads_cmodel(x->x_qt,BC_YUV420P,0)){
post("%s: using colormodel YUV420P", x->x_name->s_name);
x->x_qt_cmodel = BC_YUV420P;
}
else if (quicktime_reads_cmodel(x->x_qt,BC_YUV422,0)){
post("%s: using colormodel YUV422", x->x_name->s_name);
x->x_qt_cmodel = BC_YUV422;
}
else if (quicktime_reads_cmodel(x->x_qt,BC_RGB888,0)){
post("%s: using colormodel RGB888", x->x_name->s_name);
x->x_qt_cmodel = BC_RGB888;
}
else {
post("%s: WARNING: can't find a usable colour model", x->x_name->s_name);
x->x_video_tracks = 0;
}
}
/* no video == errors */
if (!x->x_video_tracks) {
post("%s: ERROR: no usable video stream found.", x->x_name->s_name);
goto exit_close;
}
/* initialize video data structures */
if (x->x_video_tracks){
/* allocate enough space for all supported colormodels (24bpp)*/
x->x_frame = 0;
x->x_qt_frame = (unsigned char*)pdp_alloc(x->x_video_width * x->x_video_height * 3);
x->x_qt_rows = (unsigned char **)pdp_alloc(sizeof(unsigned char *) * x->x_video_height);
size = x->x_video_width * x->x_video_height;
switch(x->x_qt_cmodel){
case BC_YUV420P:
/* planar with u&v 2x2 subsampled */
x->x_qt_rows[0] = &x->x_qt_frame[0];
x->x_qt_rows[2] = &x->x_qt_frame[size];
x->x_qt_rows[1] = &x->x_qt_frame[size + (size>>2)];
break;
case BC_YUV422:
/* packed with u&v 2x subsampled (lines) */
/* later on we will convert this to planar */
for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 2];
break;
case BC_RGB888:
/* packed rgb */
/* later on we will convert this to planar */
for(i=0; i< x->x_video_height; i++) x->x_qt_rows[i] = &x->x_qt_frame[i * x->x_video_width * 3];
break;
default:
post("%s: error on init: unkown colour model",x->x_name->s_name);
break;
}
DEBUG_MSG(quicktime_set_cmodel(x->x_qt, x->x_qt_cmodel);)
outlet_float(x->x_outlet2, (float)quicktime_video_length(x->x_qt,0));
}
/* initialize audio data structures */
if (x->x_audio_tracks){
x->x_chunk_pos = 0;
x->x_chunk_current = 0;
chunk_bytesize = sizeof(float)*x->x_chunk_size;
x->x_chunk_buf = (float *)pdp_alloc(chunk_bytesize * 4);
memset(x->x_chunk_buf, 0, chunk_bytesize * 4);
x->x_chunk[0][0] = x->x_chunk_buf;
x->x_chunk[0][1] = x->x_chunk_buf + x->x_chunk_size ;
x->x_chunk[1][0] = x->x_chunk_buf + x->x_chunk_size * 2;
x->x_chunk[1][1] = x->x_chunk_buf + x->x_chunk_size * 3;
x->x_chunk_used[0] = 0;
x->x_chunk_used[1] = 0;
x->x_syncaudio = x->x_istilde; //sync on audio if this is a tilde object
DEBUG_MSG(if (x->x_audio_channels == 0) exit(1);)
x->x_qt_audiochans = (float **)pdp_alloc(x->x_audio_channels * sizeof(float **));
memset(x->x_qt_audiochans, 0, x->x_audio_channels * sizeof(float **));
}
else {
x->x_syncaudio = 0;
}
/* everything went well */
x->x_initialized = 1;
/* start playback if outplay is on */
if(x->x_autoplay) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
/* brag about success */
post("%s: %s opened", x->x_name->s_name, name->s_name);
return;
/* error exits */
exit_close:
DEBUG_MSG(quicktime_close(x->x_qt);)
exit:
x->x_initialized = 0;
x->x_audio_tracks = 0;
x->x_video_tracks = 0;
return;
}
//static void pdp_qt_setposition(t_pdp_qt *x, int pos)
//{
// x->x_frame = pos;
// DEBUG_MSG(if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, pos, 0);)
// DEBUG_MSG(if(x->x_audio_tracks) quicktime_set_audio_position(x->x_qt, pos * x->x_chunk_size, 0);)
//
//}
static void pdp_qt_bangaudio(t_pdp_qt *x)
{
int lefterr=0;
int righterr=0;
int err=0;
int sample = 0;
int remaining = 0;
int readamount = 0;
if (!x->x_initialized){
//post("pdp_qt: no qt file opened");
return;
}
if (!x->x_audio_tracks){
//post("pdp_qt: no audio stream present");
return;
}
//DEBUG_MSG(sample = quicktime_audio_position(x->x_qt,0);)
// if the active chunk is unused, clear it and mark it used
if (!x->x_chunk_used[x->x_chunk_current]){
//post("%s: clearing unused active chunk",x->x_name->s_name);
//probably this is the !@#%&*(*)&!$() bug
//memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
//memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float)*2*x->x_chunk_size);
memset(x->x_chunk[0][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
memset(x->x_chunk[1][x->x_chunk_current], 0, sizeof(float) * x->x_chunk_size);
x->x_chunk_used[x->x_chunk_current] = 1;
}
// compute the remaining time
DEBUG_MSG(remaining = (int ) ( quicktime_audio_length(x->x_qt, 0) - quicktime_audio_position(x->x_qt, 0) );)
readamount = min(remaining, x->x_chunk_size);
if (!readamount) return;
// if the inactive chunk is unused, fill it with the current frame's audio data and mark it used
if (!x->x_chunk_used[!x->x_chunk_current]){
switch(x->x_audio_channels){
case 1:
x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
x->x_qt_audiochans[1] = 0;
DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
break;
default:
x->x_qt_audiochans[0] = x->x_chunk[0][!x->x_chunk_current];
x->x_qt_audiochans[1] = x->x_chunk[1][!x->x_chunk_current];
DEBUG_MSG(err = lqt_decode_audio(x->x_qt, NULL, x->x_qt_audiochans, readamount);)
break;
}
x->x_chunk_used[!x->x_chunk_current] = 1;
}
// if it is used, something went wrong with sync
else{
//post("%s: dropping audio chunk %d.",x->x_name->s_name, x->x_frame_thread);
}
if (err) post("%s: error decoding audio",x->x_name->s_name, x->x_frame_thread);
// ensure audio pointer points to next frame's data
//DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample + readamount, 0);)
}
static void pdp_qt_bangvideo(t_pdp_qt *x)
{
unsigned int w, h, nbpixels, packet_size, i,j;
unsigned int *source, *dest;
unsigned int uoffset, voffset;
short int* data;
t_pdp* header;
// check if we want greyscale output or not
//int grey = (x->x_qt_cmodel == BC_RGB888);
static short int gain[4] = {0x7fff, 0x7fff, 0x7fff, 0x7fff};
if ((!x->x_initialized) || (!x->x_video_tracks)){
//post("pdp_qt: no qt file opened");
return;
}
w = x->x_video_width;
h = x->x_video_height;
nbpixels = x->x_video_width * x->x_video_height;
// create a new packet
pdp_qt_create_pdp_packet(x);
header = pdp_packet_header(x->x_packet0);
if (!header) {
post("%s: ERROR: no packet available", x->x_name->s_name);
return;
}
data = (short int *) pdp_packet_data(x->x_packet0);
DEBUG_MSG(lqt_decode_video(x->x_qt, x->x_qt_rows, 0);)
switch(x->x_qt_cmodel){
case BC_YUV420P:
pdp_llconv(x->x_qt_frame, RIF_YVU__P411_U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
break;
case BC_YUV422:
pdp_llconv(x->x_qt_frame, RIF_YUYV_P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
break;
case BC_RGB888:
pdp_llconv(x->x_qt_frame, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, x->x_video_width, x->x_video_height);
break;
default:
post("%s: error on decode: unkown colour model",x->x_name->s_name);
break;
}
}
static void pdp_qt_sendpacket(t_pdp_qt *x)
{
pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet0);
//if (x->x_packet0 != -1){
//pdp_packet_mark_unused(x->x_packet0);
//outlet_pdp(x->x_outlet0, x->x_packet0);
//x->x_packet0 = -1;
//}
}
static void pdp_qt_thread_bang(t_pdp_qt *x)
{
// set audio position
if(x->x_video_tracks) quicktime_set_video_position(x->x_qt, x->x_frame_thread, 0);
// bang video
pdp_qt_bangvideo(x);
// if it's a tilde object, bang audio
if (x->x_istilde && x->x_audio_tracks){
quicktime_set_audio_position(x->x_qt, x->x_frame_thread * x->x_chunk_size, 0);
pdp_qt_bangaudio(x);
}
}
static void pdp_qt_bang(t_pdp_qt *x)
{
int length, pos;
t_pdp_procqueue *q = pdp_queue_get_queue();
/* return if not initialized */
if (!x->x_initialized) return;
//length = quicktime_video_length(x->x_qt,0);
//pos = quicktime_video_position(x->x_qt,0);
length = x->x_video_length;
pos = x->x_frame;
/* check bounds */
if (x->x_loop){
pos = x->x_frame % length;
if (pos < 0) pos += length;
}
else{
if (pos < 0) pos = 0;
if (pos >= length) pos = length - 1;
}
/* store next frame for access in thread */
x->x_frame_thread = pos;
// if autoplay is on and we do not have audio synchro
// set clock to play next frame
if (x->x_autoplay && !x->x_syncaudio) clock_delay(x->x_clock, 1000.0L / (double)x->x_video_framerate);
// make sure prev decode is finished don't drop frames in this one
pdp_procqueue_finish(q, x->x_queue_id);
x->x_queue_id = -1;
/* only decode new stuff if previous is done */
if (-1 == x->x_queue_id){
// send the current frame number to outlet
outlet_float(x->x_outlet1, (float)pos);
//pdp_qt_setposition(x, pos);
// start process method
if (x->x_process_in_thread) pdp_procqueue_add(q, x, pdp_qt_thread_bang, pdp_qt_sendpacket, &x->x_queue_id);
else {
pdp_qt_thread_bang(x);
pdp_qt_sendpacket(x);
}
}
// advance frame
x->x_frame = pos + 1;
// send the packet
//pdp_qt_sendpacket(x);
}
//static void pdp_qt_getaudiochunk(t_pdp_qt *x, int channel)
//{
// if (!x->x_audio_tracks) return;
// quicktime_decode_audio(x->x_qt, NULL, x->x_chunk[channel][x->x_chunk_current], x->x_chunk_size<<1, channel);
//
//}
static void pdp_qt_loop(t_pdp_qt *x, t_floatarg loop)
{
int loopi = (int)loop;
x->x_loop = !(loopi == 0);
}
static void pdp_qt_autoplay(t_pdp_qt *x, t_floatarg play)
{
int playi = (int)play;
x->x_autoplay = !(playi == 0);
// reset clock if autoplay is off
if (!x->x_autoplay) clock_unset(x->x_clock);
}
static void pdp_qt_frame_cold(t_pdp_qt *x, t_floatarg frameindex)
{
int frame = (int)frameindex;
//int length;
x->x_frame = frame;
//if (!(x->x_initialized)) return;
//length = quicktime_video_length(x->x_qt,0);
//frame = (frame >= length) ? length-1 : frame;
//frame = (frame < 0) ? 0 : frame;
//pdp_qt_setposition(x, frame);
}
static void pdp_qt_frame(t_pdp_qt *x, t_floatarg frameindex)
{
pdp_qt_frame_cold(x, frameindex);
pdp_qt_bang(x);
}
static void pdp_qt_stop(t_pdp_qt *x)
{
pdp_qt_autoplay(x, 0);
}
static void pdp_qt_continue(t_pdp_qt *x)
{
pdp_qt_autoplay(x, 1);
pdp_qt_bang(x);
}
static void pdp_qt_play(t_pdp_qt *x){
pdp_qt_frame_cold(x, 0);
pdp_qt_continue(x);
}
static void pdp_qt_importaudio(t_pdp_qt *x, t_symbol *array, t_floatarg channel)
{
t_pdp_procqueue *q = pdp_queue_get_queue();
int c = (int)channel;
t_garray *g;
int vecsize;
int sample;
float *f;
int i;
/* if there's no audio, there's nothing to export */
if (!x->x_audio_tracks) return;
/* check audio channel */
if ((c < 0) || (c >= x->x_audio_channels)) return;
/* check if array exists */
if (!(g = (t_garray *)pd_findbyclass(array, garray_class))){
pd_error(x, "%s: no such table", array->s_name);
return;
}
post("%s: importing audio channel %d into array %s", x->x_name->s_name, c, array->s_name);
// make sure decode is finished
pdp_procqueue_finish(q, x->x_queue_id);
x->x_queue_id = -1;
/* resize array */
garray_resize(g, x->x_audio_length);
/* for sanity's sake let's clear the save-in-patch flag here */
garray_setsaveit(g, 0);
garray_getfloatarray(g, &vecsize, &f);
/* if the resize failed, garray_resize reported the error */
if (vecsize != x->x_audio_length){
pd_error(x, "array resize failed");
return;
}
/* save pointer in file */
DEBUG_MSG(sample = quicktime_audio_position(x->x_qt, 0);)
DEBUG_MSG(quicktime_set_audio_position(x->x_qt, 0, 0);)
/* transfer the audio file to the end of the array */
DEBUG_MSG(quicktime_decode_audio(x->x_qt, NULL, f, vecsize, c);)
/* restore pointer in file */
DEBUG_MSG(quicktime_set_audio_position(x->x_qt, sample, 0);)
}
static t_int *pdp_qt_perform(t_int *w)
{
t_pdp_qt *x = (t_pdp_qt *)w[1];
t_float *out0 = (t_float *)w[2];
t_float *out1 = (t_float *)w[3];
t_int n = (t_int)w[4];
t_int xfer_samples;
if (!x->x_initialized || !x->x_audio_tracks) goto zero;
while(1){
// check current chunk
if (!x->x_chunk_used[x->x_chunk_current]) goto zero;
// transfer from chunk to output
xfer_samples = min(n, x->x_chunk_size - x->x_chunk_pos);
//x->x_audio_channels = 1;
if (x->x_audio_channels == 1){
memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
memcpy(out1, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
}
else {
memcpy(out0, x->x_chunk[0][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
memcpy(out1, x->x_chunk[1][x->x_chunk_current] + x->x_chunk_pos, sizeof(float)*xfer_samples);
}
out0 += xfer_samples;
out1 += xfer_samples;
n -= xfer_samples;
x->x_chunk_pos += xfer_samples;
// check if chunk is finished, if so mark unused, swap buffers and set clock
if (x->x_chunk_size == x->x_chunk_pos){
x->x_chunk_used[x->x_chunk_current] = 0;
x->x_chunk_pos = 0;
x->x_chunk_current ^= 1;
if (x->x_autoplay) clock_delay(x->x_clock, 0L);
}
// if chunk is not finished, the output buffer is full
else{
goto exit;
}
}
zero:
// fill the rest of the output with zeros
memset(out0, 0, sizeof(float)*n);
memset(out1, 0, sizeof(float)*n);
exit:
return(w+5);
}
static void pdp_qt_dsp(t_pdp_qt *x, t_signal **sp)
{
dsp_add(pdp_qt_perform, 4, x, sp[0]->s_vec, sp[1]->s_vec, sp[0]->s_n);
}
static void pdp_qt_process_in_thread(t_pdp_qt *x, t_float f)
{
int t = (f != 0.0f);
x->x_process_in_thread = t;
post("pdp_qt: thread processing switched %d", t ? "on" : "off");
}
static void pdp_qt_tick(t_pdp_qt *x)
{
// bang audio/video
pdp_qt_bang(x);
}
static void pdp_qt_free(t_pdp_qt *x)
{
clock_unset(x->x_clock);
pdp_qt_close(x);
clock_free(x->x_clock);
//free (x->x_state_data);
}
t_class *pdp_qt_class;
t_class *pdp_qt_tilde_class;
void pdp_qt_init_common(t_pdp_qt *x)
{
inlet_new(&x->x_obj, &x->x_obj.ob_pd, gensym("float"), gensym("frame_cold"));
/* add common outlets */
x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
x->x_outlet1 = outlet_new(&x->x_obj, &s_float);
x->x_outlet2 = outlet_new(&x->x_obj, &s_float);
/* init */
x->x_gain = 1.0f;
x->x_process_in_thread = 0;
x->x_packet0 = -1;
x->x_queue_id = -1;
x->x_initialized = 0;
x->x_audio_tracks = 0;
x->x_video_tracks = 0;
x->x_loop = 0;
x->x_autoplay = 0;
x->x_chunk[0][0] = 0;
x->x_chunk[0][1] = 0;
x->x_chunk[1][0] = 0;
x->x_chunk[1][1] = 0;
/* initialize clock object */
x->x_clock = clock_new(x, (t_method)pdp_qt_tick);
}
void *pdp_qt_new(void)
{
t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_class);
x->x_name = gensym("pdp_qt");
x->x_istilde = 0;
pdp_qt_init_common(x);
return (void *)x;
}
void *pdp_qt_tilde_new(void)
{
t_pdp_qt *x = (t_pdp_qt *)pd_new(pdp_qt_tilde_class);
x->x_name = gensym("pdp_qt");
x->x_istilde = 1;
pdp_qt_init_common(x);
/* add outlets to the right so pdp_qt~ can replace pdp_qt without breaking a patch */
x->x_outleft = outlet_new(&x->x_obj, &s_signal);
x->x_outright = outlet_new(&x->x_obj, &s_signal);
return (void *)x;
}
#ifdef __cplusplus
extern "C"
{
#endif
void pdp_qt_setup_common(t_class *class)
{
class_addmethod(class, (t_method)pdp_qt_bang, gensym("bang"), A_NULL);
class_addmethod(class, (t_method)pdp_qt_close, gensym("close"), A_NULL);
class_addmethod(class, (t_method)pdp_qt_open, gensym("open"), A_SYMBOL, A_NULL);
class_addmethod(class, (t_method)pdp_qt_autoplay, gensym("autoplay"), A_DEFFLOAT, A_NULL);
class_addmethod(class, (t_method)pdp_qt_stop, gensym("stop"), A_NULL);
class_addmethod(class, (t_method)pdp_qt_play, gensym("play"), A_NULL);
class_addmethod(class, (t_method)pdp_qt_continue, gensym("cont"), A_NULL);
class_addmethod(class, (t_method)pdp_qt_loop, gensym("loop"), A_DEFFLOAT, A_NULL);
class_addfloat (class, (t_method)pdp_qt_frame);
class_addmethod(class, (t_method)pdp_qt_frame_cold, gensym("frame_cold"), A_FLOAT, A_NULL);
class_addmethod(class, (t_method)pdp_qt_process_in_thread, gensym("thread"), A_FLOAT, A_NULL);
class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("importaudio"), A_SYMBOL, A_DEFFLOAT, A_NULL);
class_addmethod(class, (t_method)pdp_qt_importaudio, gensym("dump"), A_SYMBOL, A_DEFFLOAT, A_NULL);
}
void pdp_qt_setup(void)
{
/* plain class */
pdp_qt_class = class_new(gensym("pdp_qt"), (t_newmethod)pdp_qt_new,
(t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
pdp_qt_setup_common(pdp_qt_class);
/* tilde class */
pdp_qt_tilde_class = class_new(gensym("pdp_qt~"), (t_newmethod)pdp_qt_tilde_new,
(t_method)pdp_qt_free, sizeof(t_pdp_qt), 0, A_NULL);
pdp_qt_setup_common(pdp_qt_tilde_class);
class_addmethod(pdp_qt_tilde_class, (t_method)pdp_qt_dsp, gensym("dsp"), 0);
}
#ifdef __cplusplus
}
#endif
- Previous message: [PD-cvs] externals/pdp/modules/image_special Makefile, 1.2, 1.3 README, 1.2, 1.3 pdp_array.c, 1.2, 1.3 pdp_chrot.c, 1.2, 1.3 pdp_cog.c, 1.2, 1.3 pdp_grey2mask.c, 1.2, 1.3 pdp_histo.c, 1.2, 1.3 pdp_scale.c, 1.2, 1.3 pdp_scan.c, 1.2, 1.3 pdp_scanxy.c, 1.2, 1.3 pdp_scope.c, 1.2, 1.3
- Next message: [PD-cvs] externals/pdp/opengl Makefile, 1.2, 1.3 Makefile.config, 1.2, 1.3 README, 1.2, 1.3 TODO, 1.2, 1.3
- Messages sorted by:
[ date ]
[ thread ]
[ subject ]
[ author ]
More information about the Pd-cvs
mailing list