aboutsummaryrefslogtreecommitdiff
path: root/modules/pdp_ieee1394.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pdp_ieee1394.c')
-rw-r--r--modules/pdp_ieee1394.c483
1 files changed, 483 insertions, 0 deletions
diff --git a/modules/pdp_ieee1394.c b/modules/pdp_ieee1394.c
new file mode 100644
index 0000000..189398f
--- /dev/null
+++ b/modules/pdp_ieee1394.c
@@ -0,0 +1,483 @@
+/*
+ * PiDiP module.
+ * Copyright (c) by Yves Degoyon (ydegoyon@free.fr)
+ *
+ * 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.
+ *
+ */
+
+/* This object is a ieee1394 video input object for OSX, using QuickTime
+ * Some code is inspired by pix_video from Gem
+ * Written by Yves Degoyon
+ */
+
+#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 <sys/mman.h>
+#include <sched.h>
+#include <pthread.h>
+#include <Carbon/Carbon.h>
+#include <Quicktime/QuickTime.h>
+#include <Quicktime/QuickTimeComponents.h>
+
+#define DEFAULT_WIDTH 320
+#define DEFAULT_HEIGHT 240
+
+typedef struct pdp_ieee1394_struct
+{
+ t_object x_obj;
+ t_float x_f;
+
+ t_outlet *x_outlet0;
+
+ bool x_initialized;
+ bool x_auto_open;
+
+ t_int x_packet;
+ t_pdp* x_header;
+ short int *x_data;
+ unsigned char *x_sdata; // static data to hold the grabbed images
+
+ unsigned int x_width;
+ unsigned int x_height;
+ unsigned int x_size;
+ int x_channel;
+ pthread_t x_thread_id;
+ int x_continue_thread;
+ unsigned int x_framerate;
+ int x_frame_ready;
+ t_int x_quality;
+
+ SeqGrabComponent x_sg;
+ SGChannel x_vc;
+ short x_pixelDepth;
+ Rect x_srcRect;
+ GWorldPtr x_srcGWorld;
+ PixMapHandle x_pixMap;
+ Ptr x_baseAddr;
+ long x_rowBytes;
+
+} t_pdp_ieee1394;
+
+static void pdp_ieee1394_close(t_pdp_ieee1394 *x)
+{
+ 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);
+ }
+
+ // free sequence grabber
+ // if (x->x_vc)
+ // {
+ // if (SGDisposeChannel(x->x_sg, x->x_vc))
+ // {
+ // post("pdp_ieee1394: unable to dispose video channel");
+ // }
+ // x->x_vc = NULL;
+ // post("pdp_ieee1394: disposed video channel");
+ // }
+ // if (x->x_sg)
+ // {
+ // if (CloseComponent(x->x_sg))
+ // {
+ // post("pdp_ieee1394: unable to free sequence grabber.");
+ // }
+ // x->x_sg = NULL;
+ // post("pdp_ieee1394: freed sequence grabber.");
+ // }
+ // if (x->x_srcGWorld)
+ // {
+ // DisposeGWorld(x->x_srcGWorld);
+ // post("pdp_ieee1394: disposed world.");
+ // x->x_srcGWorld = NULL;
+ // }
+
+}
+
+static void pdp_ieee1394_capture_frame(t_pdp_ieee1394* x)
+{
+ OSErr err;
+
+ err = SGIdle(x->x_sg);
+ if (err != noErr)
+ {
+ post("pdp_ieee1394: SGIdle failed.");
+ x->x_frame_ready = 0;
+ }
+ else
+ {
+ x->x_frame_ready = 1;
+ }
+}
+
+
+static void *pdp_ieee1394_thread(void *voidx)
+{
+ t_pdp_ieee1394 *x = ((t_pdp_ieee1394 *)voidx);
+
+ /* capture with a double buffering scheme */
+ while (true)
+ {
+ if (x->x_continue_thread)
+ {
+ /* schedule capture command for next frame */
+ pdp_ieee1394_capture_frame(x);
+ }
+ else
+ {
+ sleep(1);
+ }
+ }
+
+ x->x_thread_id = 0;
+ return 0;
+}
+
+static void pdp_ieee1394_reset(t_pdp_ieee1394 *x)
+{
+ OSErr anErr;
+
+ if ( !x->x_initialized )
+ {
+ post("pdp_ieee1394: trying to reset but the sequence grabber is not initialized");
+ return;
+ }
+
+ post("pdp_ieee1394: resetting....");
+
+ switch (x->x_quality)
+ {
+ case 0:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayNormal);
+ post("pdp_ieee1394: set sequence grabber to : normal quality");
+ break;
+ case 1:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayHighQuality);
+ post("pdp_ieee1394: set sequence grabber to : high quality");
+ break;
+ case 2:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayFast);
+ post("pdp_ieee1394: set sequence grabber to : fast quality");
+ break;
+ case 3:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayAllData);
+ post("pdp_ieee1394: set sequence grabber to : play all data");
+ break;
+ }
+
+ post("pdp_ieee1394: done.");
+}
+
+static void pdp_ieee1394_quality(t_pdp_ieee1394 *x, t_floatarg fquality)
+{
+ if ( ( (t_int)fquality < 0 ) || ( (t_int)fquality > 3 ) )
+ {
+ post("pdp_ieee1394: wrong quality %d", (t_int)fquality );
+ return;
+ }
+ else
+ {
+ x->x_quality = (t_int)fquality;
+ }
+}
+
+static void pdp_ieee1394_free(t_pdp_ieee1394 *x)
+{
+ pdp_ieee1394_close(x);
+}
+
+static t_int pdp_ieee1394_init_grabber(t_pdp_ieee1394 *x)
+{
+ OSErr anErr;
+ x->x_srcRect.top = 0;
+ x->x_srcRect.left = 0;
+ x->x_srcRect.bottom = x->x_height;
+ x->x_srcRect.right = x->x_width;
+
+ x->x_sg = OpenDefaultComponent(SeqGrabComponentType, 0);
+ if(x->x_sg==NULL)
+ {
+ post("pdp_ieee1394: could not open default component");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: opened default component");
+ }
+
+ anErr = SGInitialize(x->x_sg);
+ if(anErr!=noErr)
+ {
+ post("pdp_ieee1394: could not initialize sequence grabber");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: initialized sequence grabber");
+ }
+
+ anErr = SGSetDataRef(x->x_sg, 0, 0, seqGrabDontMakeMovie);
+ if (anErr != noErr)
+ {
+ post("pdp_ieee1394: couldn't set data ref");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: set data ref ok.");
+ }
+
+ anErr = SGNewChannel(x->x_sg, VideoMediaType, &x->x_vc);
+ if(anErr!=noErr)
+ {
+ post("pdp_ieee1394: could not create new sequence grabber channnel");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: created new sequence grabber channnel.");
+ }
+
+ anErr = SGSetChannelBounds(x->x_vc, &x->x_srcRect);
+ if(anErr!=noErr)
+ {
+ post("pdp_ieee1394: could not set sequence grabber ChannelBounds ");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: set sequence grabber ChannelBounds");
+ }
+
+ anErr = SGSetChannelUsage(x->x_vc, seqGrabPreview);
+ if(anErr!=noErr)
+ {
+ post("pdp_ieee1394: could not set sequence grabber ChannelUsage ");
+ return -1;
+ }
+ else
+ {
+ post("pdp_ieee1394: set sequence grabber ChannelUsage");
+ }
+
+ switch (x->x_quality)
+ {
+ case 0:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayNormal);
+ post("pdp_ieee1394: set sequence grabber to : normal quality");
+ break;
+ case 1:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayHighQuality);
+ post("pdp_ieee1394: set sequence grabber to : high quality");
+ break;
+ case 2:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayFast);
+ post("pdp_ieee1394: set sequence grabber to : fast quality");
+ break;
+ case 3:
+ anErr = SGSetChannelPlayFlags(x->x_vc, channelPlayAllData);
+ post("pdp_ieee1394: set sequence grabber to : play all data");
+ break;
+ }
+
+ anErr = QTNewGWorldFromPtr (&x->x_srcGWorld,
+ k422YpCbCr8CodecType,
+ &x->x_srcRect,
+ NULL,
+ NULL,
+ 0,
+ x->x_sdata,
+ x->x_width*2);
+ if (anErr!= noErr)
+ {
+ post ("pdp_ieee1394: QTNewGWorldFromPtr returned %d", anErr);
+ return -1;
+ }
+
+ if (NULL == x->x_srcGWorld)
+ {
+ post ("pdp_ieee1394: could not allocate off screen");
+ return -1;
+ }
+ SGSetGWorld(x->x_sg,(CGrafPtr)x->x_srcGWorld, NULL);
+ SGStartPreview(x->x_sg);
+
+ return 0;
+}
+
+static void pdp_ieee1394_open(t_pdp_ieee1394 *x)
+{
+
+ x->x_initialized = true;
+ x->x_continue_thread = 1;
+
+ /* create thread */
+ if ( x->x_thread_id == 0 )
+ {
+ if ( pdp_ieee1394_init_grabber( x ) != 0 )
+ {
+ post("pdp_ieee1394: grabber initialization failed");
+ return;
+ }
+ x->x_frame_ready = 0;
+ pthread_create(&x->x_thread_id, 0, pdp_ieee1394_thread, x);
+ }
+}
+
+static void pdp_ieee1394_bang(t_pdp_ieee1394 *x)
+{
+ unsigned char *pQ;
+ short int *pY, *pU, *pV;
+ t_int px, py;
+
+ if (!(x->x_continue_thread))
+ {
+ post("pdp_ieee1394: not initialized.");
+
+ if (x->x_auto_open)
+ {
+ post("pdp_ieee1394: attempting auto open");
+ pdp_ieee1394_open(x);
+ if (!(x->x_initialized))
+ {
+ post("pdp_ieee1394: auto open failed");
+ return;
+ }
+ }
+ else return;
+ }
+
+ /* do nothing if there is no frame ready */
+ if (!x->x_frame_ready) return;
+
+ x->x_packet = pdp_packet_new_image_YCrCb(x->x_width, x->x_height);
+ x->x_header = pdp_packet_header(x->x_packet);
+
+ if (!x->x_header)
+ {
+ post("pdp_ieee1394: FATAL: can't allocate packet");
+ return;
+ }
+
+ x->x_data = (short int *) pdp_packet_data(x->x_packet);
+ memset( x->x_data, 0x0, (x->x_size+(x->x_size>>1))<<1 );
+ pQ = x->x_sdata;
+ pY = x->x_data;
+ pV = x->x_data+x->x_size;
+ pU = x->x_data+x->x_size+(x->x_size>>2);
+ for ( py=0; py<(t_int)x->x_height; py++ )
+ {
+ for ( px=0; px<(t_int)x->x_width; px++ )
+ {
+ *(pY+py*x->x_width+px) = (*(pQ+1+2*(py*x->x_width+px)))<<7;
+ if ( px%2 == 0 )
+ {
+ *(pU+((py>>1)*(x->x_width>>1)+(px>>1))) = (*(pQ+2*(py*x->x_width+px))-128)<<8;
+ }
+ if ( px%2 == 1 )
+ {
+ *(pV+((py>>1)*(x->x_width>>1)+(px>>1))) = (*(pQ+2*(py*x->x_width+px))-128)<<8;
+ }
+ }
+ }
+
+ pdp_packet_pass_if_valid(x->x_outlet0, &x->x_packet);
+
+ x->x_frame_ready = 0;
+}
+
+t_class *pdp_ieee1394_class;
+
+void *pdp_ieee1394_new(t_floatarg fwidth, t_floatarg fheight)
+{
+ t_pdp_ieee1394 *x = (t_pdp_ieee1394 *)pd_new(pdp_ieee1394_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+ x->x_initialized = false;
+
+ x->x_auto_open = true;
+
+ x->x_continue_thread = 0;
+
+ if (fwidth > 0.)
+ {
+ x->x_width = (int)fwidth;
+ }
+ else
+ {
+ x->x_width = DEFAULT_WIDTH;
+ }
+
+ if (fheight > 0.)
+ {
+ x->x_height = (int)fheight;
+ }
+ else
+ {
+ x->x_height = DEFAULT_WIDTH;
+ }
+ x->x_size = x->x_width*x->x_height;
+ x->x_sdata = (unsigned char*) getbytes( (x->x_size+(x->x_size>>1))<<1 );
+ if ( !x->x_sdata )
+ {
+ post ("pdp_ieee1394: FATAL : couldn't allocate static data.");
+ return NULL;
+ }
+
+ x->x_quality = 1;
+ x->x_thread_id = 0;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ieee1394_setup(void)
+{
+ pdp_ieee1394_class = class_new(gensym("pdp_ieee1394"), (t_newmethod)pdp_ieee1394_new,
+ (t_method)pdp_ieee1394_free, sizeof(t_pdp_ieee1394), 0, A_DEFFLOAT, A_DEFFLOAT, A_NULL);
+
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_bang, gensym("bang"), A_NULL);
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_close, gensym("close"), A_NULL);
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_open, gensym("open"), A_NULL);
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_reset, gensym("reset"), A_NULL);
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_quality, gensym("quality"), A_DEFFLOAT, A_NULL);
+}
+
+#ifdef __cplusplus
+}
+#endif