All pastes #453085 Raw Edit

Miscellany

public text v1 · immutable
·published 2007-04-22 19:11 UTC
rendered paste body
/* 
 * 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 <stdio.h>
#include <sys/ioctl.h>
#include <sys/mman.h>
#include <sys/time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sched.h>
#include <sys/resource.h>
#include <string.h>
#include <signal.h>
#include <pthread.h>
#include <libdv/dv.h>


#include <stdlib.h>

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;	
}