1 /*
2  * Copyright (C) 2004 Nathan Lutchansky <lutchann@litech.org>
3  *
4  * This program is free software; you can redistribute it and/or modify
5  * it under the terms of the GNU General Public License as published by
6  * the Free Software Foundation; either version 2 of the License, or
7  * (at your option) any later version.
8  *
9  * This program is distributed in the hope that it will be useful,
10  * but WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12  * GNU General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software Foundation,
16  * Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
17  */
18 
19 #include <config.h>
20 
21 #include <sys/types.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <unistd.h>
25 #include <string.h>
26 #include <fcntl.h>
27 #include <pthread.h>
28 
29 #include <libraw1394/raw1394.h>
30 #include <libdc1394/dc1394_control.h>
31 
32 #include <event.h>
33 #include <log.h>
34 #include <frame.h>
35 #include <stream.h>
36 #include <inputs.h>
37 #include <conf_parse.h>
38 
39 #define WIDTH	320
40 #define HEIGHT	240
41 
42 struct dc1394_cam {
43 	raw1394handle_t handle;
44 	int running;
45 	struct soft_queue *outq;
46 	struct stream *output;
47 };
48 
49 struct dc1394_input {
50 	struct dc1394_cam cam[16];
51 	dc1394_cameracapture camera[16];
52 	int cam_count;
53 	pthread_t thread;
54 };
55 
capture_loop(void * d)56 static void *capture_loop( void *d )
57 {
58 	struct dc1394_input *conf = (struct dc1394_input *)d;
59 	struct frame *f;
60 	int cam;
61 
62 	for(;;)
63 	{
64 		dc1394_dma_multi_capture( conf->camera, conf->cam_count );
65 		for( cam = 0; cam < conf->cam_count; ++cam )
66 		{
67 			if( conf->cam[cam].running && ( f = new_frame() ) )
68 			{
69 				f->length = HEIGHT * WIDTH * 2;
70 				f->format = FORMAT_RAW_UYVY;
71 				f->width = WIDTH;
72 				f->height = HEIGHT;
73 				f->key = 1;
74 
75 				memcpy( f->d, conf->camera[cam].capture_buffer,
76 						f->length );
77 
78 				if( soft_queue_add( conf->cam[cam].outq, f ) < 0 )
79 					unref_frame( f );
80 			}
81 			dc1394_dma_done_with_buffer( &conf->camera[cam] );
82 		}
83 	}
84 
85 	return NULL;
86 }
87 
get_back_frame(struct event_info * ei,void * d)88 static void get_back_frame( struct event_info *ei, void *d )
89 {
90 	struct dc1394_cam *cam = (struct dc1394_cam *)d;
91 	struct frame *f = (struct frame *)ei->data;
92 
93 	deliver_frame_to_stream( f, cam->output );
94 }
95 
cam_setup(struct dc1394_input * conf,int cam,int port,nodeid_t node,int dma_chan)96 static int cam_setup( struct dc1394_input *conf, int cam, int port,
97 				nodeid_t node, int dma_chan )
98 {
99 	unsigned int channel;
100 	unsigned int speed;
101 
102 	conf->cam[cam].running = 0;
103 	conf->camera[cam].node = node;
104 	conf->cam[cam].handle = dc1394_create_handle( port );
105 	if( ! conf->cam[cam].handle )
106 	{
107 		spook_log( SL_ERR, "dc1394: unable to create a camera handle" );
108 		return -1;
109 	}
110 	if( dc1394_get_iso_channel_and_speed( conf->cam[cam].handle, node,
111 				&channel, &speed ) != DC1394_SUCCESS )
112 	{
113 		spook_log( SL_ERR, "dc1394: unable to create an ISO channel" );
114 		return -1;
115 	}
116 
117 	if( dc1394_dma_setup_capture( conf->cam[cam].handle, node, dma_chan,
118 				FORMAT_VGA_NONCOMPRESSED, MODE_320x240_YUV422,
119 				SPEED_400, FRAMERATE_30, 8 /* num buffers */,
120 #ifdef DC1394_EXTRA_BUFFERING_FLAG
121 				0 /* do_extra_buffering */,
122 #endif
123 				1 /* drop frames */, NULL /* device name */,
124 				&conf->camera[cam] ) != DC1394_SUCCESS )
125 	{
126 		spook_log( SL_ERR, "dc1394: unable to set up DMA for camera" );
127 		return -1;
128 	}
129 	if( dc1394_start_iso_transmission( conf->cam[cam].handle,
130 				conf->camera[cam].node ) != DC1394_SUCCESS )
131 	{
132 		spook_log( SL_ERR,
133 			"dc1394: unable to start ISO transfer from camera" );
134 		return -1;
135 	}
136 	conf->cam[cam].outq = new_soft_queue( 16 );
137 	add_softqueue_event( conf->cam[cam].outq, 0,
138 			get_back_frame, &conf->cam[cam] );
139 	return 0;
140 }
141 
dc1394_setup(struct dc1394_input * conf)142 static int dc1394_setup( struct dc1394_input *conf )
143 {
144 	raw1394handle_t raw_handle;
145 	nodeid_t *camera_nodes = NULL;
146 	int numPorts;
147 	int actual_count = 0, c, i;
148 	struct raw1394_portinfo ports[16];
149 
150 	raw_handle = raw1394_new_handle();
151 	if( ! raw_handle )
152 	{
153 		spook_log( SL_ERR,
154 			"dc1394: unable to acquire a raw1394 handle" );
155 		return -1;
156 	}
157 
158 	numPorts = raw1394_get_port_info( raw_handle, ports, 16 );
159 	raw1394_destroy_handle( raw_handle );
160 	for( i = 0; i < numPorts; ++i )
161 	{
162 		int camCount = 0;
163 
164 		raw_handle = raw1394_new_handle();
165 		raw1394_set_port( raw_handle, i );
166 		camera_nodes = dc1394_get_camera_nodes( raw_handle,
167 							&camCount, 1 );
168 		raw1394_destroy_handle( raw_handle );
169 		spook_log( SL_INFO, "dc1394: found %d cams on port %d",
170 				camCount, i );
171 		for( c = 0; c < camCount; ++c )
172 		{
173 			if( cam_setup( conf, actual_count, i,
174 						camera_nodes[c], c ) < 0 )
175 				return -1;
176 			if( ++actual_count == conf->cam_count ) return 0;
177 		}
178 		// this doesn't work, fix later (just a li'l memory leak...)
179 		//dc1394_free_camera_nodes( camera_nodes );
180 	}
181 
182 	if( actual_count == 0 )
183 	{
184 		spook_log( SL_ERR, "dc1394: did not find any IIDC cameras" );
185 		return -1;
186 	}
187 
188 	if( actual_count < conf->cam_count )
189 		spook_log( SL_WARN,
190 			"dc1394: only found %d cameras, some outputs will be inactive",
191 			actual_count );
192 
193 	return 0;
194 }
195 
get_framerate(struct stream * s,int * fincr,int * fbase)196 static void get_framerate( struct stream *s, int *fincr, int *fbase )
197 {
198 	struct dc1394_cam *cam = (struct dc1394_cam *)s->private;
199 
200 	*fincr = 1;
201 	*fbase = 30;
202 }
203 
set_running(struct stream * s,int running)204 static void set_running( struct stream *s, int running )
205 {
206 	struct dc1394_cam *cam = (struct dc1394_cam *)s->private;
207 
208 	cam->running = running;
209 }
210 
211 #if 0
212 void dc1394_close(void)
213 {
214 	fprintf( stderr, "closing down..." );
215 	dc1394_dma_unlisten( handle, &camera );
216 	dc1394_dma_release_camera( handle, &camera );
217 	dc1394_destroy_handle( handle );
218 	fprintf( stderr, "done!\n" );
219 }
220 #endif
221 
222 /************************ CONFIGURATION DIRECTIVES ************************/
223 
start_block(void)224 static void *start_block(void)
225 {
226 	struct dc1394_input *conf;
227 
228 	conf = (struct dc1394_input *)malloc( sizeof( struct dc1394_input ) );
229 	conf->cam_count = 0;
230 
231 	return conf;
232 }
233 
end_block(void * d)234 static int end_block( void *d )
235 {
236 	struct dc1394_input *conf = (struct dc1394_input *)d;
237 
238 	if( conf->cam_count == 0 )
239 	{
240 		spook_log( SL_ERR, "dc1394: missing output stream name" );
241 		return -1;
242 	}
243 	if( dc1394_setup( conf ) < 0 )
244 	{
245 		spook_log( SL_ERR, "dc1394: unable to initialize video input" );
246 		return -1;
247 	}
248 	pthread_create( &conf->thread, NULL, capture_loop, conf );
249 
250 	return 0;
251 }
252 
set_output(int num_tokens,struct token * tokens,void * d)253 static int set_output( int num_tokens, struct token *tokens, void *d )
254 {
255 	struct dc1394_input *conf = (struct dc1394_input *)d;
256 
257 	conf->cam[conf->cam_count].output = new_stream( tokens[1].v.str,
258 				FORMAT_RAW_UYVY, &conf->cam[conf->cam_count] );
259 	if( ! conf->cam[conf->cam_count].output )
260 	{
261 		spook_log( SL_ERR, "dc1394: unable to create stream \"%s\"",
262 				tokens[1].v.str );
263 		return -1;
264 	}
265 	conf->cam[conf->cam_count].output->get_framerate = get_framerate;
266 	conf->cam[conf->cam_count].output->set_running = set_running;
267 	++conf->cam_count;
268 	return 0;
269 }
270 
271 static struct statement config_statements[] = {
272 	/* directive name, process function, min args, max args, arg types */
273 	{ "output", set_output, 1, 1, { TOKEN_STR } },
274 
275 	/* empty terminator -- do not remove */
276 	{ NULL, NULL, 0, 0, {} }
277 };
278 
dc1394_init(void)279 void dc1394_init(void)
280 {
281 	register_config_context( "input", "dc1394", start_block, end_block,
282 					config_statements );
283 }
284