1 // yuv4mpeg.c
2 // LiVES
3 // (c) G. Finch 2004 - 2019 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING or www.gnu.org for licensing details
6
7 #include "main.h"
8 #include "interface.h"
9 #include "lives-yuv4mpeg.h"
10 #include "effects-weed.h"
11
12 static boolean gotbroken;
13
14 typedef struct y4data {
15 const char *filename;
16 lives_yuv4m_t *yuv4mpeg;
17
18 int fd;
19 int i;
20 } y4data;
21
22 static int yuvout, hsize_out, vsize_out;
23
24 // lists of cards in use
25 static LiVESList *fw_cards = NULL;
26
27
lives_yuv4mpeg_alloc(void)28 static lives_yuv4m_t *lives_yuv4mpeg_alloc(void) {
29 lives_yuv4m_t *yuv4mpeg = (lives_yuv4m_t *) malloc(sizeof(lives_yuv4m_t));
30 if (!yuv4mpeg) return NULL;
31 yuv4mpeg->sar = y4m_sar_UNKNOWN;
32 yuv4mpeg->dar = y4m_dar_4_3;
33 y4m_init_stream_info(&(yuv4mpeg->streaminfo));
34 y4m_init_frame_info(&(yuv4mpeg->frameinfo));
35 yuv4mpeg->filename = NULL;
36 yuv4mpeg->name = NULL;
37 yuv4mpeg->fd = -1;
38 yuv4mpeg->ready = FALSE;
39 return yuv4mpeg;
40 }
41
42
y4open_thread(void * arg)43 static void *y4open_thread(void *arg) {
44 y4data *thread_data = (y4data *)arg;
45 int fd = lives_open2(thread_data->filename, O_RDONLY);
46 thread_data->fd = fd;
47 pthread_exit(NULL);
48 }
49
50
y4header_thread(void * arg)51 static void *y4header_thread(void *arg) {
52 y4data *thread_data = (y4data *)arg;
53 lives_yuv4m_t *yuv4mpeg = thread_data->yuv4mpeg;
54 thread_data->i = y4m_read_stream_header(yuv4mpeg->fd, &(yuv4mpeg->streaminfo));
55 pthread_exit(NULL);
56 }
57
58
fill_read(int fd,char * buf,size_t count)59 static void fill_read(int fd, char *buf, size_t count) {
60 size_t bytes = 0;
61 ssize_t got;
62
63 do {
64 got = read(fd, buf + bytes, count - bytes);
65 if (got < 0) return;
66 bytes += got;
67 } while (bytes < count);
68 }
69
70
y4frame_thread(void * arg)71 static void *y4frame_thread(void *arg) {
72 y4data *thread_data = (y4data *)arg;
73 lives_yuv4m_t *yuv4mpeg = thread_data->yuv4mpeg;
74 char buff[5], bchar;
75
76 thread_data->i = Y4M_OK;
77
78 // read 5 bytes FRAME
79 fill_read(yuv4mpeg->fd, buff, 5);
80
81 if (strncmp(buff, "FRAME", 5)) {
82 if (!gotbroken) {
83 thread_data->i = Y4M_ERR_MAGIC;
84 pthread_exit(NULL);
85 }
86
87 do {
88 lives_memmove(buff, buff + 1, 4);
89 fill_read(yuv4mpeg->fd, buff + 4, 1);
90 } while (strncmp(buff, "FRAME", 5));
91 }
92
93 do {
94 fill_read(yuv4mpeg->fd, &bchar, 1);
95 } while (strncmp(&bchar, "\n", 1));
96
97 // read YUV420
98 fill_read(yuv4mpeg->fd, (char *)yuv4mpeg->pixel_data[0], yuv4mpeg->hsize * yuv4mpeg->vsize);
99 fill_read(yuv4mpeg->fd, (char *)yuv4mpeg->pixel_data[1], yuv4mpeg->hsize * yuv4mpeg->vsize / 4);
100 fill_read(yuv4mpeg->fd, (char *)yuv4mpeg->pixel_data[2], yuv4mpeg->hsize * yuv4mpeg->vsize / 4);
101
102 pthread_exit(NULL);
103 }
104
105
lives_yuv_stream_start_read(lives_clip_t * sfile)106 static boolean lives_yuv_stream_start_read(lives_clip_t *sfile) {
107 double ofps = sfile->fps;
108
109 lives_yuv4m_t *yuv4mpeg = (lives_yuv4m_t *)sfile->ext_src;
110
111 pthread_t y4thread;
112
113 char *filename = yuv4mpeg->filename, *tmp;
114
115 ticks_t timeout;
116 lives_alarm_t alarm_handle = 0;
117
118 int ohsize = sfile->hsize;
119 int ovsize = sfile->vsize;
120
121 y4data thread_data;
122
123 int i;
124
125 if (!filename) return FALSE;
126
127 if (yuv4mpeg->fd == -1) {
128 // create a thread to open the fifo
129
130 thread_data.filename = filename;
131
132 pthread_create(&y4thread, NULL, y4open_thread, (void *)&thread_data);
133
134 alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
135
136 d_print("");
137 d_print(_("Waiting for yuv4mpeg frames..."));
138
139 gotbroken = FALSE;
140
141 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && !pthread_kill(y4thread, 0)) {
142 // wait for thread to complete or timeout
143 lives_usleep(prefs->sleep_time);
144 lives_widget_context_update();
145 }
146 lives_alarm_clear(alarm_handle);
147
148 if (timeout == 0) {
149 // timeout - kill thread and wait for it to terminateo
150 pthread_cancel(y4thread);
151 pthread_join(y4thread, NULL);
152
153 d_print_failed();
154 d_print(_("Unable to open the incoming video stream\n"));
155
156 yuv4mpeg->fd = thread_data.fd;
157
158 if (yuv4mpeg->fd >= 0) {
159 close(yuv4mpeg->fd);
160 yuv4mpeg->fd = -1;
161 }
162 return FALSE;
163 }
164
165 pthread_join(y4thread, NULL);
166
167 yuv4mpeg->fd = thread_data.fd;
168
169 if (yuv4mpeg->fd < 0) {
170 return FALSE;
171 }
172 }
173
174 // create a thread to open the stream header
175 thread_data.yuv4mpeg = yuv4mpeg;
176 pthread_create(&y4thread, NULL, y4header_thread, &thread_data);
177 alarm_handle = lives_alarm_set(LIVES_SHORT_TIMEOUT);
178
179 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && !pthread_kill(y4thread, 0)) {
180 // wait for thread to complete or timeout
181 lives_usleep(prefs->sleep_time);
182 lives_widget_context_update();
183 }
184 lives_alarm_clear(alarm_handle);
185
186 if (timeout == 0) {
187 // timeout - kill thread and wait for it to terminate
188 pthread_cancel(y4thread);
189 pthread_join(y4thread, NULL);
190 d_print(_("Unable to read the stream header\n"));
191 return FALSE;
192 }
193
194 pthread_join(y4thread, NULL);
195
196 i = thread_data.i;
197
198 if (i != Y4M_OK) {
199 char *tmp;
200 d_print((tmp = lives_strdup_printf("yuv4mpeg: %s\n", y4m_strerr(i))));
201 lives_free(tmp);
202 return FALSE;
203 }
204
205 d_print(_("got header\n"));
206
207 sfile->hsize = yuv4mpeg->hsize = y4m_si_get_width(&(yuv4mpeg->streaminfo));
208 sfile->vsize = yuv4mpeg->vsize = y4m_si_get_height(&(yuv4mpeg->streaminfo));
209
210 sfile->fps = cfile->pb_fps = lives_strtod(lives_strdup_printf("%.8f", Y4M_RATIO_DBL
211 (y4m_si_get_framerate(&(yuv4mpeg->streaminfo)))), NULL);
212
213 if (sfile->hsize * sfile->vsize == 0) {
214 do_error_dialog(lives_strdup_printf(_("Video dimensions: %d x %d are invalid. Stream cannot be opened"),
215 sfile->hsize, sfile->vsize));
216 return FALSE;
217 }
218
219 if (sfile->hsize != ohsize || sfile->vsize != ovsize || sfile->fps != ofps) {
220 set_main_title(sfile->file_name, 0);
221 }
222
223 d_print((tmp = lives_strdup_printf(_("Reset clip values for %s: size=%dx%d fps=%.3f\n"), yuv4mpeg->name,
224 cfile->hsize, yuv4mpeg->vsize, cfile->bpp, cfile->fps)));
225 lives_free(tmp);
226
227 yuv4mpeg->ready = TRUE;
228
229 return TRUE;
230 }
231
232
lives_yuv_stream_stop_read(lives_yuv4m_t * yuv4mpeg)233 void lives_yuv_stream_stop_read(lives_yuv4m_t *yuv4mpeg) {
234 y4m_fini_stream_info(&(yuv4mpeg->streaminfo));
235 y4m_fini_frame_info(&(yuv4mpeg->frameinfo));
236 yuv4mpeg->sar = y4m_sar_UNKNOWN;
237 yuv4mpeg->dar = y4m_dar_4_3;
238 if (yuv4mpeg->fd != -1) close(yuv4mpeg->fd);
239
240 if (yuv4mpeg->filename) {
241 lives_rm(yuv4mpeg->filename);
242 lives_free(yuv4mpeg->filename);
243 }
244
245 if (yuv4mpeg->name) lives_free(yuv4mpeg->name);
246
247 if (yuv4mpeg->type == YUV4_TYPE_FW) fw_cards = lives_list_remove(fw_cards, LIVES_INT_TO_POINTER(yuv4mpeg->cardno));
248 if (yuv4mpeg->type == YUV4_TYPE_TV) mainw->videodevs = lives_list_remove(mainw->videodevs,
249 LIVES_INT_TO_POINTER(yuv4mpeg->cardno));
250 }
251
252
weed_layer_set_from_yuv4m(weed_layer_t * layer,lives_clip_t * sfile)253 void weed_layer_set_from_yuv4m(weed_layer_t *layer, lives_clip_t *sfile) {
254 lives_yuv4m_t *yuv4mpeg = (lives_yuv4m_t *)(sfile->ext_src);
255
256 y4data thread_data;
257
258 pthread_t y4thread;
259
260 ticks_t timeout;
261
262 lives_alarm_t alarm_handle;
263
264 int error;
265
266 if (!yuv4mpeg->ready) lives_yuv_stream_start_read(sfile);
267
268 weed_set_int_value(layer, WEED_LEAF_WIDTH, sfile->hsize);
269 weed_set_int_value(layer, WEED_LEAF_HEIGHT, sfile->vsize);
270 weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, WEED_PALETTE_YUV420P);
271 weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_YCBCR);
272
273 create_empty_pixel_data(layer, TRUE, TRUE);
274
275 if (!yuv4mpeg->ready) {
276 return;
277 }
278
279 yuv4mpeg->pixel_data = weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, &error);
280
281 // create a thread to open the stream header
282
283 thread_data.yuv4mpeg = yuv4mpeg;
284 pthread_create(&y4thread, NULL, y4frame_thread, &thread_data);
285
286 alarm_handle = lives_alarm_set(LIVES_SHORTEST_TIMEOUT);
287
288 while ((timeout = lives_alarm_check(alarm_handle)) > 0 && !pthread_kill(y4thread, 0)) {
289 // wait for thread to complete or timeout
290 lives_usleep(prefs->sleep_time);
291 }
292 lives_alarm_clear(alarm_handle);
293
294 if (timeout == 0) {
295 // timeout - kill thread and wait for it to terminate
296 pthread_cancel(y4thread);
297 d_print(_("Unable to read the incoming video frame\n"));
298 gotbroken = TRUE;
299 } else gotbroken = FALSE;
300
301 pthread_join(y4thread, NULL);
302
303 lives_free(yuv4mpeg->pixel_data);
304 yuv4mpeg->pixel_data = NULL;
305
306 weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_MPEG);
307
308 return;
309 }
310
311
open_yuv4m_inner(const char * filename,const char * fname,int new_file,int type,int cardno)312 static boolean open_yuv4m_inner(const char *filename, const char *fname, int new_file, int type, int cardno) {
313 // create a virtual clip
314 int old_file = mainw->current_file;
315
316 lives_yuv4m_t *yuv4mpeg;
317
318 cfile->clip_type = CLIP_TYPE_YUV4MPEG;
319
320 // get size of frames, arate, achans, asamps, signed endian
321 yuv4mpeg = lives_yuv4mpeg_alloc();
322
323 yuv4mpeg->fd = -1;
324
325 yuv4mpeg->filename = lives_strdup(filename);
326 yuv4mpeg->name = lives_strdup(fname);
327
328 yuv4mpeg->type = type;
329 yuv4mpeg->cardno = cardno;
330
331 cfile->ext_src = yuv4mpeg;
332 cfile->ext_src_type = LIVES_EXT_SRC_FIFO;
333
334 cfile->bpp = 12;
335
336 cfile->start = cfile->end = cfile->frames = 1;
337
338 cfile->hsize = DEF_GEN_WIDTH;
339 cfile->vsize = DEF_GEN_HEIGHT;
340
341 cfile->img_type = IMG_TYPE_BEST; // override the pref
342
343 cfile->is_loaded = TRUE;
344
345 add_to_clipmenu();
346
347 switch_to_file((mainw->current_file = old_file), new_file);
348
349 return TRUE;
350 }
351
352
on_open_yuv4m_activate(LiVESMenuItem * menuitem,livespointer user_data)353 void on_open_yuv4m_activate(LiVESMenuItem *menuitem, livespointer user_data) {
354 // open a general yuvmpeg stream
355 // start "playing" but open frames in yuv4mpeg format on stdin
356
357 int old_file = mainw->current_file, new_file = mainw->first_free_file;
358 char *tmp;
359 char *filename;
360 char *fname;
361
362 char *audio_real, *audio_fake;
363
364 if (menuitem && !do_yuv4m_open_warning()) return;
365
366 fname = (_("yuv4mpeg stream"));
367
368 if (!get_new_handle(new_file, fname)) {
369 lives_free(fname);
370 return;
371 }
372
373 mainw->current_file = new_file;
374
375 if (!strlen(prefs->yuvin)) {
376 filename = choose_file(NULL, NULL, NULL, LIVES_FILE_CHOOSER_ACTION_OPEN, _("Open _yuv4mpeg stream (fifo)"), NULL);
377 if (!filename) return;
378 } else filename = lives_strdup(prefs->yuvin);
379
380 mkfifo(filename, S_IRUSR | S_IWUSR);
381
382 if (!open_yuv4m_inner(filename, fname, new_file, YUV4_TYPE_GENERIC, 0)) {
383 close_current_file(old_file);
384 lives_free(filename);
385 lives_free(fname);
386 return;
387 }
388
389 lives_free(fname);
390
391 if (!lives_yuv_stream_start_read(cfile)) {
392 close_current_file(old_file);
393 lives_free(filename);
394 return;
395 }
396
397 new_file = mainw->current_file;
398
399 lives_snprintf(cfile->type, 40, "%s", _("yu4mpeg stream in"));
400
401 d_print((tmp = lives_strdup_printf(_("Opened yuv4mpeg stream on %s"), filename)));
402 lives_free(tmp);
403 lives_free(filename);
404
405 d_print(_("Audio: "));
406
407 if (cfile->achans == 0) {
408 d_print(_("none\n"));
409 } else {
410 d_print((tmp = lives_strdup_printf(P_("%d Hz %d channel %d bps\n", "%d Hz %d channels %d bps\n", cfile->achans),
411 cfile->arate, cfile->achans, cfile->asampsize)));
412 lives_free(tmp);
413 }
414
415 // if not playing, start playing
416 if (!LIVES_IS_PLAYING) {
417 // temp kludge, symlink audiodump.pcm to wav file, then pretend we are playing
418 // an opening preview . Doesn't work with fifo.
419 // and we dont really care if it doesnt work
420
421 // but what it means is, if we have an audio file or stream at
422 // "prefs->workdir/audiodump.pcm" we will try to play it
423
424 // real is workdir/audiodump.pcm
425 audio_real = get_audio_file_name(-1, TRUE);
426 // fake is workdir/handle/audiodump.pcm
427 audio_fake = get_audio_file_name(mainw->current_file, TRUE);
428
429 // fake file will go away when we close the current clip
430 lives_ln(audio_real, audio_fake);
431
432 lives_free(audio_real);
433 lives_free(audio_fake);
434
435 lives_free(tmp);
436
437 mainw->pre_play_file = old_file;
438 // start playing
439 start_playback_async(7);
440 return;
441 }
442 // TODO - else...
443
444 if (mainw->current_file != old_file && mainw->current_file != new_file)
445 old_file = mainw->current_file; // we could have rendered to a new file
446
447 mainw->current_file = new_file;
448
449 // close this temporary clip
450 close_current_file(old_file);
451 }
452
453
454 ///////////////////////////////////////////////////////////////////////////////
455 // write functions - not used currently
456
lives_yuv_stream_start_write(lives_yuv4m_t * yuv4mpeg,const char * filename,int hsize,int vsize,double fps)457 boolean lives_yuv_stream_start_write(lives_yuv4m_t *yuv4mpeg, const char *filename, int hsize, int vsize, double fps) {
458 int i;
459
460 if (mainw->fixed_fpsd > -1. && mainw->fixed_fpsd != fps) {
461 do_error_dialog(lives_strdup_printf(_("Unable to set display framerate to %.3f fps.\n\n"), fps));
462 return FALSE;
463 }
464 mainw->fixed_fpsd = fps;
465
466 if (!filename) filename = lives_strdup_printf("%s/streamout.yuv", prefs->workdir);
467
468 // TODO - do_threaded_dialog
469 if ((yuvout = creat(filename, O_CREAT)) < 0) {
470 do_error_dialog(lives_strdup_printf(_("Unable to open yuv4mpeg out stream %s\n"), filename));
471 return FALSE;
472 }
473
474 if (mainw->fixed_fpsd > 23.9999 && mainw->fixed_fpsd < 24.0001) {
475 y4m_si_set_framerate(&(yuv4mpeg->streaminfo), y4m_fps_FILM);
476 } else return FALSE;
477 y4m_si_set_interlace(&(yuv4mpeg->streaminfo), Y4M_ILACE_NONE);
478
479 y4m_si_set_width(&(yuv4mpeg->streaminfo), (hsize_out = hsize));
480 y4m_si_set_height(&(yuv4mpeg->streaminfo), (vsize_out = vsize));
481 y4m_si_set_sampleaspect(&(yuv4mpeg->streaminfo), yuv4mpeg->sar);
482
483 i = y4m_write_stream_header(yuvout, &(yuv4mpeg->streaminfo));
484
485 if (i != Y4M_OK) return FALSE;
486
487 return TRUE;
488 }
489
490
lives_yuv_stream_write_frame(lives_yuv4m_t * yuv4mpeg,void * pixel_data)491 boolean lives_yuv_stream_write_frame(lives_yuv4m_t *yuv4mpeg, void *pixel_data) {
492 // pixel_data is planar yuv420 data
493 int i;
494
495 uint8_t *planes[3];
496 uint8_t *pixels = (uint8_t *)pixel_data;
497
498 planes[0] = &(pixels[0]);
499 planes[1] = &(pixels[hsize_out * vsize_out]);
500 planes[2] = &(pixels[hsize_out * vsize_out * 5 / 4]);
501
502 i = y4m_write_frame(yuvout, &(yuv4mpeg->streaminfo),
503 &(yuv4mpeg->frameinfo), (uint8_t **)&planes[0]);
504 if (i != Y4M_OK) return FALSE;
505 return TRUE;
506 }
507
508
lives_yuv_stream_stop_write(lives_yuv4m_t * yuv4mpeg)509 void lives_yuv_stream_stop_write(lives_yuv4m_t *yuv4mpeg) {
510 y4m_fini_stream_info(&(yuv4mpeg->streaminfo));
511 y4m_fini_frame_info(&(yuv4mpeg->frameinfo));
512 close(yuvout);
513 }
514
515
516 //////////////////////////////////////////////////////////////
517
518 /**
519 @brief add live input peripherals
520
521 some time in the future it would be nice to implement these via videojack
522
523 advantages would be: - no longer necessary to have mjpegtools
524 - multiple copies of LiVES could share the same input at (almost) zero cost
525
526 for each of these functions:
527 - prompt user for name of device, etc.
528
529 check if device already opened, if so exit
530
531 create clip with default values; clip type is YUV4MPEG
532
533 create a fifo file
534 set mplayer reading from device and writing yuv4mpeg
535
536 start reading - update clip values
537
538 note: we add the clip to the menu and to mainw->cliplist
539 beware when handling mainw->cliplist
540 */
on_live_tvcard_activate(LiVESMenuItem * menuitem,livespointer user_data)541 void on_live_tvcard_activate(LiVESMenuItem *menuitem, livespointer user_data) {
542 int cardno = 0;
543
544 int new_file = mainw->first_free_file;
545
546 int response;
547
548 char *com, *tmp;
549 char *fifofile;
550
551 char *chanstr;
552 char *devstr;
553
554 char *fname;
555
556 LiVESWidget *card_dialog;
557
558 lives_tvcardw_t *tvcardw;
559
560 if (!HAS_EXTERNAL_PLAYER || USE_MPV) {
561 do_need_mplayer_dialog();
562 return;
563 }
564
565 fifofile = lives_strdup_printf("%s/tvpic_%d.y4m", prefs->workdir, capable->mainpid);
566
567 mainw->open_deint = FALSE;
568
569 card_dialog = create_cdtrack_dialog(LIVES_DEVICE_TV_CARD, NULL);
570
571 tvcardw = (lives_tvcardw_t *)lives_widget_object_get_data(LIVES_WIDGET_OBJECT(card_dialog), "tvcard_data");
572
573 response = lives_dialog_run(LIVES_DIALOG(card_dialog));
574 if (response == LIVES_RESPONSE_CANCEL) {
575 lives_widget_destroy(card_dialog);
576 lives_free(fifofile);
577 lives_free(tvcardw);
578 return;
579 }
580
581 cardno = (int)mainw->fx1_val;
582 chanstr = lives_strdup_printf("%d", (int)mainw->fx2_val);
583
584 if (lives_list_find(mainw->videodevs, LIVES_INT_TO_POINTER(cardno))) {
585 lives_widget_destroy(card_dialog);
586 do_card_in_use_error();
587 lives_free(chanstr);
588 lives_free(fifofile);
589 lives_free(tvcardw);
590 return;
591 }
592
593 fname = lives_strdup_printf(_("TV card %d"), cardno);
594
595 if (!get_new_handle(new_file, fname)) {
596 lives_widget_destroy(card_dialog);
597 lives_free(chanstr);
598 lives_free(fifofile);
599 lives_free(fname);
600 lives_free(tvcardw);
601 return;
602 }
603
604 devstr = lives_strdup_printf("/dev/video%d", cardno);
605
606 if (!check_dev_busy(devstr)) {
607 lives_widget_destroy(card_dialog);
608 do_dev_busy_error(fname);
609 lives_free(devstr);
610 lives_free(chanstr);
611 lives_free(fifofile);
612 lives_free(fname);
613 lives_free(tvcardw);
614 return;
615 }
616
617 mainw->videodevs = lives_list_append(mainw->videodevs, LIVES_INT_TO_POINTER(cardno));
618
619 mainw->current_file = new_file;
620
621 cfile->deinterlace = mainw->open_deint;
622
623 lives_rm(fifofile);
624 mkfifo(fifofile, S_IRUSR | S_IWUSR);
625
626 if (!tvcardw->use_advanced) {
627 com = lives_strdup_printf("%s open_tv_card \"%s\" \"%s\" \"%s\" \"%s\"", prefs->backend, cfile->handle, chanstr,
628 devstr, fifofile);
629 } else {
630 double fps = 0.;
631 const char *driver = NULL, *outfmt = NULL;
632 int width = 0, height = 0;
633 int input = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttoni));
634
635 if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(tvcardw->radiobuttond))) {
636 width = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttonw));
637 height = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(tvcardw->spinbuttonh));
638 fps = lives_spin_button_get_value(LIVES_SPIN_BUTTON(tvcardw->spinbuttonf));
639 }
640
641 driver = lives_combo_get_active_text(LIVES_COMBO(tvcardw->combod));
642 outfmt = lives_combo_get_active_text(LIVES_COMBO(tvcardw->comboo));
643
644 com = lives_strdup_printf("%s open_tv_card \"%s\" \"%s\" \"%s\" \"%s\" %d %d %d %.3f \"%s\" \"%s\"",
645 prefs->backend, cfile->handle, chanstr,
646 devstr, fifofile, input, width, height, fps, driver, outfmt);
647 }
648 lives_widget_destroy(card_dialog);
649 lives_free(tvcardw);
650
651 lives_system(com, FALSE);
652 lives_free(com);
653
654 if (THREADVAR(com_failed)) {
655 THREADVAR(com_failed) = FALSE;
656 lives_free(fname);
657 lives_free(chanstr);
658 lives_free(fifofile);
659 lives_free(devstr);
660 return;
661 }
662
663 if (!open_yuv4m_inner(fifofile, fname, new_file, YUV4_TYPE_TV, cardno)) {
664 lives_free(fname);
665 lives_free(chanstr);
666 lives_free(fifofile);
667 lives_free(devstr);
668 return;
669 }
670
671 lives_snprintf(cfile->type, 40, "%s", fname);
672
673 d_print((tmp = lives_strdup_printf(_("Opened TV card %d (%s)"), cardno, devstr)));
674
675 lives_free(tmp);
676 lives_free(fname);
677 lives_free(chanstr);
678 lives_free(devstr);
679 lives_free(fifofile);
680 }
681
682
on_live_fw_activate(LiVESMenuItem * menuitem,livespointer user_data)683 void on_live_fw_activate(LiVESMenuItem *menuitem, livespointer user_data) {
684 char *com, *tmp;
685 int cardno;
686 int cache = 1024;
687
688 int new_file = mainw->first_free_file;
689
690 int response;
691
692 char *fifofile = lives_strdup_printf("%s/firew_%d.y4m", prefs->workdir, capable->mainpid);
693 char *fname;
694
695 LiVESWidget *card_dialog;
696
697 mainw->open_deint = FALSE;
698
699 card_dialog = create_cdtrack_dialog(LIVES_DEVICE_FW_CARD, NULL);
700 response = lives_dialog_run(LIVES_DIALOG(card_dialog));
701 if (response == LIVES_RESPONSE_CANCEL) {
702 lives_widget_destroy(card_dialog);
703 lives_free(fifofile);
704 return;
705 }
706
707 cardno = (int)mainw->fx1_val;
708
709 lives_widget_destroy(card_dialog);
710
711 if (lives_list_find(fw_cards, LIVES_INT_TO_POINTER(cardno))) {
712 lives_free(fifofile);
713 do_card_in_use_error();
714 return;
715 }
716
717 fname = lives_strdup_printf(_("Firewire card %d"), cardno);
718
719 if (!get_new_handle(new_file, fname)) {
720 lives_free(fifofile);
721 lives_free(fname);
722 return;
723 }
724
725 fw_cards = lives_list_append(fw_cards, LIVES_INT_TO_POINTER(cardno));
726
727 mainw->current_file = new_file;
728 cfile->deinterlace = mainw->open_deint;
729
730 lives_rm(fifofile);
731 mkfifo(fifofile, S_IRUSR | S_IWUSR);
732
733 com = lives_strdup_printf("%s open_fw_card \"%s\" %d %d \"%s\"", prefs->backend, cfile->handle, cardno, cache, fifofile);
734 lives_system(com, FALSE);
735 lives_free(com);
736
737 if (THREADVAR(com_failed)) {
738 THREADVAR(com_failed) = FALSE;
739 lives_free(fname);
740 lives_free(fifofile);
741 return;
742 }
743
744 if (!open_yuv4m_inner(fifofile, fname, new_file, YUV4_TYPE_FW, cardno)) {
745 lives_free(fname);
746 lives_free(fifofile);
747 return;
748 }
749
750 lives_snprintf(cfile->type, 40, "%s", fname);
751
752 d_print((tmp = lives_strdup_printf(_("Opened firewire card %d"), cardno)));
753
754 lives_free(tmp);
755 lives_free(fname);
756 lives_free(fifofile);
757 }
758