aboutsummaryrefslogtreecommitdiff
path: root/modules/pdp_ieee1394l.c
diff options
context:
space:
mode:
Diffstat (limited to 'modules/pdp_ieee1394l.c')
-rwxr-xr-xmodules/pdp_ieee1394l.c546
1 files changed, 546 insertions, 0 deletions
diff --git a/modules/pdp_ieee1394l.c b/modules/pdp_ieee1394l.c
new file mode 100755
index 0000000..bab80e6
--- /dev/null
+++ b/modules/pdp_ieee1394l.c
@@ -0,0 +1,546 @@
+/*
+ * Pure Data Packet module.
+ * Copyright (c) by Lluis Gomez i Bigorda <lluisgomez@hangar.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 <assert.h>
+#include <getopt.h> /* getopt_long() */
+#include <ctype.h>
+#include <fcntl.h>
+#include <errno.h>
+#include <malloc.h>
+#include <sys/stat.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/time.h>
+#include <sys/mman.h>
+#include <linux/types.h>
+#include <sched.h>
+#include <pthread.h>
+
+#include "dv1394.h"
+#include <libdv/dv.h>
+
+#define N_BUF 2 /*DV1394_MAX_FRAMES/4*/
+#define PAL 0
+#define NTSC 1
+
+
+typedef struct pdp_ieee1394_struct
+{
+ t_object x_obj;
+
+ t_outlet *x_outlet0;
+
+ int x_width;
+ int x_height;
+
+ int dvfd;
+ unsigned char *videobuf;
+ unsigned char *decodedbuf;
+ bool x_frame_ready;
+ int x_frame, x_lastframe;
+ bool x_continue_thread;
+ pthread_t x_thread_id;
+
+ int x_framesize;
+ unsigned char *x_mmapbuf;
+
+ dv_decoder_t *x_decoder;
+
+ bool x_haveVideo;
+ bool x_capturing;
+ bool x_norm;
+ char* x_devicename;
+ int x_devicenum;
+
+} t_pdp_ieee1394;
+
+
+
+static void
+process_image (t_pdp_ieee1394 *x)
+{
+
+ unsigned int w,h;
+ int object,length,pos,i,encoding;
+ t_pdp* header;
+ t_image* image;
+ short int * data;
+
+ //fputc ('.', stdout);
+ //fflush (stdout);
+
+
+
+ /* create new packet */
+ w = x->x_width;
+ h = x->x_height;
+
+
+ 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);
+
+ /* convert data to pdp packet */
+ //pdp_llconv(x->decodedbuf, RIF_YVYU_P____U8, data, RIF_YVU__P411_S16, w, h);
+ pdp_llconv(x->decodedbuf, RIF_RGB__P____U8, data, RIF_YVU__P411_S16, w, h); //
+
+
+ pdp_packet_pass_if_valid(x->x_outlet0, &object);
+}
+
+static int pdp_ieee1394_read_frame(t_pdp_ieee1394 *x)
+{
+
+ if (!x->x_decoder)return 0;
+ if (!x->x_frame_ready) {
+ //x->x_image.newimage = 0;
+ }
+ else {
+ dv_parse_header(x->x_decoder, x->videobuf);
+ dv_parse_packs (x->x_decoder, x->videobuf);
+ if(dv_frame_changed(x->x_decoder)) {
+ int pitches[3] = {0,0,0};
+ // pitches[0]=x_decoder->width*3; // rgb
+ // pitches[0]=x_decoder->width*((x_reqFormat==GL_RGBA)?3:2);
+ pitches[0]=x->x_decoder->width*3;
+ x->x_height=x->x_decoder->height;
+ x->x_width=x->x_decoder->width;
+
+ /* decode the DV-data to something we can handle and that is similar to the wanted format */
+ // dv_report_video_error(x_decoder, videobuf); // do we need this ?
+ // gosh, this(e_dv_color_rgb) is expansive:: the decoding is done in software only...
+ // dv_decode_full_frame(x_decoder, videobuf, ((x_reqFormat==GL_RGBA)?e_dv_color_rgb:e_dv_color_yuv), &decodedbuf, pitches);
+ dv_decode_full_frame(x->x_decoder, x->videobuf, e_dv_color_rgb, &x->decodedbuf, pitches);
+
+ // post("sampling %d", x_decoder->sampling);
+
+ /* convert the colour-space to the one we want */
+ /*
+ * btw. shouldn't this be done in [pix_video] rather than here ?
+ * no because [pix_video] knows nothing about the possible colourspaces in here
+ */
+
+ // letting the library do the conversion to RGB and then doing the conversion to RGBA
+ // is really stupid.
+ // let's do it all ourselfes:
+ // if (x_reqFormat==GL_RGBA)x_image.image.fromRGB(decodedbuf); else
+ //x_image.image.fromYVYU(decodedbuf);
+ process_image (x);
+
+ }
+
+ x->x_frame_ready = false;
+ }
+
+ return 1;
+}
+
+
+static void *pdp_ieee1394_thread(void *voidx)
+{
+ t_pdp_ieee1394 *x = ((t_pdp_ieee1394 *)voidx);
+
+ int fd=x->dvfd;
+ int framesize = x->x_framesize;
+ struct dv1394_status dvst;
+ int n_frames = N_BUF;
+ unsigned char* mmapbuf = x->x_mmapbuf;
+
+ /* this will hang if no ieee1394-device is present, what to do about it ??? */
+ x->x_haveVideo=false;
+ if(ioctl(fd, DV1394_WAIT_FRAMES, 1)) {
+ perror("error: ioctl WAIT_FRAMES");
+ x->x_capturing=false; return NULL;
+ }
+ if (ioctl(fd, DV1394_GET_STATUS, &dvst)) {
+ perror("ioctl GET_STATUS");
+ x->x_capturing=false; return NULL;
+ }
+ x->x_haveVideo=true;
+ x->x_capturing=true;
+
+ //fprintf(stderr,"aqui1");
+ while(x->x_continue_thread){
+ //fprintf(stderr,"aqui2");
+ if(ioctl(fd, DV1394_WAIT_FRAMES, n_frames - 1)) {
+ perror("error: ioctl WAIT_FRAMES");
+ x->x_capturing=false; return NULL;
+ }
+ if (ioctl(fd, DV1394_GET_STATUS, &dvst)) {
+ perror("ioctl GET_STATUS");
+ x->x_capturing=false; return NULL;
+ }
+ //fprintf(stderr,"aqui3");
+ /*
+ dvst.init
+ dvst.active_frame
+ dvst.first_clear_frame
+ dvst.n_clear_frames
+ dvst.dropped_frames
+ */
+ if (dvst.dropped_frames > 0) {
+ verbose(1,"dv1394: dropped at least %d frames", dvst.dropped_frames);
+ }
+ /*
+ memcpy( g_current_frame->data,
+ (g_dv1394_map + (dvst.first_clear_frame * DV1394_PAL_FRAME_SIZE)),
+ DV1394_PAL_FRAME_SIZE );
+ */
+ x->videobuf = mmapbuf + (dvst.first_clear_frame * framesize);
+
+ //post("thread %d\t%x %x", me->frame, me->tvfd, me->vmmap);
+ if (ioctl(fd, DV1394_RECEIVE_FRAMES, 1) < 0) {
+ perror("receiving...");
+ }
+ x->x_lastframe=x->x_frame;
+ x->x_frame++;
+ x->x_frame%=N_BUF;
+ x->x_frame_ready = true;
+ }
+ x->x_capturing=false;
+
+ //process_image (x, x->videobuf);
+
+ return 0;
+}
+
+static void
+close_device (t_pdp_ieee1394 *x)
+{
+ if(x->x_mmapbuf!=NULL)munmap(x->x_mmapbuf, N_BUF*x->x_framesize);
+ if(x->dvfd>=0)close(x->dvfd);
+ x->x_haveVideo=false;
+
+}
+
+
+static int
+startTransfer (t_pdp_ieee1394 *x)
+{
+ //if ((x->dvfd=openDevice(format))<0){
+ // verbose(1, "DV4L: closed");
+ // return(0);
+ //}
+ //x->x_image.newimage=0;
+ //x->x_image.image.data=0;
+ //x->x_image.image.xsize=720;
+ //x->x_image.image.ysize=576;
+ //x->x_image.image.setCsizeByFormat(x->x_reqFormat);
+ //x->x_image.image.reallocate();
+ x->videobuf=NULL;
+
+ x->x_frame_ready = false;
+
+ if(x->x_decoder!=NULL)dv_decoder_free(x->x_decoder);
+ if (!(x->x_decoder=dv_decoder_new(1, 1, 1))){
+ //error("DV4L: unable to create DV-decoder...closing");
+ close_device(x);
+ return(0);
+ }
+ //x->x_decoder->quality=x->x_quality;
+ x->x_decoder->quality = DV_QUALITY_BEST;
+ verbose(1, "DV4L: DV decoding quality %d ", x->x_decoder->quality);
+ //fprintf(stderr,"before");
+ x->x_continue_thread = true;
+ pthread_create(&x->x_thread_id, 0, pdp_ieee1394_thread, x);
+ return 1;
+}
+
+static int
+stopTransfer (t_pdp_ieee1394 *x)
+{
+ /* close the dv4l device and dealloc buffer */
+ /* terminate thread if there is one */
+ x->x_continue_thread=false;
+ int i=0;
+ if(x->x_haveVideo){
+ while(x->x_capturing){
+ struct timeval sleep;
+ sleep.tv_sec=0; sleep.tv_usec=10; /* 10us */
+ select(0,0,0,0,&sleep);
+ i++;
+ }
+ verbose(1, "DV4L: shutting down dv1394 after %d usec", i*10);
+ ioctl(x->dvfd, DV1394_SHUTDOWN);
+ }
+ close_device(x);
+ return(1);
+}
+
+
+static void pdp_ieee1394_close(t_pdp_ieee1394 *x)
+{
+ /* close the v4l device and dealloc buffer */
+
+ void *dummy;
+ //x->x_initialized = false;
+ /* terminate thread if there is one */
+ if(x->x_continue_thread){
+ x->x_continue_thread = 0;
+ pthread_join (x->x_thread_id, &dummy);
+ }
+
+
+ //stop_capturing (x);
+
+ //uninit_device (x);
+
+ close_device (x);
+
+ if (-1 == close (x->dvfd))
+ post ("close");
+
+ x->dvfd = -1;
+}
+
+
+static int pdp_ieee1394_open(t_pdp_ieee1394 *x, t_symbol *name)
+{
+ x->x_devicename = name->s_name;
+
+ if(x->x_haveVideo){
+ verbose(1, "Stream already going on. Doing some clean-up...");
+ stopTransfer(x);
+ }
+
+ /*
+ All of the errors in this method return -1 anyhow, so fd should be 0 to allow
+ successful open if everything goes ok.
+
+ Ico Bukvic ico@vt.edu 2-18-07
+ */
+ int fd = 0;
+ struct dv1394_init init = {
+ DV1394_API_VERSION, // api version
+ 0x63, // isochronous transmission channel
+ N_BUF, // number of frames in ringbuffer
+ (x->x_norm==NTSC)?DV1394_NTSC:DV1394_PAL, // PAL or NTSC
+ //DV1394_PAL, // PAL or NTSC
+ 0, 0 , 0 // default packet rate
+ };
+
+ x->x_framesize=(x->x_norm==NTSC)?DV1394_NTSC_FRAME_SIZE:DV1394_PAL_FRAME_SIZE;
+ //x->x_framesize=DV1394_PAL_FRAME_SIZE;
+
+ if(x->x_devicename){
+ if ((fd = open(x->x_devicename, O_RDWR)) < 0) {
+ perror(x->x_devicename);
+ return -1;
+ }
+ } else {
+ signed char devnum=(x->x_devicenum<0)?0:(signed char)x->x_devicenum;
+ char buf[256];
+ buf[255]=0;buf[32]=0;buf[33]=0;
+ if (devnum<0)devnum=0;
+ snprintf(buf, 32, "/dev/ieee1394/dv/host%d/%s/in", devnum, (x->x_norm==NTSC)?"NTSC":"PAL");
+ //snprintf(buf, 32, "/dev/ieee1394/dv/host%d/%s/in", devnum, "PAL");
+ if ((fd = open(buf, O_RDWR)) < 0) {
+ snprintf(buf, 32, "/dev/dv1394/%d", devnum);
+ if ((fd = open(buf, O_RDWR)) < 0) {
+ if ((fd=open("/dev/dv1394", O_RDWR)) < 0) {
+ perror(buf);
+ return -1;
+ }
+ }
+ }
+ }
+ if (ioctl(fd, DV1394_INIT, &init) < 0) {
+ perror("initializing");
+ close(fd);
+ return -1;
+ }
+
+ x->x_mmapbuf = (unsigned char *) mmap( NULL, N_BUF*x->x_framesize,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fd, 0);
+ if(x->x_mmapbuf == MAP_FAILED) {
+ perror("mmap frame buffers");
+ close(fd);
+ return -1;
+ }
+
+ if(ioctl(fd, DV1394_START_RECEIVE, NULL)) {
+ perror("dv1394 START_RECEIVE ioctl");
+ close(fd);
+ return -1;
+ }
+ /*Extra verbosity never hurt anyone...
+
+ Ico Bukvic ico@vt.edu 2-18-07
+ */
+ post("DV4L: Successfully opened...");
+ startTransfer(x);
+ x->dvfd=fd;
+
+ return 1;
+
+}
+
+
+static int pdp_ieee1394_norm(t_pdp_ieee1394 *x, t_symbol *s)
+{
+ int inorm = x->x_norm;
+ char* norm=s->s_name;
+ switch(norm[0]){
+ case 'N': case 'n':
+ inorm=NTSC;
+ break;
+ case 'P': case 'p':
+ inorm=PAL;
+ break;
+ }
+ if (inorm==x->x_norm)return 0;
+ x->x_norm=inorm;
+ return 0;
+}
+
+
+static void pdp_ieee1394_bang(t_pdp_ieee1394 *x)
+{
+
+ /* if initialized, grab a frame and output it */
+
+
+
+ /* 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_ieee1394: 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_ieee1394: mark unused %d", object);
+
+ /*pdp_packet_pass_if_valid(x->x_outlet0, &object);*/
+
+}
+
+
+
+static void pdp_ieee1394_free(t_pdp_ieee1394 *x)
+{
+ //pdp_ieee1394_close(x);
+ if(x->x_haveVideo)stopTransfer(x);
+ //if(x->decodedbuf)delete[]decodedbuf;
+ if(x->x_decoder!=NULL)dv_decoder_free(x->x_decoder);
+}
+
+t_class *pdp_ieee1394_class;
+
+
+
+void *pdp_ieee1394_new(t_symbol *vdef, t_symbol *format)
+{
+ t_pdp_ieee1394 *x = (t_pdp_ieee1394 *)pd_new(pdp_ieee1394_class);
+
+ x->x_outlet0 = outlet_new(&x->x_obj, &s_anything);
+
+ //x->x_channel = 0;//0x63;
+ x->x_devicenum = 0;
+ x->x_norm = PAL;
+ x->x_decoder=NULL;
+ x->x_frame_ready=false;
+ x->x_width=720;
+ x->x_height=576;
+ x->x_framesize=DV1394_PAL_FRAME_SIZE;
+ //x->x_quality = DV_QUALITY_BEST;
+ //x->decodedbuf = new unsigned char[720*576*3];
+ x->decodedbuf = malloc (720*576*3*sizeof(unsigned char));
+ x->x_haveVideo=false;
+
+ return (void *)x;
+}
+
+
+#ifdef __cplusplus
+extern "C"
+{
+#endif
+
+
+void pdp_ieee1394_setup(void)
+{
+ post( " pdp_ieee1394 : linux dv interface by Lluis Gomez i Bigorda (lluisgomez@hangar.org)" );
+
+ pdp_ieee1394_class = class_new(gensym("pdp_ieee1394"), (t_newmethod)pdp_ieee1394_new,
+ (t_method)pdp_ieee1394_free, sizeof(t_pdp_ieee1394), 0, A_DEFSYMBOL, A_DEFSYMBOL, A_NULL);
+
+
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_read_frame, 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_SYMBOL, A_NULL);
+ class_addmethod(pdp_ieee1394_class, (t_method)pdp_ieee1394_norm, gensym("norm"), A_SYMBOL, A_NULL);
+
+}
+
+#ifdef __cplusplus
+}
+#endif