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