1 // LiVES - videodev input
2 // (c) G. Finch 2010 - 2019 <salsaman+lives@gmail.com>
3 // released under the GNU GPL 3 or later
4 // see file COPYING or www.gnu.org for details
5 
6 #include "main.h"
7 
8 #ifdef HAVE_UNICAP
9 #define DEBUG_UNICAP
10 
11 #include "videodev.h"
12 #include "interface.h"
13 #include "callbacks.h"
14 #include "effects-weed.h"
15 
16 #include <unicap/unicap.h>
17 
lives_wait_user_buffer(lives_vdev_t * ldev,unicap_data_buffer_t ** buff,double timeout)18 static boolean lives_wait_user_buffer(lives_vdev_t *ldev, unicap_data_buffer_t **buff, double timeout) {
19   // wait for USER type buffer
20   unicap_status_t status;
21   int ncount;
22   lives_alarm_t alarm_handle = lives_alarm_set(timeout * TICKS_PER_SECOND_DBL);
23 
24   do {
25     status = unicap_poll_buffer(ldev->handle, &ncount);
26 
27 #ifdef DEBUG_UNICAP
28     if (status != STATUS_SUCCESS) lives_printerr("Unicap poll failed with status %d\n", status);
29 #endif
30     if (ncount >= 0) {
31       lives_alarm_clear(alarm_handle);
32       if (!SUCCESS(unicap_wait_buffer(ldev->handle, buff))) return FALSE;
33       return TRUE;
34     }
35     lives_usleep(prefs->sleep_time);
36     lives_widget_context_update();
37     sched_yield();
38   } while (lives_alarm_check(alarm_handle) > 0);
39 
40   return FALSE;
41 }
42 
43 
lives_wait_system_buffer(lives_vdev_t * ldev,double timeout)44 static boolean lives_wait_system_buffer(lives_vdev_t *ldev, double timeout) {
45   // wait for SYSTEM type buffer
46   lives_alarm_t alarm_handle = lives_alarm_set(timeout * TICKS_PER_SECOND_DBL);
47 
48   do {
49     if (ldev->buffer_ready != 0) {
50       lives_alarm_clear(alarm_handle);
51       return TRUE;
52     }
53     lives_usleep(prefs->sleep_time);
54     lives_widget_context_update();
55     sched_yield();
56   } while (lives_alarm_check(alarm_handle) > 0);
57   lives_alarm_clear(alarm_handle);
58 
59   return FALSE;
60 }
61 
62 
new_frame_cb(unicap_event_t event,unicap_handle_t handle,unicap_data_buffer_t * buffer,void * usr_data)63 static void new_frame_cb(unicap_event_t event, unicap_handle_t handle,
64                          unicap_data_buffer_t *buffer, void *usr_data) {
65   lives_vdev_t *ldev = (lives_vdev_t *)usr_data;
66   if (!LIVES_IS_PLAYING || (mainw->playing_file != ldev->fileno && mainw->blend_file != ldev->fileno)) {
67     ldev->buffer_ready = 0;
68     return;
69   }
70 
71   if (ldev->buffer_ready != 1) {
72     lives_memcpy(ldev->buffer1.data, buffer->data, ldev->buffer1.buffer_size);
73     ldev->buffer_ready = 1;
74   } else {
75     lives_memcpy(ldev->buffer2.data, buffer->data, ldev->buffer2.buffer_size);
76     ldev->buffer_ready = 2;
77   }
78 }
79 
80 
weed_layer_set_from_lvdev(weed_layer_t * layer,lives_clip_t * sfile,double timeoutsecs)81 boolean weed_layer_set_from_lvdev(weed_layer_t *layer, lives_clip_t *sfile, double timeoutsecs) {
82   lives_vdev_t *ldev = (lives_vdev_t *)sfile->ext_src;
83   unicap_data_buffer_t *returned_buffer = NULL;
84   void **pixel_data;
85   void *odata = ldev->buffer1.data;
86 
87   int error;
88 
89   weed_set_int_value(layer, WEED_LEAF_WIDTH, sfile->hsize /
90                      weed_palette_get_pixels_per_macropixel(ldev->current_palette));
91   weed_set_int_value(layer, WEED_LEAF_HEIGHT, sfile->vsize);
92   weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, ldev->current_palette);
93   weed_set_int_value(layer, WEED_LEAF_YUV_SUBSPACE, WEED_YUV_SUBSPACE_YCBCR); // TODO - handle bt.709
94   weed_set_int_value(layer, WEED_LEAF_YUV_SAMPLING, WEED_YUV_SAMPLING_DEFAULT); // TODO - use ldev->YUV_sampling
95   weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, ldev->YUV_clamping);
96 
97   create_empty_pixel_data(layer, TRUE, TRUE);
98 
99   if (ldev->buffer_type == UNICAP_BUFFER_TYPE_USER) {
100     if (weed_palette_get_nplanes(ldev->current_palette) == 1 || ldev->is_really_grey) {
101       ldev->buffer1.data = (unsigned char *)weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, &error);
102     }
103 
104     unicap_queue_buffer(ldev->handle, &ldev->buffer1);
105 
106     if (!lives_wait_user_buffer(ldev, &returned_buffer, timeoutsecs)) {
107 #ifdef DEBUG_UNICAP
108       lives_printerr("Failed to wait for user buffer!\n");
109       unicap_stop_capture(ldev->handle);
110       unicap_dequeue_buffer(ldev->handle, &returned_buffer);
111       unicap_start_capture(ldev->handle);
112 #endif
113       ldev->buffer1.data = (unsigned char *)odata;
114       return FALSE;
115     }
116   } else {
117     // wait for callback to fill buffer
118     if (!lives_wait_system_buffer(ldev, timeoutsecs)) {
119 #ifdef DEBUG_UNICAP
120       lives_printerr("Failed to wait for system buffer!\n");
121 #endif
122     }
123     if (ldev->buffer_ready == 1) returned_buffer = &ldev->buffer1;
124     else returned_buffer = &ldev->buffer2;
125   }
126 
127   pixel_data = weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, &error);
128 
129   if (weed_palette_get_nplanes(ldev->current_palette) > 1 && !ldev->is_really_grey) {
130     boolean contig = FALSE;
131     if (weed_get_boolean_value(layer, WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS, &error) == WEED_TRUE) contig = TRUE;
132     pixel_data_planar_from_membuf(pixel_data, returned_buffer->data, sfile->hsize * sfile->vsize, ldev->current_palette, contig);
133   } else {
134     if (ldev->buffer_type == UNICAP_BUFFER_TYPE_SYSTEM) {
135       int rowstride = weed_get_int_value(layer, WEED_LEAF_ROWSTRIDES, &error);
136       size_t bsize = rowstride * sfile->vsize;
137       if (bsize > returned_buffer->buffer_size) {
138 #ifdef DEBUG_UNICAP
139         lives_printerr("Warning - returned buffer size too small !\n");
140 #endif
141         bsize = returned_buffer->buffer_size;
142       }
143       lives_memcpy(pixel_data[0], returned_buffer->data, bsize);
144     }
145   }
146 
147   // shouldnt be necessary since we specified black_fill in create_empty_pixel_data()
148 
149   /* if (ldev->is_really_grey) { */
150   /*   // y contains our greyscale data */
151   /*   // set u and v planes to 128 */
152   /*   memset(pixel_data[1], 128, sfile->hsize * sfile->vsize); */
153   /*   memset(pixel_data[2], 128, sfile->hsize * sfile->vsize); */
154   /* } */
155 
156   lives_free(pixel_data);
157 
158   ldev->buffer1.data = (unsigned char *)odata;
159 
160   return TRUE;
161 }
162 
163 
lvdev_get_best_format(const unicap_format_t * formats,lives_vdev_t * ldev,int palette,int width,int height)164 static unicap_format_t *lvdev_get_best_format(const unicap_format_t *formats,
165     lives_vdev_t *ldev, int palette, int width, int height) {
166   // get nearest format for given palette, width and height
167   // if palette is WEED_PALETTE_END, or cannot be matched, get best quality palette (preferring RGB)
168   // width and height must be set, actual width and height will be set as near to this as possible
169   // giving preference to larger frame size
170 
171   // if the device supports no usable formats, returns NULL
172 
173   // Note: we match first by palette, then by size
174 
175   int format_count, i;
176   unicap_format_t *format;
177   int f = -1;
178   int bestp = WEED_PALETTE_END;
179   int bestw = 0, besth = 0;
180   int cpal;
181 
182   // get details
183   for (format_count = 0;
184        SUCCESS(unicap_enumerate_formats(ldev->handle, NULL, (unicap_format_t *)&formats[format_count], format_count))
185        && (format_count < MAX_FORMATS); format_count++) {
186     format = (unicap_format_t *)&formats[format_count];
187 
188     // TODO - check if we need to free format->sizes
189 
190     // TODO - prefer non-interlaced, YCbCr for YUV
191     cpal = fourccp_to_weedp(format->fourcc, format->bpp, NULL, NULL, NULL, NULL);
192 
193     if (cpal == WEED_PALETTE_END || weed_palette_is_alpha(cpal)) {
194 #ifdef DEBUG_UNICAP
195       // set format to try and get more data
196       unicap_set_format(ldev->handle, format);
197       lives_printerr("Unusable palette with fourcc 0x%x  bpp=%d, size=%dx%d buf=%d\n", format->fourcc, format->bpp,
198                      format->size.width,
199                      format->size.height, (int)format->buffer_size);
200 #endif
201       continue;
202     }
203 
204     if (bestp == WEED_PALETTE_END || cpal == palette || weed_palette_is_alpha(bestp) ||
205         weed_palette_is_lower_quality(bestp, cpal) ||
206         (weed_palette_is_yuv(bestp) && weed_palette_is_rgb(cpal))) {
207       // got better palette, or exact match
208 
209       // prefer exact match on target palette if we have it
210       if (palette != WEED_PALETTE_END && bestp == palette && cpal != palette) continue;
211 
212       // otherwise this is our best palette up to now
213       bestp = cpal;
214 
215       // TODO - try to minimise aspect delta
216       // for now we just go with the smallest size >= target (or largest frame size if none are >= target)
217 
218       if (width >= format->min_size.width && height >= format->min_size.height) {
219         if (format->h_stepping > 0 && format->v_stepping > 0) {
220 #ifdef DEBUG_UNICAP
221           lives_printerr("Can set any size with step %d and %d; min %d x %d, max %d x %d\n",
222                          format->h_stepping, format->v_stepping,
223                          format->min_size.width, format->min_size.height, format->max_size.width, format->max_size.height);
224 #endif
225           // can set exact size (within stepping limits)
226           format->size.width = (int)(((double)width + (double)format->h_stepping / 2.)
227                                      / (double)format->h_stepping) * format->h_stepping;
228 
229           format->size.height = (int)(((double)height + (double)format->v_stepping / 2.)
230                                       / (double)format->v_stepping) * format->v_stepping;
231 
232           if (format->size.width > format->max_size.width) format->size.width = format->max_size.width;
233           if (format->size.height > format->max_size.height) format->size.height = format->max_size.height;
234 
235           if (format->size.width > bestw || format->size.height > besth) {
236             bestw = format->size.width;
237             besth = format->size.height;
238             f = format_count;
239           }
240         } else {
241           // array of sizes supported
242           // step through sizes
243 #ifdef DEBUG_UNICAP
244           lives_printerr("Checking %d array sizes\n", format->size_count);
245 #endif
246 
247           if (format->size_count == 0) {
248             // only one size we can use, this is it...
249 
250             if ((format->size.width > bestw || format->size.height > besth) && (bestw < width || besth < height)) {
251               // this format supports a better size match
252               bestw = format->size.width;
253               besth = format->size.height;
254               f = format_count;
255 #ifdef DEBUG_UNICAP
256               lives_printerr("Size is best so far\n");
257 #endif
258             }
259             continue;
260           }
261 
262           // array of sizes
263           for (i = 0; i < format->size_count; i++) {
264 #ifdef DEBUG_UNICAP
265             lives_printerr("entry %d:%d x %d\n", i, format->sizes[i].width, format->sizes[i].height);
266 #endif
267             if (format->sizes[i].width > bestw && format->sizes[i].height > besth &&
268                 (bestw < width || besth < height)) {
269               // this format supports a better size match
270               bestw = format->size.width = format->sizes[i].width;
271               besth = format->size.height = format->sizes[i].height;
272               f = format_count;
273 #ifdef DEBUG_UNICAP
274               lives_printerr("Size is best so far\n");
275 #endif
276             }
277           }
278         }
279       } else {
280         // target is smaller than min width, height
281         if (bestw < format->min_size.width || besth < format->min_size.height) continue; // TODO - minimise aspect delta
282         bestw = format->size.width = format->min_size.width;
283         besth = format->size.height = format->min_size.height;
284         f = format_count;
285       }
286     }
287   }
288 
289   if (f > -1) return (unicap_format_t *)(&formats[f]);
290   return NULL;
291 }
292 
293 
294 /// get devnumber from user and open it to a new clip
295 
open_vdev_inner(unicap_device_t * device)296 static boolean open_vdev_inner(unicap_device_t *device) {
297   // create a virtual clip
298   lives_vdev_t *ldev = (lives_vdev_t *)lives_malloc(sizeof(lives_vdev_t));
299   unicap_format_t formats[MAX_FORMATS];
300   unicap_format_t *format;
301 
302   // open dev
303   unicap_open(&ldev->handle, device);
304 
305   //check return value and take appropriate action
306   if (!ldev->handle) {
307     LIVES_ERROR("vdev input: cannot open device");
308     lives_free(ldev);
309     return FALSE;
310   }
311 
312   unicap_lock_stream(ldev->handle);
313 
314   format = lvdev_get_best_format(formats, ldev, WEED_PALETTE_END, DEF_GEN_WIDTH, DEF_GEN_HEIGHT);
315 
316   if (!format) {
317     LIVES_INFO("No useful formats found");
318     unicap_unlock_stream(ldev->handle);
319     unicap_close(ldev->handle);
320     lives_free(ldev);
321     return FALSE;
322   }
323 
324   if (!(format->buffer_types & UNICAP_BUFFER_TYPE_USER)) {
325     // have to use system buffer type
326     format->buffer_type = UNICAP_BUFFER_TYPE_SYSTEM;
327 
328     // set a callback for new frame
329     unicap_register_callback(ldev->handle, UNICAP_EVENT_NEW_FRAME, (unicap_callback_t) new_frame_cb,
330                              (void *) ldev);
331 
332   } else format->buffer_type = UNICAP_BUFFER_TYPE_USER;
333 
334   ldev->buffer_type = format->buffer_type;
335 
336   // ignore YUV subspace for now
337   ldev->current_palette = fourccp_to_weedp(format->fourcc, format->bpp, (int *)&cfile->interlace,
338                           &ldev->YUV_sampling, &ldev->YUV_subspace, &ldev->YUV_clamping);
339 
340 #ifdef DEBUG_UNICAP
341   lives_printerr("\nUsing palette with fourcc 0x%x, translated as %s\n", format->fourcc,
342                  weed_palette_get_name(ldev->current_palette));
343 #endif
344 
345   if (!SUCCESS(unicap_set_format(ldev->handle, format))) {
346     LIVES_ERROR("Unicap error setting format");
347     unicap_unlock_stream(ldev->handle);
348     unicap_close(ldev->handle);
349     lives_free(ldev);
350     return FALSE;
351   }
352 
353   g_print("ALLX %ld %d %d %d %d\n", format->buffer_size, format->size.width, format->size.height,
354           weed_palette_get_bits_per_macropixel(
355             ldev->current_palette), weed_palette_get_pixels_per_macropixel(ldev->current_palette));
356 
357   if (format->buffer_size != format->size.width * format->size.height * weed_palette_get_bits_per_macropixel(
358         ldev->current_palette) /
359       weed_palette_get_pixels_per_macropixel(ldev->current_palette) / 8) {
360     int wwidth = format->size.width, awidth;
361     int wheight = format->size.height, aheight;
362     // something went wrong setting the size - the buffer is wrongly sized
363 #ifdef DEBUG_UNICAP
364     lives_printerr("Unicap buffer size is wrong, resetting it.\n");
365 #endif
366     // get the size again
367 
368     unicap_get_format(ldev->handle, format);
369     awidth = format->size.width;
370     aheight = format->size.height;
371 
372 #ifdef DEBUG_UNICAP
373     lives_printerr("Wanted frame size %d x %d, got %d x %d\n", wwidth, wheight, awidth, aheight);
374 #endif
375 
376     format->buffer_size = format->size.width * format->size.height * weed_palette_get_bits_per_macropixel(ldev->current_palette) /
377                           weed_palette_get_pixels_per_macropixel(ldev->current_palette) / 8;
378   }
379 
380   cfile->hsize = format->size.width;
381   cfile->vsize = format->size.height;
382 
383   cfile->ext_src = ldev;
384   cfile->ext_src_type = LIVES_EXT_SRC_DEVICE;
385 
386   ldev->buffer1.data = (unsigned char *)lives_malloc(format->buffer_size);
387   ldev->buffer1.buffer_size = format->buffer_size;
388 
389   ldev->buffer2.data = (unsigned char *)lives_malloc(format->buffer_size);
390   ldev->buffer2.buffer_size = format->buffer_size;
391 
392   ldev->buffer_ready = 0;
393   ldev->fileno = mainw->current_file;
394 
395   cfile->bpp = format->bpp;
396 
397   unicap_start_capture(ldev->handle);
398 
399   // if it is greyscale, we will add fake U and V planes
400   if (ldev->current_palette == WEED_PALETTE_A8) {
401     ldev->current_palette = WEED_PALETTE_YUV444P;
402     ldev->is_really_grey = TRUE;
403   } else ldev->is_really_grey = FALSE;
404 
405   return TRUE;
406 }
407 
408 
lives_vdev_free(lives_vdev_t * ldev)409 void lives_vdev_free(lives_vdev_t *ldev) {
410   if (!ldev) return;
411   unicap_stop_capture(ldev->handle);
412   unicap_unlock_stream(ldev->handle);
413   unicap_close(ldev->handle);
414   if (ldev->buffer1.data) lives_free(ldev->buffer1.data);
415   if (ldev->buffer2.data) lives_free(ldev->buffer2.data);
416 }
417 
418 
on_open_vdev_activate(LiVESMenuItem * menuitem,livespointer user_data)419 boolean on_open_vdev_activate(LiVESMenuItem *menuitem, livespointer user_data) {
420   unicap_device_t devices[MAX_DEVICES];
421 
422   LiVESList *devlist = NULL;
423 
424   LiVESWidget *card_dialog;
425 
426   char *fname;
427 
428   int devno = 0;
429 
430   int new_file = mainw->first_free_file;
431   int old_file = mainw->current_file;
432 
433   int response;
434 
435   int dev_count;
436   int status = STATUS_SUCCESS;
437 
438   register int i;
439 
440   mainw->open_deint = FALSE;
441 
442   status = unicap_reenumerate_devices(&dev_count);
443 
444   if (dev_count == 0) {
445     do_no_in_vdevs_error();
446     return FALSE;
447   }
448 
449   // get device list
450   for (i = 0; SUCCESS(status) && (dev_count < MAX_DEVICES); i++) {
451     status = unicap_enumerate_devices(NULL, &devices[i], i);
452     if (!SUCCESS(status)) {
453       if (i == 0) LIVES_INFO("Unicap failed to get any devices");
454     }
455   }
456 
457   if (!user_data) {
458     for (i = 0; i < dev_count; i++) {
459       if (!unicap_is_stream_locked(&devices[i])) {
460         devlist = lives_list_prepend(devlist, devices[i].identifier);
461       }
462     }
463 
464     if (!devlist) {
465       do_locked_in_vdevs_error();
466       return FALSE;
467     }
468 
469     mainw->fx1_val = 0;
470     mainw->open_deint = FALSE;
471     card_dialog = create_combo_dialog(1, (livespointer)devlist);
472     response = lives_dialog_run(LIVES_DIALOG(card_dialog));
473     lives_list_free(devlist); /// free only after runniong dialog !!!
474     if (response == LIVES_RESPONSE_CANCEL) {
475       return FALSE;
476     }
477     lives_widget_destroy(card_dialog);
478   } else {
479     char *device = (char *)user_data;
480     for (i = 0; i < dev_count; i++) {
481       if (!strcmp(device, devices[i].device)) {
482         mainw->fx1_val = i;
483         break;
484       }
485     }
486   }
487 
488   for (i = dev_count - 1; i >= 0; i--) {
489     if (!unicap_is_stream_locked(&devices[i])) {
490       if (mainw->fx1_val == 0) {
491         devno = i;
492         break;
493       }
494     }
495     mainw->fx1_val--;
496   }
497 
498   if (*devices[devno].device) fname = lives_strdup(devices[devno].device);
499   else fname = lives_strdup(devices[devno].identifier);
500 
501   if (!get_new_handle(new_file, fname)) {
502     lives_free(fname);
503     return FALSE;
504   }
505 
506   mainw->current_file = new_file;
507   cfile->clip_type = CLIP_TYPE_VIDEODEV;
508 
509   d_print(""); ///< force switchtext
510 
511   g_print("checking formats for %s\n", fname);
512 
513   if (!open_vdev_inner(&devices[devno])) {
514     d_print(_("Unable to open device %s\n"), fname);
515     lives_free(fname);
516     close_current_file(old_file);
517     return FALSE;
518   }
519 
520   if (cfile->interlace != LIVES_INTERLACE_NONE && prefs->auto_deint) cfile->deinterlace = TRUE; ///< auto deinterlace
521   if (!cfile->deinterlace) cfile->deinterlace = mainw->open_deint; ///< user can also force deinterlacing
522 
523   cfile->start = cfile->end = cfile->frames = 1;
524   cfile->is_loaded = TRUE;
525   add_to_clipmenu();
526 
527   lives_snprintf(cfile->type, 40, "%s", fname);
528 
529   d_print(_("Opened device %s\n"), devices[devno].identifier);
530 
531   switch_clip(0, new_file, TRUE);
532 
533   lives_free(fname);
534 
535   return TRUE;
536 }
537 
538 #endif
539 
540