LiVES  3.2.0
stream.c
Go to the documentation of this file.
1 // stream.c
2 // LiVES
3 // (c) G. Finch 2008 - 2018 <salsaman+lives@gmail.com>
4 // released under the GNU GPL 3 or later
5 // see file ../COPYING for licensing details
6 
7 // TODO - implement multicast streaming
8 
9 #include "main.h"
10 #include "stream.h"
11 #include "htmsocket.h"
12 #include "interface.h"
13 #include "effects-weed.h"
14 
15 #define L2L_PACKET_LEN 1024
16 
17 static char pckbuf[L2L_PACKET_LEN * 2];
18 static int pckoffs = 0;
19 static size_t pcksize = 0;
20 
21 static boolean has_last_delta_ticks;
22 static char *hdr = NULL;
23 static boolean fps_can_change;
24 
25 LIVES_INLINE int64_t abs64(int64_t a) {
26  return ((a > 0) ? a : -a);
27 }
28 
29 //#define USE_STRMBUF
30 #ifdef USE_STRMBUF
31 
32 #define STREAM_BUF_SIZE 1024*1024*128 // allow 8MB buffer size; actually we use twice this much: - TODO - make pref
33 static volatile boolean buffering;
34 
35 void *streambuf(void *arg) {
36  // read bytes from udp port and load into ringbuffer
37  lives_vstream_t *lstream = (lives_vstream_t *)arg;
38 
39  ssize_t res;
40  size_t btowrite;
41  size_t tmpbufoffs;
42 
43  uint8_t tmpbuf[STREAM_BUF_SIZE];
44 
45  lstream->bufoffs = 0;
46 
47  while (buffering) {
48  // keep calling lives_stream_in until main thread sets buffering to FALSE
49  res = lives_stream_in(lstream->handle, STREAM_BUF_SIZE, tmpbuf, 0);
50  if (res > 0) {
51  // got packet of size res
52  tmpbufoffs = 0;
53  btowrite = res;
54  if (lstream->bufoffs + btowrite > STREAM_BUF_SIZE) {
55  btowrite = STREAM_BUF_SIZE - lstream->bufoffs;
56  lives_memcpy(lstream->buffer + lstream->bufoffs, tmpbuf, btowrite);
57  tmpbufoffs += btowrite;
58  res -= btowrite;
59  lstream->bufoffs = 0;
60  }
61  lives_memcpy(lstream->buffer + lstream->bufoffs, tmpbuf + tmpbufoffs, res);
62  lstream->bufoffs += res;
63  lstream->reading = TRUE;
64  }
65  //else lstream->reading=FALSE;
66  }
67  pthread_exit(NULL);
68  return NULL;
69 }
70 
71 
72 static size_t l2l_rcv_packet(lives_vstream_t *lstream, size_t buflen, void *buf) {
73  // take a packet from our stream buffer
74  static size_t bufoffs = 0;
75  size_t btoread = 0;
76  size_t end = bufoffs + buflen;
77 
78  while ((end < STREAM_BUF_SIZE && lstream->bufoffs >= bufoffs && lstream->bufoffs <= end) || (end >= STREAM_BUF_SIZE &&
79  (lstream->bufoffs >= bufoffs ||
80  lstream->bufoffs <= (end - STREAM_BUF_SIZE)))) {
81  lives_usleep(1000);
82  }
83 
84  while (1) {
85  // loop until we read the packet, or the user cancels
86  if (lstream->reading) {
87  if (buflen + bufoffs > STREAM_BUF_SIZE) {
88  btoread = STREAM_BUF_SIZE - bufoffs;
89  lives_memcpy(buf, (void *)((uint8_t *)lstream->buffer + bufoffs), btoread);
90  bufoffs = 0;
91  buflen -= btoread;
92  buf = (void *)((uint8_t *)buf + btoread);
93  }
94  lives_memcpy(buf, (void *)((uint8_t *)lstream->buffer + bufoffs), buflen);
95  bufoffs += buflen;
96  return buflen + btoread;
97  } else {
98  weed_plant_t *frame_layer = mainw->frame_layer;
99  mainw->frame_layer = NULL;
101  mainw->frame_layer = frame_layer;
103  if (mainw->cancelled) return buflen + btoread;
104  lives_usleep(prefs->sleep_time);
105  }
106  }
107 }
108 
109 
110 static boolean lives_stream_in_chunks(lives_vstream_t *lstream, size_t buflen, uint8_t *buf, int xx) {
111  // read first from pckbuf, then from streambuf
112  size_t copied = 0;
113  if (pckoffs < L2L_PACKET_LEN) {
114  // use up our pckbuf
115  copied = L2L_PACKET_LEN - pckoffs;
116  if (copied > buflen) copied = buflen;
117 
118  lives_memcpy(buf, pckbuf, copied);
119 
120  buflen -= copied;
121  pckoffs += copied;
122  }
123  if (buflen > 0) l2l_rcv_packet(lstream, buflen, (void *)((uint8_t *)buf + copied));
124  return TRUE;
125 }
126 #else
127 
128 
129 static size_t l2l_rcv_packet(lives_vstream_t *lstream, size_t buflen, void *buf) {
130  int ret;
131  do {
132  ret = lives_stream_in(lstream->handle, buflen, buf, 0);
133  if (ret == -1) {
134  weed_plant_t *frame_layer = mainw->frame_layer;
135  mainw->frame_layer = NULL;
137  mainw->frame_layer = frame_layer;
139  if (mainw->cancelled) {
140  return -1;
141  }
142  lives_usleep(prefs->sleep_time);
143  }
144  } while (ret == -1);
145  return ret;
146 }
147 
148 
149 static boolean lives_stream_in_chunks(lives_vstream_t *lstream, size_t buflen, uint8_t *buf, int bfsize) {
150  // return FALSE if we could not set socket buffer size
151 
152  size_t copied;
153 
154  if (pckoffs < pcksize) {
155  // use up our pckbuf
156  copied = pcksize - pckoffs;
157  if (copied > buflen) copied = buflen;
158 
159  lives_memcpy(buf, pckbuf, copied);
160 
161  buflen -= copied;
162  pckoffs += copied;
163  buf += copied;
164  }
165  while (buflen > 0) {
166  // read in the rest
167  do {
168  copied = lives_stream_in(lstream->handle, buflen, buf, bfsize);
169  if (copied == -2) return FALSE;
170  if (copied == -1) {
171  weed_plant_t *frame_layer = mainw->frame_layer;
172  mainw->frame_layer = NULL;
174  mainw->frame_layer = frame_layer;
176  if (mainw->cancelled) return TRUE;
177  lives_usleep(prefs->sleep_time);
178  }
179  } while (copied == -1);
180  buflen -= copied;
181  buf += copied;
182  }
183  return TRUE;
184 }
185 
186 #endif
187 
188 static void l2l_get_packet_sync(lives_vstream_t *lstream) {
189  boolean sync = FALSE;
190 
191  if (pckoffs == pcksize) {
192  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
193  pckoffs = 0;
194  if (mainw->cancelled) return;
195  }
196 
197  while (!sync) {
198  while (strncmp(pckbuf + pckoffs, "P", 1)) {
199  if (++pckoffs == pcksize) {
200  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
201  pckoffs = 0;
202  if (mainw->cancelled) return;
203  }
204  }
205  if (++pckoffs == pcksize) {
206  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
207  pckoffs = 0;
208  if (mainw->cancelled) return;
209  }
210  if (strncmp(pckbuf + pckoffs, "A", 1)) continue;
211  if (++pckoffs == pcksize) {
212  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
213  pckoffs = 0;
214  if (mainw->cancelled) return;
215  }
216  if (strncmp(pckbuf + pckoffs, "C", 1)) continue;
217  if (++pckoffs == pcksize) {
218  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
219  pckoffs = 0;
220  if (mainw->cancelled) return;
221  }
222  if (strncmp(pckbuf + pckoffs, "K", 1)) continue;
223  if (++pckoffs == pcksize) {
224  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
225  pckoffs = 0;
226  if (mainw->cancelled) return;
227  }
228  if (strncmp(pckbuf + pckoffs, "E", 1)) continue;
229  if (++pckoffs == pcksize) {
230  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
231  pckoffs = 0;
232  if (mainw->cancelled) return;
233  }
234  if (strncmp(pckbuf + pckoffs, "T", 1)) continue;
235  if (++pckoffs == pcksize) {
236  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
237  pckoffs = 0;
238  if (mainw->cancelled) return;
239  }
240  if (strncmp(pckbuf + pckoffs, " ", 1)) continue;
241 
242  sync = TRUE;
243  }
244  pckoffs++;
245 }
246 
247 
248 static char *l2l_get_packet_header(lives_vstream_t *lstream) {
249  size_t hdrsize = 0, csize;
250 
251  char hdr_buf[1024];
252 
253  boolean sync = FALSE;
254 
255  if (pckoffs == pcksize) {
256  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
257  if (mainw->cancelled) return NULL;
258  }
259 
260  while (!sync) {
261  if (pckoffs == pcksize) {
262  if (pcksize > L2L_PACKET_LEN) {
263  csize = pcksize;
264  pcksize = (pcksize + 1) >> 1;
265  csize -= pcksize;
266  lives_memcpy(pckbuf, pckbuf + pcksize, csize);
267  pckoffs -= pcksize;
268  pcksize = csize;
269  }
270  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
271  if (mainw->cancelled) return NULL;
272  }
273 
274  while (strncmp(pckbuf + pckoffs, "D", 1)) {
275  hdr_buf[hdrsize++] = pckbuf[pckoffs];
276  if (hdrsize > 1000) {
277  if (pckoffs >= L2L_PACKET_LEN) {
278  lives_memcpy(pckbuf, pckbuf + L2L_PACKET_LEN, L2L_PACKET_LEN);
279  pckoffs -= L2L_PACKET_LEN;
280  }
281  return NULL;
282  }
283  if (++pckoffs == pcksize) {
284  if (pcksize > L2L_PACKET_LEN) {
285  csize = pcksize;
286  pcksize = (pcksize + 1) >> 1;
287  csize -= pcksize;
288  lives_memcpy(pckbuf, pckbuf + pcksize, csize);
289  pckoffs -= pcksize;
290  pcksize = csize;
291  }
292  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
293  if (mainw->cancelled) return NULL;
294  }
295  }
296 
297  if (++pckoffs == pcksize) {
298  if (pcksize > L2L_PACKET_LEN) {
299  csize = pcksize;
300  pcksize = (pcksize + 1) >> 1;
301  csize -= pcksize;
302  lives_memcpy(pckbuf, pckbuf + pcksize, csize);
303  pckoffs -= pcksize;
304  pcksize = csize;
305  }
306  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
307  if (mainw->cancelled) return NULL;
308  }
309 
310  if (strncmp(pckbuf + pckoffs, "A", 1)) {
311  lives_memcpy(&hdr_buf[hdrsize], pckbuf + pckoffs - 1, 2);
312  hdrsize += 2;
313  continue;
314  }
315 
316  if (++pckoffs == pcksize) {
317  if (pcksize > L2L_PACKET_LEN) {
318  csize = pcksize;
319  pcksize = (pcksize + 1) >> 1;
320  csize -= pcksize;
321  lives_memcpy(pckbuf, pckbuf + pcksize, csize);
322  pckoffs -= pcksize;
323  pcksize = csize;
324  }
325  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
326  if (mainw->cancelled) return NULL;
327  }
328 
329  if (strncmp(pckbuf + pckoffs, "T", 1)) {
330  lives_memcpy(&hdr_buf[hdrsize], pckbuf + pckoffs - 2, 3);
331  hdrsize += 3;
332  continue;
333  }
334 
335  if (++pckoffs == pcksize) {
336  if (pcksize > L2L_PACKET_LEN) {
337  csize = pcksize;
338  pcksize = (pcksize + 1) >> 1;
339  csize -= pcksize;
340  lives_memcpy(pckbuf, pckbuf + pcksize, csize);
341  pckoffs -= pcksize;
342  pcksize = csize;
343  }
344  pcksize += l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf + pckoffs);
345  if (mainw->cancelled) return NULL;
346  }
347 
348  if (strncmp(pckbuf + pckoffs, "A", 1)) {
349  lives_memcpy(&hdr_buf[hdrsize], pckbuf + pckoffs - 3, 4);
350  hdrsize += 4;
351  continue;
352  }
353  sync = TRUE;
354  }
355 
356  if (pckoffs >= L2L_PACKET_LEN) {
357  lives_memcpy(pckbuf, pckbuf + L2L_PACKET_LEN, L2L_PACKET_LEN);
358  pckoffs -= L2L_PACKET_LEN;
359  pcksize -= L2L_PACKET_LEN;
360  }
361 
362  hdr_buf[hdrsize] = 0;
363 
364  pckoffs++;
365 
366  return lives_strdup(hdr_buf);
367 }
368 
369 
370 static boolean l2l_parse_packet_header(lives_vstream_t *lstream, int strtype, int strid) {
371  char **array = lives_strsplit(hdr, " ", -1);
372  int pid = -1, ptype = -1;
373 
374  if (!hdr || !array || !array[0] || !array[1] || !array[2] || !array[3]) {
375  if (array) lives_strfreev(array);
376  return FALSE;
377  }
378 
379  ptype = atoi(array[0]);
380  pid = atoi(array[1]);
381 
382  if (pid != strid || ptype != strtype) {
383  // wrong stream id, or not video
384  if (array) lives_strfreev(array);
385  return FALSE;
386  }
387 
388  lstream->flags = atoi(array[2]);
389  lstream->dsize = atoi(array[3]);
390 
391  if (!(lstream->flags & LIVES_VSTREAM_FLAGS_IS_CONTINUATION)) {
392  if (capable->cpu_bits == 32) {
393  lstream->timecode = strtoll(array[4], NULL, 10);
394  } else {
395  lstream->timecode = strtol(array[4], NULL, 10);
396  }
397 
398  lstream->hsize = atoi(array[5]);
399  lstream->vsize = atoi(array[6]);
400  lstream->fps = lives_strtod(array[7], NULL);
401  lstream->palette = atoi(array[8]);
402  lstream->YUV_sampling = atoi(array[9]);
403  lstream->YUV_clamping = atoi(array[10]);
404  lstream->YUV_subspace = atoi(array[11]);
405  lstream->compression_type = atoi(array[12]);
406  }
407 
408  lives_strfreev(array);
409  lstream->data_ready = TRUE;
410 
411  return TRUE;
412 }
413 
414 
415 void lives2lives_read_stream(const char *host, int port) {
417 
418  char *tmp;
419  char *hostname;
420 
421 #ifdef USE_STRMBUF
422  pthread_t stthread;
423  pthread_attr_t pattr;
424 #endif
425 
426  boolean done = FALSE;
427 
428  int old_file = mainw->current_file, new_file;
429 
431 
432  lstream->handle = OpenHTMSocket(host, port, FALSE);
433  if (!lstream->handle) {
435  do_error_dialog(_("LiVES to LiVES stream error: Could not open port !\n"));
438  return;
439  }
440 
441  d_print(_("Waiting for LiVES stream on port %d..."), port);
442 
444  do_threaded_dialog(_("\nWaiting for stream"), TRUE);
445 
446 #ifdef USE_STRMBUF
447  buffering = TRUE;
448  lstream->reading = FALSE;
449 
450  pthread_attr_init(&pattr);
451  if (pthread_attr_setstacksize(&pattr, STREAM_BUF_SIZE * 4)) {
453  CloseHTMSocket(lstream->handle);
454  lives_free(lstream);
455  d_print_failed();
456  do_error_dialog(_("LiVES to LiVES stream error: Could not set buffer size !\n"));
458  return;
459  }
460  lstream->buffer = lives_malloc(STREAM_BUF_SIZE);
461  pthread_create(&stthread, &pattr, streambuf, (void *)lstream);
462  pthread_attr_destroy(&pattr);
463 #endif
464 
465  pcksize = l2l_rcv_packet(lstream, L2L_PACKET_LEN, pckbuf);
466  pckoffs = 0;
467  if (mainw->cancelled) {
469 #ifdef USE_STRMBUF
470  buffering = FALSE;
471  pthread_join(stthread, NULL);
472 #endif
473  CloseHTMSocket(lstream->handle);
474 #ifdef USE_STRMBUF
475  lives_free(lstream->buffer);
476 #endif
477  lives_free(lstream);
480  return;
481  }
482 
483  while (!done) {
484  do {
485  // get video stream 0 PACKET
486  l2l_get_packet_sync(lstream);
487  if (mainw->cancelled) {
489 #ifdef USE_STRMBUF
490  buffering = FALSE;
491  pthread_join(stthread, NULL);
492 #endif
493  CloseHTMSocket(lstream->handle);
494 #ifdef USE_STRMBUF
495  lives_free(lstream->buffer);
496 #endif
497  lives_free(lstream);
500  return;
501  }
502  // get packet header
503  hdr = l2l_get_packet_header(lstream);
504  if (mainw->cancelled) {
506 #ifdef USE_STRMBUF
507  buffering = FALSE;
508  pthread_join(stthread, NULL);
509 #endif
510  CloseHTMSocket(lstream->handle);
511 #ifdef USE_STRMBUF
512  lives_free(lstream->buffer);
513 #endif
514  lives_free(lstream);
517  return;
518  }
519  } while (!hdr);
520  // parse packet header
521  done = l2l_parse_packet_header(lstream, LIVES_STREAM_TYPE_VIDEO, 0);
522  if (lstream->flags & LIVES_VSTREAM_FLAGS_IS_CONTINUATION) done = FALSE;
523  if (!done) {
524  // wrong packet type or id, or a continuation packet
525  uint8_t *tmpbuf = (uint8_t *)lives_malloc(lstream->dsize);
526  lives_stream_in_chunks(lstream, lstream->dsize, tmpbuf, lstream->dsize * 4);
527  // throw this packet away
528  lives_printerr("unrecognised packet in stream - dropping it.\n");
529  lives_free(tmpbuf);
530  if (mainw->cancelled) {
532 #ifdef USE_STRMBUF
533  buffering = FALSE;
534  pthread_join(stthread, NULL);
535 #endif
536  CloseHTMSocket(lstream->handle);
537 #ifdef USE_STRMBUF
538  lives_free(lstream->buffer);
539 #endif
540  lives_free(lstream);
543  return;
544  }
545  }
546  lives_free(hdr);
547  }
548 
550 
551  if (mainw->fixed_fpsd <= 0.) fps_can_change = TRUE;
552  else fps_can_change = FALSE;
553 
554  if (mainw->fixed_fpsd > 0. && (cfile->fps != mainw->fixed_fpsd)) {
556  do_error_dialog(_("\n\nUnable to open stream, framerate does not match fixed rate.\n"));
558 #ifdef USE_STRMBUF
559  buffering = FALSE;
560  pthread_join(stthread, NULL);
561 #endif
562  CloseHTMSocket(lstream->handle);
563 #ifdef USE_STRMBUF
564  lives_free(lstream->buffer);
565 #endif
566  lives_free(lstream);
567  d_print_failed();
569  return;
570  }
571 
572  // now we should have lstream details
573 
574  //
575  new_file = mainw->first_free_file;
576  if (!get_new_handle(new_file, "LiVES to LiVES stream")) {
577  mainw->error = TRUE;
578 #ifdef USE_STRMBUF
579  buffering = FALSE;
580  pthread_join(stthread, NULL);
581 #endif
582  CloseHTMSocket(lstream->handle);
583 #ifdef USE_STRMBUF
584  lives_free(lstream->buffer);
585 #endif
586  lives_free(lstream);
587  d_print_failed();
589  return;
590  }
591 
592  mainw->current_file = new_file;
593  cfile->clip_type = CLIP_TYPE_LIVES2LIVES;
594 
595  cfile->fps = lstream->fps;
596  cfile->hsize = lstream->hsize;
597  cfile->vsize = lstream->vsize;
598 
599  cfile->ext_src = lstream;
600  cfile->ext_src_type = LIVES_EXT_SRC_STREAM;
601 
602  switch_to_file((mainw->current_file = old_file), new_file);
603  set_main_title(cfile->file_name, 0);
604  add_to_clipmenu();
605 
606  cfile->achans = 0;
607  cfile->asampsize = 0;
608 
609  // open as a clip with 1 frame
610  cfile->start = cfile->end = cfile->frames = 1;
611  cfile->arps = cfile->arate = 0;
612  mainw->fixed_fpsd = cfile->pb_fps = cfile->fps;
613 
614  cfile->opening = FALSE;
615  mainw->proc_ptr = NULL;
616 
617  cfile->changed = FALSE;
618 
619  // allow clip switching
620  cfile->is_loaded = TRUE;
621 
622  d_print("\n");
623 
624  lives_snprintf(cfile->type, 40, "LiVES to LiVES stream in");
625 
626  if (!strcmp(host, "INADDR_ANY")) hostname = (_("any host"));
627  else hostname = (_("host %d"));
628 
629  d_print(_("Opened LiVES to LiVES stream from %s on port %d"), hostname, port);
630  lives_free(hostname);
631  d_print(_(" size=%dx%d bpp=%d fps=%.3f\nAudio: "), cfile->hsize, cfile->vsize, cfile->bpp, cfile->fps);
632 
633  if (cfile->achans == 0) {
634  d_print(_("none\n"));
635  } else {
636  d_print(P_("%d Hz %d channel %d bps\n", "%d Hz %d channels %d bps\n", cfile->achans), cfile->arate, cfile->achans,
637  cfile->asampsize);
638  }
639 
640  d_print(_("Syncing to external framerate of %s frames per second.\n"), (tmp = remove_trailing_zeroes(mainw->fixed_fpsd)));
641  lives_free(tmp);
642 
643  has_last_delta_ticks = FALSE;
644 
645  // if not playing, start playing
646  if (!LIVES_IS_PLAYING) {
648  return;
649  }
650  // TODO - else...
651 
652  if (mainw->current_file != old_file &&
653  mainw->current_file != new_file) old_file = mainw->current_file; // we could have rendered to a new file
654 
655  mainw->fixed_fpsd = -1.;
656  d_print(_("Sync lock off.\n"));
657  mainw->current_file = new_file;
658 #ifdef USE_STRMBUF
659  buffering = FALSE;
660  pthread_join(stthread, NULL);
661 #endif
662  CloseHTMSocket(lstream->handle);
663 #ifdef USE_STRMBUF
664  lives_free(lstream->buffer);
665 #endif
666  lives_free(cfile->ext_src);
667  cfile->ext_src = NULL;
668  cfile->ext_src_type = LIVES_EXT_SRC_NONE;
669 
670  close_current_file(old_file);
672 }
673 
674 
676  static ticks_t last_delta_ticks = 0;
677  ticks_t currticks;
678 
679  void **pixel_data;
680 
681  size_t framedataread = 0;
682  size_t target_size;
683 
684  boolean timeout = FALSE; // TODO
685  boolean done;
686 
687  int myflags = 0, width = 0, height = 0;
688 
689  while (!timeout) {
690  // loop until we read all frame data, or we get a new frame
691  done = FALSE;
692  if (!lstream->data_ready) {
693  while (!done) {
694  // get video stream 0 PACKET
695  do {
696  l2l_get_packet_sync(lstream);
697  if (mainw->cancelled) return;
698  // get packet header
699  hdr = l2l_get_packet_header(lstream);
700  if (mainw->cancelled) return;
701  } while (!hdr && mainw->cancelled == CANCEL_NONE);
702  if (mainw->cancelled) {
703  lives_free(hdr);
704  hdr = NULL;
705  return;
706  }
707  // parse packet header
708  done = l2l_parse_packet_header(lstream, LIVES_STREAM_TYPE_VIDEO, 0);
710  done = FALSE;
712  // we missed some continuation packets, just return what we have
713  lstream->data_ready = TRUE;
714  lives_free(hdr);
715  hdr = NULL;
716  return;
717  }
718 
719  if (!done) {
720  // wrong packet type or id, or a continuation of previous frame
721  uint8_t *tmpbuf = (uint8_t *)lives_malloc(lstream->dsize);
722  lives_stream_in_chunks(lstream, lstream->dsize, tmpbuf, lstream->dsize * 4);
723  // throw this packet away
724  lives_printerr("unrecognised packet in stream - dropping it.\n");
725  lives_free(tmpbuf);
726  if (mainw->cancelled) {
727  lives_free(hdr);
728  hdr = NULL;
729  return;
730  }
731  }
732  lives_free(hdr);
733  hdr = NULL;
734 
735  if (lstream->fps != mainw->fixed_fpsd && fps_can_change) {
736  char *tmp;
737  d_print(_("Detected new framerate for stream:\n"));
738  mainw->files[clip]->fps = mainw->fixed_fpsd = lstream->fps;
739  d_print(_("Syncing to external framerate of %s frames per second.\n"),
741  lives_free(tmp);
742  has_last_delta_ticks = FALSE;
743  if (clip == mainw->current_file) set_main_title(cfile->file_name, 0);
744  }
745 
746 #define DROP_AGING_FRAMES
747 #ifdef DROP_AGING_FRAMES
748  // this seems to help smoothing when recording, however I have only tested it on one machine
749  // where frames were being generated and streamed and then received
750  // - needs testing in other situations
751  currticks = lives_get_current_ticks();
752 
753  if (mainw->record && !mainw->record_paused) {
754  if (has_last_delta_ticks && (abs64(currticks - lstream->timecode)) < last_delta_ticks) {
755  // drop this frame
756  uint8_t *tmpbuf = (uint8_t *)lives_malloc(lstream->dsize);
757  lives_stream_in_chunks(lstream, lstream->dsize, tmpbuf, lstream->dsize * 4);
758  // throw this packet away
759 #ifdef DEBUG_STREAM_AGING
760  lives_printerr("packet too early (!) - dropping it.\n");
761 #endif
762  lives_free(tmpbuf);
763  done = FALSE;
764  if (mainw->cancelled) {
765  lives_free(hdr);
766  hdr = NULL;
767  return;
768  }
769  }
770  }
771  last_delta_ticks = ((ticks_t)(last_delta_ticks >> 1) + (ticks_t)((abs64(currticks - lstream->timecode)) >> 1));
772 #endif
773  }
774  }
775 
776  if (!has_last_delta_ticks) {
777  last_delta_ticks = abs64(mainw->currticks - lstream->timecode);
778  }
779  has_last_delta_ticks = TRUE;
780 
781  lstream->data_ready = FALSE;
782 
783  width = mainw->files[clip]->hsize;
784  height = mainw->files[clip]->vsize;
785 
786  if (lstream->hsize != width || lstream->vsize != height) {
787  // frame size changed...
788  d_print(_("Detected frame size change to %d x %d\n"), lstream->hsize, lstream->vsize);
789 
790  mainw->files[clip]->hsize = lstream->hsize;
791  mainw->files[clip]->vsize = lstream->vsize;
792 
793  if (clip == mainw->current_file) {
794  set_main_title(cfile->file_name, 0);
795  }
797  }
798 
799  width = height = 0;
800 
801  if (weed_plant_has_leaf(layer, WEED_LEAF_HEIGHT)) height = weed_get_int_value(layer, WEED_LEAF_HEIGHT, NULL);
802  if (weed_plant_has_leaf(layer, WEED_LEAF_WIDTH)) width = weed_get_int_value(layer, WEED_LEAF_WIDTH, NULL);
803 
804  if (lstream->hsize != width || lstream->vsize != height) {
806  }
807 
808  if (!weed_plant_has_leaf(layer, WEED_LEAF_PIXEL_DATA) || !weed_get_voidptr_value(layer, WEED_LEAF_PIXEL_DATA, NULL)) {
809  weed_set_int_value(layer, WEED_LEAF_WIDTH, lstream->hsize);
810  weed_set_int_value(layer, WEED_LEAF_HEIGHT, lstream->vsize);
811  weed_set_int_value(layer, WEED_LEAF_CURRENT_PALETTE, lstream->palette);
812  weed_set_int_value(layer, WEED_LEAF_YUV_CLAMPING, lstream->YUV_clamping);
814  }
815 
816  pixel_data = weed_get_voidptr_array(layer, WEED_LEAF_PIXEL_DATA, NULL);
817 
818  switch (lstream->palette) {
819  case WEED_PALETTE_RGB24:
820  target_size = lstream->hsize * lstream->vsize * 3 - framedataread;
821 #ifdef USE_STRMBUF
822  if (target_size > lstream->dsize) target_size = lstream->dsize;
823  lives_stream_in_chunks(lstream, target_size, (uint8_t *)pixel_data[0] + framedataread, 0);
824  lstream->dsize -= target_size;
825  framedataread += target_size;
826 #else
827  if (target_size >= lstream->dsize) {
828  if (!lives_stream_in_chunks(lstream, target_size, (uint8_t *)pixel_data[0] + framedataread, lstream->dsize * 12)) {
829  do_rmem_max_error(lstream->dsize * 12);
831  }
832  if (mainw->cancelled) {
833  lives_free(pixel_data);
834  return;
835  }
836  }
837 #endif
838  lives_free(pixel_data);
839  if (framedataread >= lstream->hsize * lstream->vsize * 3) {
840  return;
841  }
843  break;
844  case WEED_PALETTE_YUV420P:
845  // assume uncompressed, - TODO
846 
847  if (framedataread < lstream->hsize * lstream->vsize) {
848  target_size = lstream->hsize * lstream->vsize - framedataread;
849 #ifdef USE_STRMBUF
850  if (target_size > lstream->dsize) target_size = lstream->dsize;
851  lives_stream_in_chunks(lstream, target_size, (uint8_t *)pixel_data[0] + framedataread, 0);
852  lstream->dsize -= target_size;
853  framedataread += target_size;
854 #else
855  if (target_size >= lstream->dsize) {
856  // packet contains data for single plane
857  if (!lives_stream_in_chunks(lstream, lstream->dsize, (uint8_t *)pixel_data[0] + framedataread, lstream->dsize * 9)) {
858  do_rmem_max_error(lstream->dsize * 9);
860  }
861  if (mainw->cancelled) {
862  lives_free(pixel_data);
863  return;
864  }
865  } else {
866  // this packet contains data for multiple planes
867  uint8_t *fbuffer = (uint8_t *)lives_malloc(lstream->dsize);
868  size_t fbufoffs = 0;
869  size_t dsize = lstream->dsize;
870 
871  if (!lives_stream_in_chunks(lstream, lstream->dsize, fbuffer, lstream->dsize * 8)) {
872  do_rmem_max_error(lstream->dsize * 8);
874  }
875  if (mainw->cancelled) {
876  lives_free(pixel_data);
877  lives_free(fbuffer);
878  return;
879  }
880  lives_memcpy((uint8_t *)pixel_data[0] + framedataread, fbuffer, target_size);
881  dsize -= target_size;
882  fbufoffs += target_size;
883 
884  target_size = (lstream->hsize * lstream->vsize) >> 2;
885  if (target_size > dsize) target_size = dsize;
886 
887  if (target_size > 0) lives_memcpy((uint8_t *)pixel_data[1], fbuffer + fbufoffs, target_size);
888 
889  dsize -= target_size;
890  fbufoffs += target_size;
891 
892  target_size = (lstream->hsize * lstream->vsize) >> 2;
893  if (target_size > dsize) target_size = dsize;
894 
895  if (target_size > 0) lives_memcpy((uint8_t *)pixel_data[2], fbuffer + fbufoffs, target_size);
896 
897  lives_free(fbuffer);
898  }
899 #endif
900  }
901 #ifdef USE_STRMBUF
902  if (framedataread < (lstream->hsize * lstream->vsize * 5) >> 2) {
903  target_size = ((lstream->hsize * lstream->vsize * 5) >> 2) - framedataread;
904  if (target_size > lstream->dsize) target_size = lstream->dsize;
905  lives_stream_in_chunks(lstream, target_size,
906  (uint8_t *)pixel_data[1] + framedataread - lstream->hsize * lstream->vsize, 0);
907  lstream->dsize -= target_size;
908  framedataread += target_size;
909 #else
910  else if (framedataread < (lstream->hsize * lstream->vsize * 5) >> 2) {
911  target_size = ((lstream->hsize * lstream->vsize * 5) >> 2) - framedataread;
912  if (target_size >= lstream->dsize) {
913  lives_stream_in_chunks(lstream, lstream->dsize,
914  ((uint8_t *)pixel_data[1] + framedataread - lstream->hsize * lstream->vsize), 0);
915  if (mainw->cancelled) {
916  lives_free(pixel_data);
917  return;
918  }
919  } else {
920  // this packet contains data for multiple planes
921  uint8_t *fbuffer = (uint8_t *)lives_malloc(lstream->dsize);
922  size_t fbufoffs = 0;
923  size_t dsize = lstream->dsize;
924 
925  lives_stream_in_chunks(lstream, lstream->dsize, fbuffer, 0);
926  if (mainw->cancelled) {
927  lives_free(pixel_data);
928  lives_free(fbuffer);
929  return;
930  }
931  lives_memcpy((uint8_t *)pixel_data[1] + framedataread - lstream->hsize * lstream->vsize, fbuffer, target_size);
932 
933  dsize -= target_size;
934  fbufoffs += target_size;
935 
936  target_size = (lstream->hsize * lstream->vsize) >> 2;
937  if (target_size > dsize) target_size = dsize;
938 
939  if (target_size > 0) lives_memcpy((uint8_t *)pixel_data[2], fbuffer + fbufoffs, target_size);
940 
941  lives_free(fbuffer);
942  }
943 #endif
944  }
945 #ifdef USE_STRMBUF
946  if (framedataread < (lstream->hsize * lstream->vsize * 6) >> 2) {
947  target_size = ((lstream->hsize * lstream->vsize) >> 2) - framedataread + ((lstream->hsize * lstream->vsize * 5) >> 2);
948  if (target_size > lstream->dsize) target_size = lstream->dsize;
949  lives_stream_in_chunks(lstream, target_size, (uint8_t *)pixel_data[2] + framedataread -
950  ((lstream->hsize * lstream->vsize * 5) >> 2), 0);
951  lstream->dsize -= target_size;
952  framedataread += target_size;
953  }
954 #else
955  else {
956  target_size = ((lstream->hsize * lstream->vsize * 3) >> 1) - framedataread;
957  if (target_size >= lstream->dsize) target_size = lstream->dsize;
958  lives_stream_in_chunks(lstream, target_size,
959  ((uint8_t *)pixel_data[2] + framedataread - ((lstream->hsize * lstream->vsize * 5) >> 2)), 0);
960  if (mainw->cancelled) {
961  lives_free(pixel_data);
962  return;
963  }
964  }
965  framedataread += lstream->dsize;
966 #endif
967  lives_free(pixel_data);
968  if (framedataread >= (lstream->hsize * lstream->vsize * 3) >> 1) {
969  return;
970  }
972  break;
973  }
974  }
975 }
976 
977 
979 
980 // gui bits
981 
982 void on_send_lives2lives_activate(LiVESMenuItem *menuitem, livespointer user_data) {
983  _vppaw *vppa;
984 
985  char *orig_name = lives_strdup(mainw->string_constants[LIVES_STRING_CONSTANT_NONE]);
986  char *tmp;
987 
988  int resp;
989 
990  if (mainw->vpp) {
991  lives_free(orig_name);
992  orig_name = lives_strdup(mainw->vpp->name);
993  }
994 
995  if (!mainw->vpp || strcmp(mainw->vpp->name, "lives2lives_stream")) {
996  lives_snprintf(future_prefs->vpp_name, 64, "lives2lives_stream");
997  }
998  vppa = on_vpp_advanced_clicked(NULL, LIVES_INT_TO_POINTER(LIVES_INTENTION_STREAM));
999  resp = lives_dialog_run(LIVES_DIALOG(vppa->dialog));
1000 
1001  if (vppa->rfx) {
1002  tmp = lives_build_filename(prefs->workdir, vppa->rfx->name, NULL);
1003  lives_rm(tmp);
1004  lives_free(tmp);
1005  }
1006 
1007  if (resp == LIVES_RESPONSE_CANCEL) {
1008  lives_free(orig_name);
1009  return;
1010  }
1011 
1012  set_vpp(FALSE);
1013 
1014  if (strcmp(orig_name, "lives2lives_stream")) {
1016  do_info_dialogf(_("\nLiVES will stream whenever it is in full screen/separate window mode.\n"
1017  "To reset this behaviour, go to Tools/Preferences/Playback,\nand set the playback "
1018  "plugin back to %s\n"),
1019  orig_name);
1021  }
1022  lives_free(orig_name);
1023 }
1024 
1025 
1026 void on_open_lives2lives_activate(LiVESMenuItem *menuitem, livespointer user_data) {
1027  lives_pandh_w *pandh = create_pandh_dialog(0);
1028 
1029  char *host = NULL;
1030 
1031  int port = 0;
1032  int response = lives_dialog_run(LIVES_DIALOG(pandh->dialog));
1033 
1034  if (response == LIVES_RESPONSE_OK) {
1035  if (!lives_toggle_button_get_active(LIVES_TOGGLE_BUTTON(pandh->rb_anyhost))) {
1036  host = lives_strdup_printf("%s.%s.%s.%s", lives_entry_get_text(LIVES_ENTRY(pandh->entry1)),
1037  lives_entry_get_text(LIVES_ENTRY(pandh->entry2)),
1038  lives_entry_get_text(LIVES_ENTRY(pandh->entry3)),
1039  lives_entry_get_text(LIVES_ENTRY(pandh->entry4)));
1040  } else host = lives_strdup("INADDR_ANY");
1041  port = lives_spin_button_get_value_as_int(LIVES_SPIN_BUTTON(pandh->port_spin));
1042  lives_widget_destroy(pandh->dialog);
1043  }
1044 
1045  lives_free(pandh);
1046 
1048 
1049  if (host) {
1050  // start receiving
1051  lives2lives_read_stream(host, port);
1052  lives_free(host);
1053  }
1054 }
1055 
1056 
1057 static void pandhw_anyhost_toggled(LiVESToggleButton *tbut, livespointer user_data) {
1058  lives_pandh_w *pandhw = (lives_pandh_w *)user_data;
1059 
1060  if (lives_toggle_button_get_active(tbut)) {
1065  } else {
1070  }
1071 }
1072 
1073 
1075  // type = 0 lives2lives stream input
1076 
1077  LiVESWidget *dialog_vbox;
1078  LiVESWidget *hbox;
1079  LiVESWidget *label;
1080 
1081  LiVESSList *radiobutton_group = NULL;
1082 
1083  lives_pandh_w *pandhw = (lives_pandh_w *)(lives_malloc(sizeof(lives_pandh_w)));
1084 
1085  char *tmp, *tmp2;
1086 
1087  pandhw->dialog = lives_standard_dialog_new(_("Receive LiVES Stream"), TRUE, -1, -1);
1088 
1089  dialog_vbox = lives_dialog_get_content_area(LIVES_DIALOG(pandhw->dialog));
1090 
1091  label = lives_standard_label_new(_("You can receive streams from another copy of LiVES."));
1092  lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1093 
1094  label = lives_standard_label_new(
1095  _("In the source copy of LiVES, you must select Advanced/Send stream to LiVES\n"
1096  "or select the lives2lives_stream playback plugin in Preferences."));
1097  lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1098 
1099  add_hsep_to_box(LIVES_BOX(dialog_vbox));
1100 
1101  label = lives_standard_label_new(_("Select the host to receive the stream from (or allow any host to stream)."));
1102  lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1103 
1104  hbox = lives_hbox_new(FALSE, 0);
1105  lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1106 
1107  pandhw->rb_anyhost = lives_standard_radio_button_new((tmp = (_("Accept LiVES streams from _any host"))),
1108  &radiobutton_group,
1109  LIVES_BOX(hbox),
1110  (tmp2 = (_("Accept incoming LiVES streams from any connected host."))));
1111 
1112  lives_free(tmp);
1113  lives_free(tmp2);
1114 
1115  lives_signal_connect_after(LIVES_GUI_OBJECT(pandhw->rb_anyhost), LIVES_WIDGET_TOGGLED_SIGNAL,
1116  LIVES_GUI_CALLBACK(pandhw_anyhost_toggled),
1117  (livespointer)pandhw);
1118 
1119  hbox = lives_hbox_new(FALSE, 0);
1120  lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1121 
1122  lives_standard_radio_button_new((tmp = (_("Accept LiVES streams only from the _specified host:"))),
1123  &radiobutton_group, LIVES_BOX(hbox),
1124  (tmp2 = (_("Accept LiVES streams from the specified host only."))));
1125 
1126  lives_free(tmp); lives_free(tmp2);
1127 
1129 
1130  hbox = lives_hbox_new(FALSE, 0);
1131  lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1132 
1133  pandhw->entry1 = lives_standard_entry_new("", "127", 3, 3, LIVES_BOX(hbox), NULL);
1134  pandhw->entry2 = lives_standard_entry_new(".", "0", 3, 3, LIVES_BOX(hbox), NULL);
1135  pandhw->entry3 = lives_standard_entry_new(".", "0", 3, 3, LIVES_BOX(hbox), NULL);
1136  pandhw->entry4 = lives_standard_entry_new(".", "0", 3, 3, LIVES_BOX(hbox), NULL);
1137 
1138  lives_widget_set_sensitive(pandhw->entry1, FALSE);
1139  lives_widget_set_sensitive(pandhw->entry2, FALSE);
1140  lives_widget_set_sensitive(pandhw->entry3, FALSE);
1141  lives_widget_set_sensitive(pandhw->entry4, FALSE);
1142 
1143  label = lives_standard_label_new(_("Enter the port number to listen for LiVES streams on:"));
1144  lives_box_pack_start(LIVES_BOX(dialog_vbox), label, FALSE, FALSE, widget_opts.packing_height);
1145 
1146  hbox = lives_hbox_new(FALSE, 0);
1147  lives_box_pack_start(LIVES_BOX(dialog_vbox), hbox, FALSE, FALSE, widget_opts.packing_height);
1148 
1149  pandhw->port_spin = lives_standard_spin_button_new(_("Port"), 48888., 1., 65535, 1., 1., 0, LIVES_BOX(hbox), NULL);
1150 
1151  lives_widget_show_all(pandhw->dialog);
1152 
1153  return pandhw;
1154 }
lives_vstream_t::palette
int palette
Definition: stream.h:19
LIVES_IS_PLAYING
#define LIVES_IS_PLAYING
Definition: main.h:840
lives_pandh_w::entry1
LiVESWidget * entry1
Definition: stream.h:52
lives_vstream_t::YUV_sampling
int YUV_sampling
Definition: stream.h:20
mainwindow::fixed_fpsd
double fixed_fpsd
<=0. means free playback
Definition: mainwindow.h:990
lives_free
#define lives_free
Definition: machinestate.h:52
lives_malloc
#define lives_malloc
Definition: machinestate.h:46
mainwindow::record
volatile boolean record
Definition: mainwindow.h:794
capability::cpu_bits
short cpu_bits
Definition: main.h:583
on_send_lives2lives_activate
void on_send_lives2lives_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: stream.c:982
lives_widget_destroy
LIVES_GLOBAL_INLINE boolean lives_widget_destroy(LiVESWidget *widget)
Definition: widget-helper.c:1553
lives_standard_spin_button_new
LiVESWidget * lives_standard_spin_button_new(const char *labeltext, double val, double min, double max, double step, double page, int dp, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9397
_prefs::workdir
char workdir[PATH_MAX]
kept in locale encoding
Definition: preferences.h:61
lives_spin_button_get_value_as_int
WIDGET_HELPER_GLOBAL_INLINE int lives_spin_button_get_value_as_int(LiVESSpinButton *button)
Definition: widget-helper.c:5091
lives_dialog_get_content_area
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_dialog_get_content_area(LiVESDialog *dialog)
Definition: widget-helper.c:2479
lives_vstream_t::YUV_subspace
int YUV_subspace
Definition: stream.h:22
mainwindow::current_file
int current_file
Definition: mainwindow.h:727
mainwindow::vpp
_vid_playback_plugin * vpp
video plugin
Definition: mainwindow.h:1572
do_info_dialogf
LiVESResponseType do_info_dialogf(const char *fmt,...)
Definition: dialogs.c:773
cfile
#define cfile
Definition: main.h:1833
lives_rfx_t::name
char * name
the name of the executable (so we can run it !)
Definition: plugins.h:626
lives_standard_dialog_new
LiVESWidget * lives_standard_dialog_new(const char *title, boolean add_std_buttons, int width, int height)
Definition: widget-helper.c:9971
prefs
_prefs * prefs
Definition: preferences.h:847
lives_dialog_run
WIDGET_HELPER_GLOBAL_INLINE LiVESResponseType lives_dialog_run(LiVESDialog *dialog)
Definition: widget-helper.c:1783
mainwindow::frame_layer
weed_plant_t * frame_layer
Definition: mainwindow.h:948
frame_size_update
LIVES_GLOBAL_INLINE void frame_size_update(void)
Definition: gui.c:4479
add_hsep_to_box
LiVESWidget * add_hsep_to_box(LiVESBox *box)
Definition: widget-helper.c:12355
lives_pandh_w
Definition: stream.h:50
add_to_clipmenu
void add_to_clipmenu(void)
Definition: gui.c:4512
set_main_title
void set_main_title(const char *file, int untitled)
Definition: main.c:5005
do_rmem_max_error
LIVES_GLOBAL_INLINE void do_rmem_max_error(int size)
Definition: dialogs.c:3755
weed_layer_set_from_lives2lives
void weed_layer_set_from_lives2lives(weed_layer_t *layer, int clip, lives_vstream_t *lstream)
Definition: stream.c:675
lives_vstream_t::flags
uint32_t flags
Definition: stream.h:13
lives_pandh_w::entry3
LiVESWidget * entry3
Definition: stream.h:54
lives_pandh_w::entry4
LiVESWidget * entry4
Definition: stream.h:55
ticks_t
int64_t ticks_t
Definition: main.h:97
do_error_dialog
LIVES_GLOBAL_INLINE LiVESResponseType do_error_dialog(const char *text)
Definition: dialogs.c:749
lives_standard_entry_new
LiVESWidget * lives_standard_entry_new(const char *labeltext, const char *txt, int dispwidth, int maxchars, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9688
end_threaded_dialog
void end_threaded_dialog(void)
Definition: dialogs.c:3883
threaded_dialog_spin
void threaded_dialog_spin(double fraction)
Definition: dialogs.c:3823
TRUE
#define TRUE
Definition: videoplugin.h:59
mainwindow::string_constants
char * string_constants[NUM_LIVES_STRING_CONSTANTS]
Definition: mainwindow.h:1539
weed_layer_pixel_data_free
void weed_layer_pixel_data_free(weed_layer_t *layer)
free pixel_data from layer
Definition: colourspace.c:13819
mainwindow::cancelled
volatile lives_cancel_t cancelled
Definition: mainwindow.h:798
lives_clip_t::fps
double fps
Definition: main.h:893
CANCEL_ERROR
@ CANCEL_ERROR
cancelled because of error
Definition: main.h:740
LIVES_INTENTION_STREAM
@ LIVES_INTENTION_STREAM
Definition: plugins.h:46
LIVES_VSTREAM_FLAGS_IS_CONTINUATION
#define LIVES_VSTREAM_FLAGS_IS_CONTINUATION
Definition: stream.h:39
capable
capability * capable
Definition: main.h:627
lives_toggle_button_get_active
WIDGET_HELPER_GLOBAL_INLINE boolean lives_toggle_button_get_active(LiVESToggleButton *button)
Definition: widget-helper.c:4472
d_print
void d_print(const char *fmt,...)
Definition: utils.c:2542
close_current_file
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
switch_to_file
void switch_to_file(int old_file, int new_file)
Definition: main.c:9646
create_pandh_dialog
lives_pandh_w * create_pandh_dialog(int type)
Definition: stream.c:1074
create_empty_pixel_data
boolean create_empty_pixel_data(weed_layer_t *layer, boolean black_fill, boolean may_contig)
creates pixel data for layer
Definition: colourspace.c:9058
lives_standard_label_new
LiVESWidget * lives_standard_label_new(const char *text)
Definition: widget-helper.c:8601
lives2lives_read_stream
void lives2lives_read_stream(const char *host, int port)
Definition: stream.c:415
interface.h
d_print_failed
void d_print_failed(void)
Definition: utils.c:2615
P_
#define P_(String, StringPlural, n)
Definition: support.h:46
set_vpp
void set_vpp(boolean set_in_prefs)
Definition: preferences.c:476
LIVES_EXT_SRC_STREAM
#define LIVES_EXT_SRC_STREAM
Definition: main.h:1047
stream.h
mainwindow::files
lives_clip_t * files[MAX_FILES+1]
+1 for the clipboard
Definition: mainwindow.h:729
lives_pandh_w::dialog
LiVESWidget * dialog
Definition: stream.h:51
CANCEL_NONE
@ CANCEL_NONE
no cancel
Definition: main.h:701
lives_vstream_t::timecode
int64_t timecode
Definition: stream.h:15
remove_trailing_zeroes
char * remove_trailing_zeroes(double val)
Definition: utils.c:5395
mainwindow::first_free_file
int first_free_file
Definition: mainwindow.h:728
widget_opts_t::packing_height
int packing_height
vertical pixels between widgets
Definition: widget-helper.h:1411
lives_vstream_t::hsize
int hsize
Definition: stream.h:16
widget_opts_t::non_modal
boolean non_modal
non-modal for dialogs
Definition: widget-helper.h:1422
lives_hbox_new
WIDGET_HELPER_GLOBAL_INLINE LiVESWidget * lives_hbox_new(boolean homogeneous, int spacing)
Definition: widget-helper.c:3253
lives_vstream_t
Definition: stream.h:11
lives_get_current_ticks
LIVES_GLOBAL_INLINE ticks_t lives_get_current_ticks(void)
Definition: machinestate.c:835
abs64
LIVES_INLINE int64_t abs64(int64_t a)
Definition: stream.c:25
do_threaded_dialog
void do_threaded_dialog(const char *trans_text, boolean has_cancel)
Definition: dialogs.c:3849
lives_strdup_printf
#define lives_strdup_printf(fmt,...)
Definition: support.c:27
CLIP_TYPE_LIVES2LIVES
@ CLIP_TYPE_LIVES2LIVES
type for LiVES to LiVES streaming
Definition: main.h:770
mainwindow::open_lives2lives
LiVESWidget * open_lives2lives
Definition: mainwindow.h:1118
lives_vstream_t::YUV_clamping
int YUV_clamping
Definition: stream.h:21
weed_layer_t
weed_plant_t weed_layer_t
Definition: colourspace.h:71
OpenHTMSocket
void * OpenHTMSocket(const char *host, int portnumber, boolean sender)
Definition: htmsocket.c:40
lives_clip_t::hsize
int hsize
frame width (horizontal) in pixels (NOT macropixels !)
Definition: main.h:896
lives_vstream_t::bufoffs
volatile size_t bufoffs
Definition: stream.h:32
lives_memcpy
#define lives_memcpy
Definition: machinestate.h:55
lives_stream_in
ssize_t lives_stream_in(void *htmrecvhandle, size_t length, void *buffer, int bfsize)
Definition: htmsocket.c:163
future_prefs
_future_prefs * future_prefs
Definition: preferences.h:848
lives_widget_set_sensitive
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_set_sensitive(LiVESWidget *widget, boolean state)
Definition: widget-helper.c:1477
d_print_cancelled
void d_print_cancelled(void)
Definition: utils.c:2610
_vppaw
video playback plugin window - fixed part
Definition: plugins.h:729
mainwindow::record_paused
volatile boolean record_paused
pause during recording
Definition: mainwindow.h:1557
_future_prefs::vpp_name
char vpp_name[64]
new video playback plugin
Definition: preferences.h:801
CloseHTMSocket
void CloseHTMSocket(void *htmsendhandle)
Definition: htmsocket.c:173
main.h
lives_vstream_t::dsize
size_t dsize
Definition: stream.h:26
lives_vstream_t::buffer
void * buffer
Definition: stream.h:31
_prefs::sleep_time
int sleep_time
Definition: preferences.h:176
lives_vstream_t::reading
volatile boolean reading
Definition: stream.h:30
lives_vstream_t::data_ready
boolean data_ready
Definition: stream.h:27
_vid_playback_plugin::name
char name[64]
Definition: plugins.h:125
mainw
mainwindow * mainw
Definition: main.c:103
_vppaw::dialog
LiVESWidget * dialog
Definition: plugins.h:731
LIVES_STRING_CONSTANT_NONE
@ LIVES_STRING_CONSTANT_NONE
Definition: mainwindow.h:371
LIVES_EXT_SRC_NONE
#define LIVES_EXT_SRC_NONE
Definition: main.h:1043
mainwindow::proc_ptr
xprocess * proc_ptr
Definition: mainwindow.h:1090
lives_pandh_w::port_spin
LiVESWidget * port_spin
Definition: stream.h:56
lives_pandh_w::rb_anyhost
LiVESWidget * rb_anyhost
Definition: stream.h:57
lives_vstream_t::vsize
int vsize
Definition: stream.h:17
lives_widget_show_all
WIDGET_HELPER_GLOBAL_INLINE boolean lives_widget_show_all(LiVESWidget *widget)
Definition: widget-helper.c:1523
widget_opts
widget_opts_t widget_opts
Definition: widget-helper.h:1442
on_vpp_advanced_clicked
_vppaw * on_vpp_advanced_clicked(LiVESButton *button, livespointer user_data)
Definition: plugins.c:727
lives_entry_get_text
WIDGET_HELPER_GLOBAL_INLINE const char * lives_entry_get_text(LiVESEntry *entry)
Definition: widget-helper.c:6203
lives_clip_t::vsize
int vsize
frame height (vertical) in pixels
Definition: main.h:897
L2L_PACKET_LEN
#define L2L_PACKET_LEN
Definition: stream.c:15
effects-weed.h
mainwindow::currticks
volatile ticks_t currticks
wall clock time, updated whenever lives_get_*_ticks is called
Definition: mainwindow.h:1005
lives_pandh_w::entry2
LiVESWidget * entry2
Definition: stream.h:53
lives_vstream_t::handle
void * handle
Definition: stream.h:28
lives_vstream_t::fps
double fps
Definition: stream.h:18
LIVES_STREAM_TYPE_VIDEO
#define LIVES_STREAM_TYPE_VIDEO
Definition: stream.h:36
FALSE
#define FALSE
Definition: videoplugin.h:60
on_open_lives2lives_activate
void on_open_lives2lives_activate(LiVESMenuItem *menuitem, livespointer user_data)
Definition: stream.c:1026
htmsocket.h
_
#define _(String)
Definition: support.h:44
start_playback_async
void start_playback_async(int type)
Definition: saveplay.c:96
mainwindow::error
boolean error
Definition: mainwindow.h:801
lives_rm
int lives_rm(const char *file)
Definition: utils.c:4395
LIVES_INLINE
#define LIVES_INLINE
Definition: main.h:238
_vppaw::rfx
lives_rfx_t * rfx
Definition: plugins.h:737
lives_vstream_t::compression_type
int compression_type
Definition: stream.h:23
lives_widget_context_update
boolean lives_widget_context_update(void)
Definition: widget-helper.c:11878
lives_standard_radio_button_new
LiVESWidget * lives_standard_radio_button_new(const char *labeltext, LiVESSList **rbgroup, LiVESBox *box, const char *tooltip)
Definition: widget-helper.c:9265
lives_box_pack_start
WIDGET_HELPER_GLOBAL_INLINE boolean lives_box_pack_start(LiVESBox *box, LiVESWidget *child, boolean expand, boolean fill, uint32_t padding)
Definition: widget-helper.c:3281
get_new_handle
boolean get_new_handle(int index, const char *name)
Definition: saveplay.c:3821