LiVES 3.2.0
videodev.c
Go to the documentation of this file.
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
18static 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);
37 sched_yield();
38 } while (lives_alarm_check(alarm_handle) > 0);
39
40 return FALSE;
41}
42
43
44static 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);
55 sched_yield();
56 } while (lives_alarm_check(alarm_handle) > 0);
57 lives_alarm_clear(alarm_handle);
58
59 return FALSE;
60}
61
62
63static 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
81boolean 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
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
164static 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
295
296static 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,
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
409void 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
419boolean 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
441
442 status = unicap_reenumerate_devices(&dev_count);
443
444 if (dev_count == 0) {
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) {
466 return FALSE;
467 }
468
469 mainw->fx1_val = 0;
471 card_dialog = create_combo_dialog(1, (livespointer)devlist);
472 response = lives_dialog_run(LIVES_DIALOG(card_dialog));
473 lives_list_free(devlist);
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("");
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;
521 if (!cfile->deinterlace) cfile->deinterlace = mainw->open_deint;
522
523 cfile->start = cfile->end = cfile->frames = 1;
524 cfile->is_loaded = TRUE;
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
void switch_clip(int type, int newclip, boolean force)
Definition: callbacks.c:6900
LIVES_GLOBAL_INLINE boolean weed_palette_is_alpha(int pal)
Definition: colourspace.c:1427
LIVES_GLOBAL_INLINE int weed_palette_get_bits_per_macropixel(int pal)
Definition: colourspace.c:1411
LIVES_GLOBAL_INLINE int weed_palette_get_nplanes(int pal)
Definition: colourspace.c:1417
LIVES_GLOBAL_INLINE boolean weed_palette_is_yuv(int pal)
Definition: colourspace.c:1457
boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig)
creates pixel data for layer
Definition: colourspace.c:9058
boolean weed_palette_is_lower_quality(int p1, int p2)
Definition: colourspace.c:2143
LIVES_GLOBAL_INLINE int weed_palette_get_pixels_per_macropixel(int pal)
Definition: colourspace.c:1403
LIVES_GLOBAL_INLINE boolean weed_palette_is_rgb(int pal)
Definition: colourspace.c:1448
void pixel_data_planar_from_membuf(void **pixel_data, void *data, size_t size, int palette, boolean contig)
Definition: colourspace.c:2236
#define WEED_LEAF_HOST_PIXEL_DATA_CONTIGUOUS
Definition: colourspace.h:20
weed_plant_t weed_layer_t
Definition: colourspace.h:71
LIVES_GLOBAL_INLINE void do_locked_in_vdevs_error(void)
Definition: dialogs.c:4404
LIVES_GLOBAL_INLINE void do_no_in_vdevs_error(void)
Definition: dialogs.c:4399
void add_to_clipmenu(void)
Definition: gui.c:4512
LiVESWidget * create_combo_dialog(int type, LiVESList *list)
Definition: interface.c:3088
error("LSD_RANDFUNC(ptr, size) must be defined")
#define lives_free
Definition: machinestate.h:52
#define lives_malloc
Definition: machinestate.h:46
#define lives_memcpy
Definition: machinestate.h:55
_palette * palette
interface colour settings
Definition: main.c:101
mainwindow * mainw
Definition: main.c:103
void close_current_file(int file_to_switch_to)
close current file, and try to switch to file_to_switch_to
Definition: main.c:9373
#define LIVES_IS_PLAYING
Definition: main.h:840
boolean lives_alarm_clear(lives_alarm_t alarm_handle)
Definition: utils.c:1732
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821
lives_alarm_t lives_alarm_set(ticks_t ticks)
set alarm for now + delta ticks (10 nanosec) param ticks (10 nanoseconds) is the offset when we want ...
Definition: utils.c:1643
#define LIVES_EXT_SRC_DEVICE
Definition: main.h:1048
#define cfile
Definition: main.h:1833
@ LIVES_INTERLACE_NONE
Definition: main.h:791
void d_print(const char *fmt,...)
Definition: utils.c:2542
#define LIVES_ERROR(x)
Definition: main.h:1870
@ CLIP_TYPE_VIDEODEV
frames from video device
Definition: main.h:771
ticks_t lives_alarm_check(lives_alarm_t alarm_handle)
Definition: utils.c:1687
#define LIVES_INFO(x)
Definition: main.h:1854
#define TICKS_PER_SECOND_DBL
actually microseconds / 100.
Definition: mainwindow.h:37
#define DEF_GEN_HEIGHT
Definition: mainwindow.h:150
#define DEF_GEN_WIDTH
Definition: mainwindow.h:149
int lives_alarm_t
Definition: mainwindow.h:696
_prefs * prefs
Definition: preferences.h:847
boolean auto_deint
Definition: preferences.h:302
int sleep_time
Definition: preferences.h:176
corresponds to one clip in the GUI
Definition: main.h:877
void * ext_src
points to opaque source for non-disk types
Definition: main.h:1040
int vsize
frame height (vertical) in pixels
Definition: main.h:897
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
boolean open_deint
Definition: mainwindow.h:907
int current_file
Definition: mainwindow.h:727
int blend_file
background clip details
Definition: mainwindow.h:976
double fx1_val
Definition: mainwindow.h:1049
int first_free_file
Definition: mainwindow.h:728
int playing_file
which number file we are playing (or -1) [generally mainw->current_file]
Definition: mainwindow.h:943
#define _(String)
Definition: support.h:44
#define TRUE
Definition: videoplugin.h:59
#define FALSE
Definition: videoplugin.h:60
const char * weed_palette_get_name(int pal)
WIDGET_HELPER_GLOBAL_INLINE LiVESResponseType lives_dialog_run(LiVESDialog *dialog)
LIVES_GLOBAL_INLINE boolean lives_widget_destroy(LiVESWidget *widget)
boolean lives_widget_context_update(void)