1 #include "config.h"
2
3 #include <stdio.h>
4 #include <stdlib.h>
5 #include <unistd.h>
6 #include <signal.h>
7 #include <time.h>
8 #include <pthread.h>
9 #include <aalib.h>
10
11 #include "grab-ng.h"
12 #include "capture.h"
13 #include "channel.h"
14 #include "commands.h"
15 #include "frequencies.h"
16 #include "parseconfig.h"
17 #include "sound.h"
18
19 /* ---------------------------------------------------------------------- */
20 /* capture stuff */
21
22 static struct aa_hardware_params params;
23 static aa_renderparams render;
24 static aa_context *context;
25 char *framebuffer;
26 static int signaled;
27
28 static char title[256];
29 static char message[256];
30 static time_t mtime;
31 static struct ng_video_fmt fmt,gfmt;
32 static struct ng_video_conv *conv;
33 static struct ng_convert_handle *ch;
34 static int fast;
35
36 static void
37 grabber_init(void)
38 {
39 drv = ng_vid_open(ng_dev.video,NULL,NULL,0,&h_drv);
40 if (NULL == drv) {
41 fprintf(stderr,"no grabber device available\n");
42 exit(1);
43 }
44 f_drv = drv->capabilities(h_drv);
45 add_attrs(drv->list_attrs(h_drv));
46 }
47
48 static void
49 new_title(char *txt)
50 {
51 strcpy(title,txt);
52 }
53
54 static void
55 new_message(char *txt)
56 {
57 mtime = time(NULL);
58 strcpy(message,txt);
59 }
60
61 static void do_capture(int from, int to, int tmp_switch)
62 {
63 /* off */
64 switch (from) {
65 case CAPTURE_GRABDISPLAY:
66 if (f_drv & CAN_CAPTURE)
67 drv->stopvideo(h_drv);
68 break;
69 }
70
71 /* on */
72 switch (to) {
73 case CAPTURE_GRABDISPLAY:
74 /* try native */
75 fmt.fmtid = VIDEO_GRAY;
76 fmt.width = aa_imgwidth(context);
77 fmt.height = aa_imgheight(context);
78 if (0 != ng_grabber_setformat(&fmt,1)) {
79 gfmt = fmt;
80 if (NULL == (conv = ng_grabber_findconv(&gfmt,0))) {
81 fprintf(stderr,"can't capture gray data\n");
82 exit(1);
83 }
84 ch = ng_convert_alloc(conv,&gfmt,&fmt);
85 ng_convert_init(ch);
86 }
87 if (f_drv & CAN_CAPTURE)
88 drv->startvideo(h_drv,-1,2);
89 break;
90 }
91 }
92
93 static void blitframe(struct ng_video_buf *buf)
94 {
95 int w,h,y;
96 char *s,*d;
97
98 #if 0
99 /* debug */
100 fprintf(stdout,"P5\n%d %d\n255\n",buf->fmt.width,buf->fmt.height);
101 fwrite(buf->data,buf->fmt.width,buf->fmt.height,stdout);
102 exit(1);
103 #endif
104 if (buf->fmt.width == aa_imgwidth(context) &&
105 buf->fmt.height == aa_imgheight(context)) {
106 memcpy(framebuffer,buf->data,buf->fmt.width*buf->fmt.height);
107 } else {
108 s = buf->data;
109 d = framebuffer;
110 if (buf->fmt.height < aa_imgheight(context)) {
111 h = buf->fmt.height;
112 d += (aa_imgheight(context)-buf->fmt.height)/2 *
113 aa_imgwidth(context);
114 } else {
115 h = aa_imgheight(context);
116 s += (buf->fmt.height-aa_imgheight(context))/2 *
117 buf->fmt.width;
118 }
119 if (buf->fmt.width < aa_imgwidth(context)) {
120 w = buf->fmt.width;
121 d += (aa_imgwidth(context)-buf->fmt.width)/2;
122 } else {
123 w = aa_imgwidth(context);
124 s += (buf->fmt.width-aa_imgwidth(context))/2;
125 }
126 for (y = 0; y < h; y++) {
127 memcpy(d,s,w);
128 s += buf->fmt.width;
129 d += aa_imgwidth(context);
130 }
131 }
132 }
133
134 /* ----------------------------------------------------------------------- */
135
136 static void aa_cleanup(void)
137 {
138 aa_uninitkbd(context);
139 aa_close(context);
140 }
141
142 static void
143 ctrlc(int signal)
144 {
145 signaled++;
146 }
147
148 static void
149 usage(void)
150 {
151 printf("ttv -- watch tv on a ascii terminal using aalib\n"
152 "\n"
153 "ttv options:\n"
154 " -h print this text\n"
155 " -f use fast aalib render function\n"
156 " -c <device> video device [%s]\n"
157 "\n"
158 "aalib options:\n"
159 "%s",
160 ng_dev.video,aa_help);
161 exit(1);
162 }
163
164 int
165 main(int argc, char **argv)
166 {
167 struct ng_video_buf *buf;
168 unsigned long freq;
169 int c,i,key,frames,fps;
170 time_t now,last;
171 struct tm *t;
172
173 ng_init();
174 params = aa_defparams;
175 render = aa_defrenderparams;
176 if (!aa_parseoptions (¶ms, &render, &argc, argv))
177 usage();
178 for (;;) {
179 c = getopt(argc, argv, "vfhc:");
180 if (c == -1)
181 break;
182 switch (c) {
183 case 'v':
184 debug++;
185 ng_debug++;
186 break;
187 case 'f':
188 fast++;
189 break;
190 case 'c':
191 ng_dev.video = optarg;
192 break;
193 case 'h':
194 default:
195 usage();
196 break;
197 }
198 }
199
200 /* init aalib */
201 context = aa_autoinit(¶ms);
202 if (context == NULL) {
203 printf("Failed to initialize aalib\n");
204 exit (1);
205 }
206 aa_autoinitkbd(context,0);
207 atexit(aa_cleanup);
208 framebuffer = aa_image(context);
209
210 /* init v4l */
211 grabber_init();
212 freq_init();
213 read_config(NULL,NULL,NULL);
214 ng_ratio_x = 0;
215 ng_ratio_y = 0;
216
217 /* init mixer */
218 if (0 != strlen(mixerdev)) {
219 struct ng_attribute *attr;
220 if (NULL != (attr = ng_mix_init(mixerdev,mixerctl)))
221 add_attrs(attr);
222 }
223
224 /* set hooks (command.c) */
225 update_title = new_title;
226 display_message = new_message;
227 set_capture_hook = do_capture;
228
229 /* init hardware */
230 attr_init();
231 audio_on();
232 audio_init();
233
234 /* build channel list */
235 parse_config();
236 do_va_cmd(2,"setfreqtab",(-1 != chantab)
237 ? chanlist_names[chantab].str : "europe-west");
238 cur_capture = 0;
239 do_va_cmd(2,"capture","grabdisplay");
240 if (optind+1 == argc) {
241 do_va_cmd(2,"setstation",argv[optind]);
242 } else {
243 if ((f_drv & CAN_TUNE) && 0 != (freq = drv->getfreq(h_drv))) {
244 for (i = 0; i < chancount; i++)
245 if (chanlist[i].freq == freq*1000/16) {
246 do_va_cmd(2,"setchannel",chanlist[i].name);
247 break;
248 }
249 }
250 if (-1 == cur_channel) {
251 if (count > 0)
252 do_va_cmd(2,"setstation","");
253 else
254 set_defaults();
255 }
256 }
257
258 /* catch ^C */
259 signal(SIGINT,ctrlc);
260 signal(SIGTERM,ctrlc);
261 signal(SIGQUIT,ctrlc);
262
263 /* main loop */
264 last = now = time(NULL);
265 frames = fps = 0;
266 for (;!signaled;) {
267 /* time + performance */
268 now = time(NULL);
269 t = localtime(&now);
270 frames++;
271 if (now - last >= 5) {
272 fps = frames * 10 / (now-last);
273 last = now;
274 frames = 0;
275 }
276
277 /* grab + convert frame */
278 if (NULL == (buf = ng_grabber_grab_image(0))) {
279 fprintf(stderr,"capturing image failed\n");
280 exit(1);
281 }
282 if (ch)
283 buf = ng_convert_frame(ch,NULL,buf);
284
285 /* blit frame */
286 blitframe(buf);
287 ng_release_video_buf(buf);
288 if (fast)
289 aa_fastrender(context, 0, 0,
290 aa_scrwidth (context), aa_scrheight (context));
291 else
292 aa_render(context, &render, 0, 0,
293 aa_scrwidth (context), aa_scrheight (context));
294 if (now - mtime < 6) {
295 aa_printf(context,0,0,AA_NORMAL,"[ %s ] ",
296 message);
297 } else {
298 aa_printf(context,0,0,AA_NORMAL,"[ %s - %d.%d fps - %02d:%02d ] ",
299 title,fps/10,fps%10,t->tm_hour,t->tm_min);
300 }
301 aa_flush(context);
302
303 /* check for keys */
304 key = aa_getkey(context,0);
305 switch (key) {
306 case 'q':
307 case 'Q':
308 case 'e':
309 case 'E':
310 case 'x':
311 case 'X':
312 audio_off();
313 signaled++;
314 break;
315 case 'd':
316 case 'D':
317 mtime = time(NULL);
318 sprintf(message,"debug: scr=%dx%d / img=%dx%d / cap=%dx%d",
319 aa_scrwidth(context),aa_scrheight(context),
320 aa_imgwidth(context),aa_imgheight(context),
321 fmt.width,fmt.height);
322 break;
323 case '+':
324 do_va_cmd(2,"volume","inc");
325 break;
326 case '-':
327 do_va_cmd(2,"volume","dec");
328 break;
329 case 10:
330 case 13:
331 do_va_cmd(2,"volume","mute");
332 break;
333 case AA_UP:
334 do_va_cmd(2,"setchannel","next");
335 break;
336 case AA_DOWN:
337 do_va_cmd(2,"setchannel","prev");
338 break;
339 case AA_RIGHT:
340 do_va_cmd(2,"setchannel","fine_up");
341 break;
342 case AA_LEFT:
343 do_va_cmd(2,"setchannel","fine_down");
344 break;
345 case ' ':
346 do_va_cmd(2,"setstation","next");
347 break;
348 default:
349 /* nothing */
350 break;
351 }
352 }
353 exit(0);
354 }
355
|
This page was automatically generated by the
LXR engine.
|