/* * This file is heavly based on libdv code: * - dvconnect.c * - playdv * Copyright (C) Peter Schlaile * libdv is free software; you can redistribute it and/or modify it * under the terms of the GNU Lesser Public License as published by * the Free Software Foundation; either version 2.1, or (at your * option) any later version. * * libdv 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 * Lesser Public License for more details. * * You should have received a copy of the GNU Lesser Public License * along with libdv; see the file COPYING. If not, write to * the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA. * * The libdv homepage is http://libdv.sourceforge.net/. */ #define _FILE_OFFSET_BITS 64 #include #include #include #include #include #include #include #include #include #include #include #include #include static dv_decoder_t * dvd; static long syt_offset = 11000; #define TARGETBUFSIZE 320 #define MAX_PACKET_SIZE 512 #define VBUF_SIZE (4096) #define VIDEO1394_MAX_SIZE 0x4000000 enum { VIDEO1394_BUFFER_FREE = 0, VIDEO1394_BUFFER_QUEUED, VIDEO1394_BUFFER_READY }; #define VIDEO1394_SYNC_FRAMES 0x00000001 #define VIDEO1394_INCLUDE_ISO_HEADERS 0x00000002 #define VIDEO1394_VARIABLE_PACKET_SIZE 0x00000004 struct video1394_mmap { int channel; unsigned int sync_tag; unsigned int nb_buffers; unsigned int buf_size; /* For VARIABLE_PACKET_SIZE: Maximum packet size */ unsigned int packet_size; unsigned int fps; unsigned int syt_offset; unsigned int flags; }; struct video1394_wait { unsigned int channel; unsigned int buffer; struct timeval filltime; /* time of buffer full */ }; #define VIDEO1394_LISTEN_CHANNEL \ _IOWR('#', 0x10, struct video1394_mmap) #define VIDEO1394_UNLISTEN_CHANNEL \ _IOW ('#', 0x11, int) #define VIDEO1394_LISTEN_QUEUE_BUFFER \ _IOW ('#', 0x12, struct video1394_wait) #define VIDEO1394_LISTEN_WAIT_BUFFER \ _IOWR('#', 0x13, struct video1394_wait) #define VIDEO1394_TALK_CHANNEL \ _IOWR('#', 0x14, struct video1394_mmap) #define VIDEO1394_UNTALK_CHANNEL \ _IOW ('#', 0x15, int) #define VIDEO1394_TALK_QUEUE_BUFFER \ _IOW ('#', 0x16, size_t) #define VIDEO1394_TALK_WAIT_BUFFER \ _IOW ('#', 0x17, struct video1394_wait) #define VIDEO1394_LISTEN_POLL_BUFFER \ _IOWR('#', 0x18, struct video1394_wait) static int cap_verbose_mode; static int frames_captured = 0; static int broken_frames = 0; /* ------------------------------------------------------------------------ - buffer management ------------------------------------------------------------------------ */ static unsigned char frame[144000]; /* NON-decoded frame */ static unsigned char rgb[3 * 720 * 576]; /* decoded frame */ static unsigned int width, height; /* decoded frame size */ static pthread_mutex_t cond_mutex = PTHREAD_MUTEX_INITIALIZER; static pthread_cond_t start_cond = PTHREAD_COND_INITIALIZER; /* 0 == working thread has done the processing, you can modify the buffer */ /* 1 == working thread is processing the data, do NOT modify the buffer */ /* 2 == buffer reasy to be processed */ #define STATE_FREE 0 #define STATE_BUSY 1 #define STATE_READY 2 static int thread_status = STATE_FREE; /* protected by cond_mutex (and start_cond) */ /* ------------------------------------------------------------------------ - Working thread ------------------------------------------------------------------------*/ void saveimage(void) { char foo[255]; static int i = 0; int imagefile; sprintf(foo,"test%d.ppm",i++); printf("%s\n",foo); imagefile = open(foo, O_WRONLY | O_CREAT | O_TRUNC, 00644); sprintf(foo,"P6\n%d %d\n255\n",width,height); write(imagefile, foo, strlen(foo)); write(imagefile, rgb, width * height * 3); close(imagefile); } void * w_thread(void * unused) { pthread_mutex_lock(&cond_mutex); while(1) { while(thread_status != STATE_READY) pthread_cond_wait(&start_cond, &cond_mutex); thread_status = STATE_BUSY; pthread_mutex_unlock(&cond_mutex); /* HERE DO THE IMAGE PROCESSING */ /* rgb[] is the RGB data * width & height is the image size */ saveimage(); /* END OF DATA PROCESSING SECTION */ pthread_mutex_lock(&cond_mutex); thread_status = STATE_FREE; } return NULL; } /* ------------------------------------------------------------------------ - Decoder ------------------------------------------------------------------------- */ void decode_frame(unsigned char * frame) { unsigned char * pixels[3] = {rgb, NULL,NULL}; int pitches[3] = {720 * 3,0,0}; int ret; pthread_mutex_lock(&cond_mutex); if(thread_status != STATE_FREE) { pthread_mutex_unlock(&cond_mutex); printf("Dropping one frame, working thread not ready\n"); return; } if((ret = dv_parse_header(dvd, frame)) < 0) { printf("dv_parse_header returned %d\n",ret); pthread_mutex_unlock(&cond_mutex); return; } dv_parse_packs(dvd,frame); if(!dv_frame_changed(dvd) && dvd->prev_frame_decoded ) { pthread_mutex_unlock(&cond_mutex); printf("Same Frame\n"); return; } dv_decode_full_frame(dvd, frame,e_dv_color_rgb,pixels,pitches); width = dvd->width; height = dvd->height; dvd->prev_frame_decoded = 1; thread_status = STATE_READY; pthread_cond_signal(&start_cond); pthread_mutex_unlock(&cond_mutex); } /* ------------------------------------------------------------------------ - receiver ------------------------------------------------------------------------ */ void handle_packet(unsigned char* data, int len) { int start_of_frame = 0; static int frame_size = 0; static int isPAL = 0; static unsigned char* p_out = NULL; switch (len) { case 488: if (data[12] == 0x1f && data[13] == 0x07) { start_of_frame = 1; } if (start_of_frame) { int frame_broken = 0; if (frame_size) { if ((isPAL && frame_size != 144000) || (!isPAL && frame_size != 120000)) { fprintf(stderr, "Broken frame %8d " "(size = %d)!\n", frames_captured, frame_size); broken_frames++; frame_broken = 1; } if (cap_verbose_mode) { fprintf(stderr, "Captured frame %8d\r", frames_captured); } frames_captured++; } isPAL = (data[15] & 0x80); if (!frame_broken && frame_size) { decode_frame(frame); p_out = NULL; } if(!p_out) { p_out = frame; } frame_size = 0; } if (frame_size < 144000 && p_out) { memcpy(p_out, data + 12, 480); p_out += 480; frame_size += 480; } else { fprintf(stderr, "Frame buffer overrun: " "Frame discarded!\n"); broken_frames++; p_out = frame; frame_size = 0; } break; case 8: break; default: fprintf(stderr, "Penguin on the bus? (packet size = %d!)\n", len); break; } } int capture_raw(int channel, int nbuffers, int verbose_mode, char *device) { int viddev; unsigned char *recv_buf; struct video1394_mmap v; struct video1394_wait w; int unused_buffers; unsigned char outbuf[2*65536]; int outbuf_used = 0; cap_verbose_mode = verbose_mode; if ((viddev = open(device, O_RDWR)) < 0) { perror("open video1394 device"); return -1; } v.channel = channel; v.sync_tag = 0; v.nb_buffers = nbuffers; v.buf_size = VBUF_SIZE; v.packet_size = MAX_PACKET_SIZE; v.syt_offset = syt_offset; v.flags = VIDEO1394_INCLUDE_ISO_HEADERS; w.channel = v.channel; if (ioctl(viddev, VIDEO1394_LISTEN_CHANNEL, &v) < 0) { perror("VIDEO1394_LISTEN_CHANNEL"); return -1; } if ((recv_buf = (unsigned char *) mmap( 0, v.nb_buffers*v.buf_size, PROT_READ|PROT_WRITE, MAP_SHARED, viddev, 0)) == (unsigned char *)-1) { perror("mmap videobuffer"); return -1; } /* signal(SIGTERM, sig_int_recv_handler); signal(SIGINT, sig_int_recv_handler); */ unused_buffers = v.nb_buffers; w.buffer = 0; while (1) { struct video1394_wait wcopy; unsigned char * curr; int ofs; while (unused_buffers--) { unsigned char * curr = recv_buf+ v.buf_size * w.buffer; memset(curr, 0, v.buf_size); wcopy = w; if (ioctl(viddev,VIDEO1394_LISTEN_QUEUE_BUFFER, &wcopy) < 0) { perror("VIDEO1394_LISTEN_QUEUE_BUFFER"); } w.buffer++; w.buffer %= v.nb_buffers; } wcopy = w; if (ioctl(viddev, VIDEO1394_LISTEN_WAIT_BUFFER, &wcopy) < 0) { perror("VIDEO1394_LISTEN_WAIT_BUFFER"); } curr = recv_buf + v.buf_size * w.buffer; ofs = 0; while (ofs < VBUF_SIZE) { while (outbuf_used < 4 && ofs < VBUF_SIZE) { outbuf[outbuf_used++] = curr[ofs++]; } if (ofs != VBUF_SIZE) { int len = outbuf[2] + (outbuf[3] << 8) + 8; if (ofs + len - outbuf_used > VBUF_SIZE) { memcpy(outbuf + outbuf_used, curr+ofs, VBUF_SIZE - ofs); outbuf_used += VBUF_SIZE - ofs; ofs = VBUF_SIZE; } else { memcpy(outbuf + outbuf_used, curr + ofs, len - outbuf_used); ofs += len - outbuf_used; outbuf_used = 0; handle_packet(outbuf, len - 8); } } } unused_buffers = 1; } if (broken_frames) { fprintf(stderr, "\nCaptured %d broken frames!\n", broken_frames); } munmap(recv_buf, v.nb_buffers * v.buf_size); if (ioctl(viddev, VIDEO1394_UNLISTEN_CHANNEL, &v.channel)<0) { perror("VIDEO1394_UNLISTEN_CHANNEL"); } close(viddev); return 0; } /* ------------------------------------------------------------------------ - sender ------------------------------------------------------------------------ */ int rt_raisepri (int pri) { #ifdef _SC_PRIORITY_SCHEDULING struct sched_param scp; /* * Verify that scheduling is available */ if (sysconf (_SC_PRIORITY_SCHEDULING) == -1) { fprintf (stderr, "WARNING: RR-scheduler not available, " "disabling.\n"); return (-1); } else { memset (&scp, '\0', sizeof (scp)); scp.sched_priority = sched_get_priority_max (SCHED_RR) - pri; if (sched_setscheduler (0, SCHED_RR, &scp) < 0) { fprintf (stderr, "WARNING: Cannot set RR-scheduler\n"); return (-1); } } #endif return (0); } /* ------------------------------------------------------------------------ - main() ------------------------------------------------------------------------ */ int main(int argc, char** argv) { int verbose_mode = 0; int channel = 63; char * device; pthread_t wth; #if 0 setpriority (PRIO_PROCESS, 0, -20); if (rt_raisepri (1) != 0) { setpriority (PRIO_PROCESS, 0, -20); } #if _POSIX_MEMLOCK > 0 if (mlockall(MCL_CURRENT | MCL_FUTURE) == -1) { if (verbose_mode) fprintf(stderr, "Cannot disable swapping\n"); } else #endif { /* Prevent excessive underruns from locking down all mem. */ ceil_buffer_blocks = 10*max_buffer_blocks; } #endif dvd = dv_decoder_new(FALSE, FALSE, FALSE); if(!dvd) { fprintf(stderr,"Could not create decoder ! \n"); exit(-1); } dvd->prev_frame_decoded = 0; dvd->quality = DV_QUALITY_BEST; if ( argc == 1 ) device = "/dev/video1394/0"; else device = argv[1]; if(pthread_create(&wth,NULL,w_thread,NULL)) { printf("Could not create thread !\n"); } capture_raw(channel, 100, verbose_mode, device); return 0; }