add bluray dv, misc fixes
[goodguy/history.git] / cinelerra-5.1 / cinelerra / vdevicex11.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008 Adam Williams <broadcast at earthling dot net>
5  *
6  * This program is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 2 of the License, or
9  * (at your option) any later version.
10  *
11  * This program is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for more details.
15  *
16  * You should have received a copy of the GNU General Public License
17  * along with this program; if not, write to the Free Software
18  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
19  *
20  */
21
22 #include "assets.h"
23 #include "auto.h"
24 #include "bccapture.h"
25 #include "bcsignals.h"
26 #include "canvas.h"
27 #include "bccmodels.h"
28 #include "edl.h"
29 #include "edlsession.h"
30 #include "maskautos.h"
31 #include "maskauto.h"
32 #include "mwindow.h"
33 #include "playback3d.h"
34 #include "playbackconfig.h"
35 #include "preferences.h"
36 #include "recordconfig.h"
37 #include "strategies.inc"
38 #include "vdevicex11.h"
39 #include "vframe.h"
40 #include "videodevice.h"
41 #include "videowindow.h"
42 #include "videowindowgui.h"
43
44 #include <string.h>
45 #include <unistd.h>
46
47 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
48  : VDeviceBase(device)
49 {
50         reset_parameters();
51         this->output = output;
52 }
53
54 VDeviceX11::~VDeviceX11()
55 {
56         close_all();
57 }
58
59 int VDeviceX11::reset_parameters()
60 {
61         output_frame = 0;
62         window_id = 0;
63         bitmap = 0;
64         bitmap_type = 0;
65         bitmap_w = 0;
66         bitmap_h = 0;
67         output_x1 = 0;
68         output_y1 = 0;
69         output_x2 = 0;
70         output_y2 = 0;
71         canvas_x1 = 0;
72         canvas_y1 = 0;
73         canvas_x2 = 0;
74         canvas_y2 = 0;
75         capture_bitmap = 0;
76         color_model_selected = 0;
77         is_cleared = 0;
78         return 0;
79 }
80
81 int VDeviceX11::open_input()
82 {
83 //printf("VDeviceX11::open_input 1\n");
84         capture_bitmap = new BC_Capture(device->in_config->w,
85                 device->in_config->h,
86                 device->in_config->screencapture_display);
87 //printf("VDeviceX11::open_input 2\n");
88
89         return 0;
90 }
91
92 int VDeviceX11::open_output()
93 {
94         if(output)
95         {
96                 output->lock_canvas("VDeviceX11::open_output");
97                 output->get_canvas()->lock_window("VDeviceX11::open_output");
98                 if(!device->single_frame)
99                         output->start_video();
100                 else
101                         output->start_single();
102                 output->get_canvas()->unlock_window();
103
104 // Enable opengl in the first routine that needs it, to reduce the complexity.
105
106                 output->unlock_canvas();
107         }
108         return 0;
109 }
110
111
112 int VDeviceX11::output_visible()
113 {
114         if(!output) return 0;
115
116         output->lock_canvas("VDeviceX11::output_visible");
117         if(output->get_canvas()->get_hidden())
118         {
119                 output->unlock_canvas();
120                 return 0;
121         }
122         else
123         {
124                 output->unlock_canvas();
125                 return 1;
126         }
127 }
128
129
130 int VDeviceX11::close_all()
131 {
132         if(output)
133         {
134                 output->lock_canvas("VDeviceX11::close_all 1");
135                 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
136         }
137
138         if(output && output_frame)
139         {
140 // Copy our output frame buffer to the canvas's permanent frame buffer.
141 // They must be different buffers because the output frame is being written
142 // while the user is redrawing the canvas frame buffer over and over.
143
144                 int use_opengl = device->out_config->driver == PLAYBACK_X11_GL &&
145                         output_frame->get_opengl_state() == VFrame::SCREEN;
146                 int best_color_model = output_frame->get_color_model();
147
148 // OpenGL does YUV->RGB in the compositing step
149                 if(use_opengl)
150                         best_color_model = BC_RGB888;
151
152                 if(output->refresh_frame &&
153                         (output->refresh_frame->get_w() != device->out_w ||
154                         output->refresh_frame->get_h() != device->out_h ||
155                         output->refresh_frame->get_color_model() != best_color_model))
156                 {
157                         delete output->refresh_frame;
158                         output->refresh_frame = 0;
159                 }
160
161                 if(!output->refresh_frame)
162                 {
163                         output->refresh_frame = new VFrame(0, -1,
164                                 device->out_w, device->out_h,
165                                 best_color_model, -1);
166                 }
167
168                 if(use_opengl)
169                 {
170                         output->get_canvas()->unlock_window();
171                         output->unlock_canvas();
172
173                         output->mwindow->playback_3d->copy_from(output,
174                                 output->refresh_frame, output_frame, 0);
175                         output->lock_canvas("VDeviceX11::close_all 2");
176                         output->get_canvas()->lock_window("VDeviceX11::close_all 2");
177                 }
178                 else
179                         output->refresh_frame->copy_from(output_frame);
180
181 // // Update the status bug
182 //              if(!device->single_frame)
183 //              {
184 //                      output->stop_video();
185 //              }
186 //              else
187 //              {
188 //                      output->stop_single();
189 //              }
190
191 // Draw the first refresh with new frame.
192 // Doesn't work if video and openGL because OpenGL doesn't have
193 // the output buffer for video.
194 // Not necessary for any case if we mandate a frame advance after
195 // every stop.
196                 if(/* device->out_config->driver != PLAYBACK_X11_GL ||
197                         */ device->single_frame)
198                         output->draw_refresh();
199         }
200
201
202
203
204         if(bitmap)
205         {
206                 delete bitmap;
207                 bitmap = 0;
208         }
209
210         if(output_frame)
211         {
212                 delete output_frame;
213                 output_frame = 0;
214         }
215
216         if(capture_bitmap) delete capture_bitmap;
217
218         if(output)
219         {
220
221 // Update the status bug
222                 if(!device->single_frame)
223                 {
224                         output->stop_video();
225                 }
226                 else
227                 {
228                         output->stop_single();
229                 }
230
231                 output->get_canvas()->unlock_window();
232                 output->unlock_canvas();
233         }
234
235
236         reset_parameters();
237         return 0;
238 }
239
240 int VDeviceX11::read_buffer(VFrame *frame)
241 {
242         capture_bitmap->capture_frame(frame, device->input_x, device->input_y);
243         return 0;
244 }
245
246
247 int VDeviceX11::get_best_colormodel(Asset *asset)
248 {
249         return BC_RGB888;
250 }
251
252
253 int VDeviceX11::get_best_colormodel(int colormodel)
254 {
255         int result = -1;
256
257         if(device->out_config->driver == PLAYBACK_X11_GL)
258         {
259                 if(colormodel == BC_RGB888 ||
260                         colormodel == BC_RGBA8888 ||
261                         colormodel == BC_YUV888 ||
262                         colormodel == BC_YUVA8888 ||
263                         colormodel == BC_RGB_FLOAT ||
264                         colormodel == BC_RGBA_FLOAT)
265                 {
266                         return colormodel;
267                 }
268                 return BC_RGB888;
269         }
270
271         if(!device->single_frame)
272         {
273                 switch(colormodel)
274                 {
275                         case BC_YUV420P:
276                         case BC_YUV422P:
277                         case BC_YUV422:
278                                 result = colormodel;
279                                 break;
280                 }
281         }
282
283 // 2 more colormodels are supported by OpenGL
284         if(device->out_config->driver == PLAYBACK_X11_GL)
285         {
286                 if(colormodel == BC_RGB_FLOAT ||
287                         colormodel == BC_RGBA_FLOAT)
288                         result = colormodel;
289         }
290
291         if(result < 0)
292         {
293                 switch(colormodel)
294                 {
295                         case BC_RGB888:
296                         case BC_RGBA8888:
297                         case BC_YUV888:
298                         case BC_YUVA8888:
299                                 result = colormodel;
300                                 break;
301
302                         default:
303                                 output->lock_canvas("VDeviceX11::get_best_colormodel");
304                                 result = output->get_canvas()->get_color_model();
305                                 output->unlock_canvas();
306                                 break;
307                 }
308         }
309
310         return result;
311 }
312
313
314 void VDeviceX11::new_output_buffer(VFrame **result, int colormodel)
315 {
316 //printf("VDeviceX11::new_output_buffer 1\n");
317         output->lock_canvas("VDeviceX11::new_output_buffer");
318         output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
319
320 // Get the best colormodel the display can handle.
321         int best_colormodel = get_best_colormodel(colormodel);
322
323 // Only create OpenGL Pbuffer and texture.
324         if(device->out_config->driver == PLAYBACK_X11_GL)
325         {
326 // Create bitmap for initial load into texture.
327 // Not necessary to do through Playback3D.....yet
328                 if(!output_frame)
329                 {
330                         output_frame = new VFrame(0, -1,
331                                 device->out_w, device->out_h,
332                                 colormodel, -1);
333 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 1");
334                 }
335
336                 window_id = output->get_canvas()->get_id();
337                 output_frame->set_opengl_state(VFrame::RAM);
338         }
339         else
340         {
341 // Conform existing bitmap to new colormodel and output size
342                 if(bitmap)
343                 {
344 // Restart if output size changed or output colormodel changed.
345 // May have to recreate if transferring between windowed and fullscreen.
346                         if(!color_model_selected ||
347                                 (!bitmap->hardware_scaling() &&
348                                         (bitmap->get_w() != output->get_canvas()->get_w() ||
349                                         bitmap->get_h() != output->get_canvas()->get_h())) ||
350                                 colormodel != output_frame->get_color_model())
351                         {
352                                 int size_change = (bitmap->get_w() != output->get_canvas()->get_w() ||
353                                         bitmap->get_h() != output->get_canvas()->get_h());
354 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
355                                 delete bitmap;
356                                 delete output_frame;
357                                 bitmap = 0;
358                                 output_frame = 0;
359
360 // Blank only if size changed
361                                 if(size_change)
362                                 {
363                                         output->get_canvas()->set_color(BLACK);
364                                         output->get_canvas()->draw_box(0, 0, output->w, output->h);
365                                         output->get_canvas()->flash();
366                                 }
367                         }
368                         else
369 // Update the ring buffer
370                         if(bitmap_type == BITMAP_PRIMARY)
371                         {
372 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
373                                 output_frame->set_memory(bitmap);
374                         }
375                 }
376
377 // Create new bitmap
378                 if(!bitmap)
379                 {
380 // Try hardware accelerated
381                         switch(best_colormodel)
382                         {
383                                 case BC_YUV420P:
384                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
385                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
386                                                 !output->use_scrollbars)
387                                         {
388                                                 bitmap = new BC_Bitmap(output->get_canvas(),
389                                                         device->out_w, device->out_h,
390                                                         best_colormodel, 1);
391                                                 output_frame = new VFrame(bitmap,
392                                                         device->out_w, device->out_h,
393                                                         best_colormodel, -1);
394                                                 bitmap_type = BITMAP_PRIMARY;
395                                         }
396                                         break;
397
398                                 case BC_YUV422P:
399                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
400                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
401                                                 !output->use_scrollbars)
402                                         {
403                                                 bitmap = new BC_Bitmap(output->get_canvas(),
404                                                         device->out_w, device->out_h,
405                                                         best_colormodel, 1);
406                                                 output_frame = new VFrame(bitmap,
407                                                         device->out_w, device->out_h,
408                                                         best_colormodel, -1);
409                                                 bitmap_type = BITMAP_PRIMARY;
410                                         }
411                                         else
412                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
413                                                 output->get_canvas()->accel_available(BC_YUV422, 0))
414                                         {
415                                                 bitmap = new BC_Bitmap(output->get_canvas(),
416                                                         device->out_w,
417                                                         device->out_h,
418                                                         BC_YUV422,
419                                                         1);
420                                                 bitmap_type = BITMAP_TEMP;
421                                         }
422                                         break;
423
424                                 case BC_YUV422:
425                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
426                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
427                                                 !output->use_scrollbars)
428                                         {
429                                                 bitmap = new BC_Bitmap(output->get_canvas(),
430                                                         device->out_w, device->out_h,
431                                                         best_colormodel, 1);
432                                                 output_frame = new VFrame(bitmap,
433                                                         device->out_w, device->out_h,
434                                                         best_colormodel, -1);
435                                                 bitmap_type = BITMAP_PRIMARY;
436                                         }
437                                         else
438                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
439                                                 output->get_canvas()->accel_available(BC_YUV422P, 0))
440                                         {
441                                                 bitmap = new BC_Bitmap(output->get_canvas(),
442                                                         device->out_w, device->out_h,
443                                                         BC_YUV422P, 1);
444                                                 bitmap_type = BITMAP_TEMP;
445                                         }
446                                         break;
447                         }
448
449 // Try default colormodel
450                         if(!bitmap)
451                         {
452                                 best_colormodel = output->get_canvas()->get_color_model();
453                                 bitmap = new BC_Bitmap(output->get_canvas(),
454                                         output->get_canvas()->get_w(),
455                                         output->get_canvas()->get_h(),
456                                         best_colormodel, 1);
457                                 bitmap_type = BITMAP_TEMP;
458                         }
459
460                         if(bitmap_type == BITMAP_TEMP)
461                         {
462 // Intermediate frame
463                                 output_frame = new VFrame(0, -1,
464                                         device->out_w, device->out_h,
465                                         colormodel, -1);
466 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 2");
467                                 bitmap_type = BITMAP_TEMP;
468                         }
469                         color_model_selected = 1;
470                 }
471         }
472
473         *result = output_frame;
474 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
475
476         output->get_canvas()->unlock_window();
477         output->unlock_canvas();
478 }
479
480
481 int VDeviceX11::start_playback()
482 {
483 // Record window is initialized when its monitor starts.
484         if(!device->single_frame)
485                 output->start_video();
486         return 0;
487 }
488
489 int VDeviceX11::stop_playback()
490 {
491         if(!device->single_frame)
492                 output->stop_video();
493 // Record window goes back to monitoring
494 // get the last frame played and store it in the video_out
495         return 0;
496 }
497
498 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
499 {
500 // The reason for not drawing single frame is that it is _always_ drawn
501 // when drawing draw_refresh in cwindowgui and vwindowgui
502         if (device->single_frame)
503                 return 0;
504
505         output->lock_canvas("VDeviceX11::write_buffer");
506         output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
507
508 // Canvas may be a different size than the temporary bitmap for pure software
509         int xfr_w, xfr_h;
510         if(bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) {
511                 xfr_w = bitmap->get_w();
512                 xfr_h = bitmap->get_h();
513         }
514         else
515                 xfr_w = xfr_h = -1;
516
517 //printf("VDeviceX11::write_buffer %d %d\n", __LINE__, output->get_canvas()->get_video_on());
518         output->get_transfers(edl, output_x1, output_y1, output_x2, output_y2,
519                 canvas_x1, canvas_y1, canvas_x2, canvas_y2, xfr_w, xfr_h);
520
521 // Convert colormodel
522 #if 0
523 // this is handled by overlay call in virtualvnode, using flatten alpha
524 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
525         if(device->out_config->driver == PLAYBACK_X11_GL &&
526             output_frame->get_color_model() != BC_RGB888) {
527                 int cmodel = BC_RGB888;
528                 output->get_canvas()->unlock_window();
529                 output->unlock_canvas();
530                 output->mwindow->playback_3d->convert_cmodel(output, output_frame, cmodel);
531                 output_frame->reallocate(0,-1,0,0,0,output_frame->get_w(),output_frame->get_h(),cmodel,-1);
532                 output->lock_canvas("VDeviceX11::write_buffer 3");
533                 output->get_canvas()->lock_window("VDeviceX11::write_buffer 3");
534         }
535         else
536 #endif
537         if(bitmap_type == BITMAP_TEMP) {
538 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
539 //  output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h );
540 // fflush(stdout);
541 //printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
542
543
544                 if(bitmap->hardware_scaling())
545                 {
546                         BC_CModels::transfer(bitmap->get_row_pointers(),
547                                 output_channels->get_rows(), 0, 0, 0,
548                                 output_channels->get_y(),
549                                 output_channels->get_u(),
550                                 output_channels->get_v(),
551                                 0, 0,
552                                 output_channels->get_w(),
553                                 output_channels->get_h(),
554                                 0, 0,
555                                 bitmap->get_w(),
556                                 bitmap->get_h(),
557                                 output_channels->get_color_model(),
558                                 bitmap->get_color_model(),
559                                 0,
560                                 output_channels->get_w(),
561                                 bitmap->get_w());
562                 }
563                 else
564                 {
565                         BC_CModels::transfer(bitmap->get_row_pointers(),
566                                 output_channels->get_rows(), 0, 0, 0,
567                                 output_channels->get_y(),
568                                 output_channels->get_u(),
569                                 output_channels->get_v(),
570                                 (int)output_x1,
571                                 (int)output_y1,
572                                 (int)(output_x2 - output_x1),
573                                 (int)(output_y2 - output_y1),
574                                 0, 0,
575                                 (int)(canvas_x2 - canvas_x1),
576                                 (int)(canvas_y2 - canvas_y1),
577                                 output_channels->get_color_model(),
578                                 bitmap->get_color_model(),
579                                 0,
580                                 output_channels->get_w(),
581                                 bitmap->get_w());
582                 }
583         }
584
585 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
586 //for(i = 0; i < 1000; i += 4) bitmap->get_data()[i] = 128;
587 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
588 //  bitmap->get_color_model(), output->get_color_model());
589 //fflush(stdout);
590 //printf("VDeviceX11::write_buffer 2 %d %d, %f %f %f %f -> %f %f %f %f\n",
591 // output->w, output->h, output_x1, output_y1, output_x2, output_y2,
592 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
593
594 // Cause X server to display it
595         if(device->out_config->driver == PLAYBACK_X11_GL)
596         {
597 // Output is drawn in close_all if no video.
598                 if(output->get_canvas()->get_video_on())
599                 {
600 // Draw output frame directly.  Not used for compositing.
601                         output->get_canvas()->unlock_window();
602                         output->unlock_canvas();
603                         output->mwindow->playback_3d->write_buffer(output,
604                                 output_frame, output_x1, output_y1, output_x2, output_y2,
605                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2, is_cleared);
606                         is_cleared = 0;
607                         output->lock_canvas("VDeviceX11::write_buffer 2");
608                         output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
609                 }
610         }
611         else
612         if(bitmap->hardware_scaling())
613         {
614                 output->get_canvas()->draw_bitmap(bitmap,
615                         !device->single_frame,
616                         (int)canvas_x1, (int)canvas_y1,
617                         (int)(canvas_x2 - canvas_x1),
618                         (int)(canvas_y2 - canvas_y1),
619                         (int)output_x1, (int)output_y1,
620                         (int)(output_x2 - output_x1),
621                         (int)(output_y2 - output_y1),
622                         0);
623         }
624         else
625         {
626 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
627                 output->get_canvas()->draw_bitmap(bitmap,
628                         !device->single_frame,
629                         (int)canvas_x1, (int)canvas_y1,
630                         (int)(canvas_x2 - canvas_x1),
631                         (int)(canvas_y2 - canvas_y1),
632                         0, 0,
633                         (int)(canvas_x2 - canvas_x1),
634                         (int)(canvas_y2 - canvas_y1),
635                         0);
636 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
637         }
638
639
640         output->get_canvas()->unlock_window();
641         output->unlock_canvas();
642         return 0;
643 }
644
645
646 void VDeviceX11::clear_output()
647 {
648         is_cleared = 1;
649
650         output->mwindow->playback_3d->clear_output(output,
651                 output->get_canvas()->get_video_on() ? 0 : output_frame);
652
653 }
654
655
656 void VDeviceX11::clear_input(VFrame *frame)
657 {
658         this->output->mwindow->playback_3d->clear_input(this->output, frame);
659 }
660
661 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
662 {
663         this->output->mwindow->playback_3d->convert_cmodel(this->output,
664                 output,
665                 dst_cmodel);
666 }
667
668 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
669         float in_x1, float in_y1, float in_x2, float in_y2,
670         float out_x1, float out_y1, float out_x2, float out_y2)
671 {
672         this->output->mwindow->playback_3d->do_camera(
673                 this->output, output, input,
674                 in_x1, in_y1, in_x2, in_y2,
675                 out_x1, out_y1, out_x2, out_y2);
676 }
677
678
679 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
680 {
681         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
682 }
683
684 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
685 {
686         Auto *current = 0;
687         MaskAuto *keyframe = (MaskAuto*)keyframe_set->
688                 get_prev_auto(start_position_project, PLAY_FORWARD, current);
689         return keyframe->disable_opengl_masking ? 0 : 1;
690 }
691
692 void VDeviceX11::do_mask(VFrame *output_temp,
693         int64_t start_position_project, MaskAutos *keyframe_set,
694         MaskAuto *keyframe, MaskAuto *default_auto)
695 {
696         this->output->mwindow->playback_3d->do_mask(output,
697                 output_temp, start_position_project,
698                 keyframe_set, keyframe, default_auto);
699 }
700
701 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
702 // This is the transfer from track to output frame
703                 float in_x1, float in_y1, float in_x2, float in_y2,
704                 float out_x1, float out_y1, float out_x2, float out_y2,
705                 float alpha /*0-1*/, int mode, EDL *edl, int is_nested)
706 {
707         int interpolation_type = edl->session->interpolation_type;
708
709 // printf("VDeviceX11::overlay 1:\n"
710 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
711 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
712 // in_x1, in_y1, in_x2, in_y2,
713 // out_x1, out_y1, out_x2, out_y2);
714 // Convert node coords to canvas coords in here
715
716 // If single frame playback or nested EDL, use full sized PBuffer as output.
717         if(device->single_frame || is_nested > 0)
718         {
719                 output->mwindow->playback_3d->overlay(output, input,
720                         in_x1, in_y1, in_x2, in_y2,
721                         out_x1, out_y1, out_x2, out_y2,
722                         alpha, mode, interpolation_type,
723                         output_frame, is_nested);
724 // printf("VDeviceX11::overlay 1 %p %d %d %d\n",
725 // output_frame,
726 // output_frame->get_w(),
727 // output_frame->get_h(),
728 // output_frame->get_opengl_state());
729         }
730         else
731         {
732                 output->lock_canvas("VDeviceX11::overlay");
733                 output->get_canvas()->lock_window("VDeviceX11::overlay");
734
735 // This is the transfer from output frame to canvas
736                 output->get_transfers(edl,
737                         output_x1, output_y1, output_x2, output_y2,
738                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
739                         -1, -1);
740
741                 output->get_canvas()->unlock_window();
742                 output->unlock_canvas();
743
744
745 // Get transfer from track to canvas
746                 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
747                 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
748                 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
749                 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
750
751
752 // Get coordinates of canvas relative to track frame
753                 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
754                 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
755                 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
756                 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
757
758 // Clamp canvas coords to track boundary
759                 if(track_x1 < 0)
760                 {
761                         float difference = -track_x1;
762                         track_x1 += difference;
763                         canvas_x1 += difference * track_xscale * canvas_xscale;
764                 }
765                 if(track_y1 < 0)
766                 {
767                         float difference = -track_y1;
768                         track_y1 += difference;
769                         canvas_y1 += difference * track_yscale * canvas_yscale;
770                 }
771
772                 if(track_x2 > input->get_w())
773                 {
774                         float difference = track_x2 - input->get_w();
775                         track_x2 -= difference;
776                         canvas_x2 -= difference * track_xscale * canvas_xscale;
777                 }
778                 if(track_y2 > input->get_h())
779                 {
780                         float difference = track_y2 - input->get_h();
781                         track_y2 -= difference;
782                         canvas_y2 -= difference * track_yscale * canvas_yscale;
783                 }
784
785 // Overlay directly from track buffer to canvas, skipping output buffer
786                 if(track_x2 > track_x1 && track_y2 > track_y1 &&
787                         canvas_x2 > canvas_x1 && canvas_y2 > canvas_y1)
788                 {
789                         output->mwindow->playback_3d->overlay(output, input,
790                                 track_x1, track_y1, track_x2, track_y2,
791                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
792                                 alpha, mode, interpolation_type, 0, is_nested);
793                 }
794         }
795 }
796
797 void VDeviceX11::run_plugin(PluginClient *client)
798 {
799         output->mwindow->playback_3d->run_plugin(output, client);
800 }
801
802 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
803 {
804         output->mwindow->playback_3d->copy_from(output, dst, src, 1);
805 }
806