r956: README.BUILD - add more library recommendations
[cinelerra_cv/ct.git] / cinelerra / vdevicex11.C
blob5eb20e3286f1dad2a1818f63c418ce40f59fb454
1 #include "assets.h"
2 #include "bccapture.h"
3 #include "bcsignals.h"
4 #include "canvas.h"
5 #include "colormodels.h"
6 #include "edl.h"
7 #include "edlsession.h"
8 #include "mwindow.h"
9 #include "playback3d.h"
10 #include "playbackconfig.h"
11 #include "preferences.h"
12 #include "recordconfig.h"
13 #include "strategies.inc"
14 #include "vdevicex11.h"
15 #include "vframe.h"
16 #include "videodevice.h"
17 #include "videowindow.h"
18 #include "videowindowgui.h"
20 #include <string.h>
21 #include <unistd.h>
23 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
24  : VDeviceBase(device)
26         reset_parameters();
27         this->output = output;
30 VDeviceX11::~VDeviceX11()
32         close_all();
35 int VDeviceX11::reset_parameters()
37         output_frame = 0;
38         window_id = 0;
39         bitmap = 0;
40         bitmap_type = 0;
41         bitmap_w = 0;
42         bitmap_h = 0;
43         output_x1 = 0;
44         output_y1 = 0;
45         output_x2 = 0;
46         output_y2 = 0;
47         canvas_x1 = 0;
48         canvas_y1 = 0;
49         canvas_x2 = 0;
50         canvas_y2 = 0;
51         capture_bitmap = 0;
52         color_model_selected = 0;
53         is_cleared = 0;
54         return 0;
57 int VDeviceX11::open_input()
59 //printf("VDeviceX11::open_input 1\n");
60         capture_bitmap = new BC_Capture(device->in_config->w, 
61                 device->in_config->h,
62                 device->in_config->screencapture_display);
63 //printf("VDeviceX11::open_input 2\n");
64         
65         return 0;
68 int VDeviceX11::open_output()
70         if(output)
71         {
72                 output->lock_canvas("VDeviceX11::open_output");
73                 output->get_canvas()->lock_window("VDeviceX11::open_output");
74                 if(!device->single_frame)
75                         output->start_video();
76                 else
77                         output->start_single();
78                 output->get_canvas()->unlock_window();
80 // Enable opengl in the first routine that needs it, to reduce the complexity.
82                 output->unlock_canvas();
83         }
84         return 0;
88 int VDeviceX11::output_visible()
90         if(!output) return 0;
92         output->lock_canvas("VDeviceX11::output_visible");
93         if(output->get_canvas()->get_hidden()) 
94         {
95                 output->unlock_canvas();
96                 return 0; 
97         }
98         else 
99         {
100                 output->unlock_canvas();
101                 return 1;
102         }
106 int VDeviceX11::close_all()
108         if(output)
109         {
110                 output->lock_canvas("VDeviceX11::close_all 1");
111                 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
112         }
114         if(output && output_frame)
115         {
116 // Copy our output frame buffer to the canvas's permanent frame buffer.
117 // They must be different buffers because the output frame is being written
118 // while the user is redrawing the canvas frame buffer over and over.
120                 int use_opengl = device->out_config->driver == PLAYBACK_X11_GL &&
121                         output_frame->get_opengl_state() == VFrame::SCREEN;
122                 int best_color_model = output_frame->get_color_model();
124 // OpenGL does YUV->RGB in the compositing step
125                 if(use_opengl)
126                         best_color_model = BC_RGB888;
128                 if(output->refresh_frame &&
129                         (output->refresh_frame->get_w() != device->out_w ||
130                         output->refresh_frame->get_h() != device->out_h ||
131                         output->refresh_frame->get_color_model() != best_color_model))
132                 {
133                         delete output->refresh_frame;
134                         output->refresh_frame = 0;
135                 }
137                 if(!output->refresh_frame)
138                 {
139                         output->refresh_frame = new VFrame(0,
140                                 device->out_w,
141                                 device->out_h,
142                                 best_color_model);
143                 }
145                 if(use_opengl)
146                 {
147                         output->get_canvas()->unlock_window();
148                         output->unlock_canvas();
150                         output->mwindow->playback_3d->copy_from(output, 
151                                 output->refresh_frame,
152                                 output_frame,
153                                 0);
154                         output->lock_canvas("VDeviceX11::close_all 2");
155                         output->get_canvas()->lock_window("VDeviceX11::close_all 2");
156                 }
157                 else
158                         output->refresh_frame->copy_from(output_frame);
160 // // Update the status bug
161 //              if(!device->single_frame)
162 //              {
163 //                      output->stop_video();
164 //              }
165 //              else
166 //              {
167 //                      output->stop_single();
168 //              }
170 // Draw the first refresh with new frame.
171 // Doesn't work if video and openGL because OpenGL doesn't have 
172 // the output buffer for video.
173 // Not necessary for any case if we mandate a frame advance after
174 // every stop.
175                 if(/* device->out_config->driver != PLAYBACK_X11_GL || 
176                         */ device->single_frame)
177                         output->draw_refresh();
178         }
183         if(bitmap)
184         {
185                 delete bitmap;
186                 bitmap = 0;
187         }
189         if(output_frame)
190         {
191                 delete output_frame;
192                 output_frame = 0;
193         }
195         if(capture_bitmap) delete capture_bitmap;
197         if(output)
198         {
199         
200 // Update the status bug
201                 if(!device->single_frame)
202                 {
203                         output->stop_video();
204                 }
205                 else
206                 {
207                         output->stop_single();
208                 }
210                 output->get_canvas()->unlock_window();
211                 output->unlock_canvas();
212         }
215         reset_parameters();
216         return 0;
219 int VDeviceX11::read_buffer(VFrame *frame)
221         capture_bitmap->capture_frame(frame, device->input_x, device->input_y);
222         return 0;
226 int VDeviceX11::get_best_colormodel(Asset *asset)
228         return BC_RGB888;
232 int VDeviceX11::get_best_colormodel(int colormodel)
234         int result = -1;
236         if(device->out_config->driver == PLAYBACK_X11_GL)
237         {
238                 if(colormodel == BC_RGB888 ||
239                         colormodel == BC_RGBA8888 ||
240                         colormodel == BC_YUV888 ||
241                         colormodel == BC_YUVA8888 ||
242                         colormodel == BC_RGB_FLOAT ||
243                         colormodel == BC_RGBA_FLOAT)
244                 {
245                         return colormodel;
246                 }
247                 return BC_RGB888;
248         }
250         if(!device->single_frame)
251         {
252                 switch(colormodel)
253                 {
254                         case BC_YUV420P:
255                         case BC_YUV422P:
256                         case BC_YUV422:
257                                 result = colormodel;
258                                 break;
259                 }
260         }
262 // 2 more colormodels are supported by OpenGL
263         if(device->out_config->driver == PLAYBACK_X11_GL)
264         {
265                 if(colormodel == BC_RGB_FLOAT ||
266                         colormodel == BC_RGBA_FLOAT)
267                         result = colormodel;
268         }
270         if(result < 0)
271         {
272                 switch(colormodel)
273                 {
274                         case BC_RGB888:
275                         case BC_RGBA8888:
276                         case BC_YUV888:
277                         case BC_YUVA8888:
278                                 result = colormodel;
279                                 break;
281                         default:
282                                 output->lock_canvas("VDeviceX11::get_best_colormodel");
283                                 result = output->get_canvas()->get_color_model();
284                                 output->unlock_canvas();
285                                 break;
286                 }
287         }
289         return result;
293 void VDeviceX11::new_output_buffer(VFrame **result, int colormodel)
295 //printf("VDeviceX11::new_output_buffer 1\n");
296         output->lock_canvas("VDeviceX11::new_output_buffer");
297         output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
299 // Get the best colormodel the display can handle.
300         int best_colormodel = get_best_colormodel(colormodel);
302 // Only create OpenGL Pbuffer and texture.
303         if(device->out_config->driver == PLAYBACK_X11_GL)
304         {
305 // Create bitmap for initial load into texture.
306 // Not necessary to do through Playback3D.....yet
307                 if(!output_frame)
308                 {
309                         output_frame = new VFrame(0, 
310                                 device->out_w, 
311                                 device->out_h, 
312                                 colormodel);
313 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 1");
314                 }
316                 window_id = output->get_canvas()->get_id();
317                 output_frame->set_opengl_state(VFrame::RAM);
318         }
319         else
320         {
321 // Conform existing bitmap to new colormodel and output size
322                 if(bitmap)
323                 {
324 // Restart if output size changed or output colormodel changed.
325 // May have to recreate if transferring between windowed and fullscreen.
326                         if(!color_model_selected ||
327                                 (!bitmap->hardware_scaling() && 
328                                         (bitmap->get_w() != output->get_canvas()->get_w() ||
329                                         bitmap->get_h() != output->get_canvas()->get_h())) ||
330                                 colormodel != output_frame->get_color_model())
331                         {
332                                 int size_change = (bitmap->get_w() != output->get_canvas()->get_w() ||
333                                         bitmap->get_h() != output->get_canvas()->get_h());
334                                 delete bitmap;
335                                 delete output_frame;
336                                 bitmap = 0;
337                                 output_frame = 0;
339 // Blank only if size changed
340                                 if(size_change)
341                                 {
342                                         output->get_canvas()->set_color(BLACK);
343                                         output->get_canvas()->draw_box(0, 0, output->w, output->h);
344                                         output->get_canvas()->flash();
345                                 }
346                         }
347                         else
348 // Update the ring buffer
349                         if(bitmap_type == BITMAP_PRIMARY)
350                         {
352                                 output_frame->set_memory((unsigned char*)bitmap->get_data() /* + bitmap->get_shm_offset() */,
353                                                         bitmap->get_y_offset(),
354                                                         bitmap->get_u_offset(),
355                                                         bitmap->get_v_offset());
356                         }
357                 }
359 // Create new bitmap
360                 if(!bitmap)
361                 {
362 // Try hardware accelerated
363                         switch(best_colormodel)
364                         {
365                                 case BC_YUV420P:
366                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
367                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
368                                                 !output->use_scrollbars)
369                                         {
370                                                 bitmap = new BC_Bitmap(output->get_canvas(), 
371                                                         device->out_w,
372                                                         device->out_h,
373                                                         best_colormodel,
374                                                         1);
375                                                 output_frame = new VFrame((unsigned char*)bitmap->get_data() + bitmap->get_shm_offset(), 
376                                                         bitmap->get_y_offset(),
377                                                         bitmap->get_u_offset(),
378                                                         bitmap->get_v_offset(),
379                                                         device->out_w,
380                                                         device->out_h,
381                                                         best_colormodel);
382                                                 bitmap_type = BITMAP_PRIMARY;
383                                         }
384                                         break;
386                                 case BC_YUV422P:
387                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
388                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
389                                                 !output->use_scrollbars)
390                                         {
391                                                 bitmap = new BC_Bitmap(output->get_canvas(), 
392                                                         device->out_w,
393                                                         device->out_h,
394                                                         best_colormodel,
395                                                         1);
396                                                 output_frame = new VFrame((unsigned char*)bitmap->get_data() + bitmap->get_shm_offset(), 
397                                                         bitmap->get_y_offset(),
398                                                         bitmap->get_u_offset(),
399                                                         bitmap->get_v_offset(),
400                                                         device->out_w,
401                                                         device->out_h,
402                                                         best_colormodel);
403                                                 bitmap_type = BITMAP_PRIMARY;
404                                         }
405                                         else
406                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
407                                                 output->get_canvas()->accel_available(BC_YUV422, 0))
408                                         {
409                                                 bitmap = new BC_Bitmap(output->get_canvas(), 
410                                                         device->out_w,
411                                                         device->out_h,
412                                                         BC_YUV422,
413                                                         1);
414                                                 bitmap_type = BITMAP_TEMP;
415                                         }
416                                         break;
418                                 case BC_YUV422:
419                                         if(device->out_config->driver == PLAYBACK_X11_XV &&
420                                                 output->get_canvas()->accel_available(best_colormodel, 0) &&
421                                                 !output->use_scrollbars)
422                                         {
423                                                 bitmap = new BC_Bitmap(output->get_canvas(), 
424                                                         device->out_w,
425                                                         device->out_h,
426                                                         best_colormodel,
427                                                         1);
428                                                 output_frame = new VFrame((unsigned char*)bitmap->get_data() + bitmap->get_shm_offset(), 
429                                                         bitmap->get_y_offset(),
430                                                         bitmap->get_u_offset(),
431                                                         bitmap->get_v_offset(),
432                                                         device->out_w,
433                                                         device->out_h,
434                                                         best_colormodel);
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,
443                                                         device->out_h,
444                                                         BC_YUV422P,
445                                                         1);
446                                                 bitmap_type = BITMAP_TEMP;
447                                         }
448                                         break;
449                         }
451 // Try default colormodel
452                         if(!bitmap)
453                         {
454                                 best_colormodel = output->get_canvas()->get_color_model();
455                                 bitmap = new BC_Bitmap(output->get_canvas(), 
456                                         output->get_canvas()->get_w(),
457                                         output->get_canvas()->get_h(),
458                                         best_colormodel,
459                                         1);
460                                 bitmap_type = BITMAP_TEMP;
461                         }
463                         if(bitmap_type == BITMAP_TEMP)
464                         {
465 // Intermediate frame
466                                 output_frame = new VFrame(0, 
467                                         device->out_w,
468                                         device->out_h,
469                                         colormodel);
470 // printf("VDeviceX11::new_outout_buffer %p %d %d %d %p\n", 
471 // device,
472 // device->out_w,
473 // device->out_h,
474 // colormodel,
475 // output_frame->get_rows());
476 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 2");
477                                 bitmap_type = BITMAP_TEMP;
478                         }
479                         color_model_selected = 1;
480                 }
482 // Fill arguments
483                 if(bitmap_type == BITMAP_PRIMARY)
484                 {
485 // Only useful if the primary is RGB888 which XFree86 never uses.
486                         output_frame->set_shm_offset(bitmap->get_shm_offset());
487                 }
488                 else
489                 if(bitmap_type == BITMAP_TEMP)
490                 {
491                         output_frame->set_shm_offset(0);
492                 }
493         }
496         *result = output_frame;
498         output->get_canvas()->unlock_window();
499         output->unlock_canvas();
500 //printf("VDeviceX11::new_output_buffer 10\n");
504 int VDeviceX11::start_playback()
506 // Record window is initialized when its monitor starts.
507         if(!device->single_frame)
508                 output->start_video();
509         return 0;
512 int VDeviceX11::stop_playback()
514         if(!device->single_frame)
515                 output->stop_video();
516 // Record window goes back to monitoring
517 // get the last frame played and store it in the video_out
518         return 0;
521 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
523 // The reason for not drawing single frame is that it is _always_ drawn 
524 // when drawing draw_refresh in cwindowgui and vwindowgui
525         if (device->single_frame) 
526                 return 0;
528         int i = 0;
529         output->lock_canvas("VDeviceX11::write_buffer");
530         output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
533 //printf("VDeviceX11::write_buffer %d\n", output->get_canvas()->get_video_on());
534         output->get_transfers(edl, 
535                 output_x1, 
536                 output_y1, 
537                 output_x2, 
538                 output_y2, 
539                 canvas_x1, 
540                 canvas_y1, 
541                 canvas_x2, 
542                 canvas_y2,
543 // Canvas may be a different size than the temporary bitmap for pure software
544                 (bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) ? bitmap->get_w() : -1,
545                 (bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) ? bitmap->get_h() : -1);
548 // Convert colormodel
549         if(bitmap_type == BITMAP_TEMP)
550         {
551 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
552 //                      output->w,
553 //                      output->h,
554 //                      in_x, 
555 //                      in_y, 
556 //                      in_w, 
557 //                      in_h,
558 //                      out_x, 
559 //                      out_y, 
560 //                      out_w, 
561 //                      out_h );
562 // fflush(stdout);
564 //printf("VDeviceX11::write_buffer 2\n");
567                 if(bitmap->hardware_scaling())
568                 {
569                         cmodel_transfer(bitmap->get_row_pointers(), 
570                                 output_channels->get_rows(),
571                                 0,
572                                 0,
573                                 0,
574                                 output_channels->get_y(),
575                                 output_channels->get_u(),
576                                 output_channels->get_v(),
577                                 0, 
578                                 0, 
579                                 output_channels->get_w(), 
580                                 output_channels->get_h(),
581                                 0, 
582                                 0, 
583                                 bitmap->get_w(), 
584                                 bitmap->get_h(),
585                                 output_channels->get_color_model(), 
586                                 bitmap->get_color_model(),
587                                 0,
588                                 output_channels->get_w(),
589                                 bitmap->get_w());
590                 }
591                 else
592                 {
593                         cmodel_transfer(bitmap->get_row_pointers(), 
594                                 output_channels->get_rows(),
595                                 0,
596                                 0,
597                                 0,
598                                 output_channels->get_y(),
599                                 output_channels->get_u(),
600                                 output_channels->get_v(),
601                                 (int)output_x1, 
602                                 (int)output_y1, 
603                                 (int)(output_x2 - output_x1), 
604                                 (int)(output_y2 - output_y1),
605                                 0, 
606                                 0, 
607                                 (int)(canvas_x2 - canvas_x1), 
608                                 (int)(canvas_y2 - canvas_y1),
609                                 output_channels->get_color_model(), 
610                                 bitmap->get_color_model(),
611                                 0,
612                                 output_channels->get_w(),
613                                 bitmap->get_w());
614                 }
615         }
617 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
618 //for(i = 0; i < 1000; i += 4) bitmap->get_data()[i] = 128;
619 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type, 
620 //      bitmap->get_color_model(), 
621 //      output->get_color_model());fflush(stdout);
622 // printf("VDeviceX11::write_buffer 2 %d %d, %f %f %f %f -> %f %f %f %f\n",
623 // output->w,
624 // output->h,
625 // output_x1, 
626 // output_y1, 
627 // output_x2, 
628 // output_y2, 
629 // canvas_x1, 
630 // canvas_y1, 
631 // canvas_x2, 
632 // canvas_y2);
636 // Cause X server to display it
637         if(device->out_config->driver == PLAYBACK_X11_GL)
638         {
639 // Output is drawn in close_all if no video.
640                 if(output->get_canvas()->get_video_on())
641                 {
642 // Draw output frame directly.  Not used for compositing.
643                         output->get_canvas()->unlock_window();
644                         output->unlock_canvas();
645                         output->mwindow->playback_3d->write_buffer(output, 
646                                 output_frame,
647                                 output_x1,
648                                 output_y1,
649                                 output_x2,
650                                 output_y2,
651                                 canvas_x1,
652                                 canvas_y1,
653                                 canvas_x2,
654                                 canvas_y2,
655                                 is_cleared);
656                         is_cleared = 0;
657                         output->lock_canvas("VDeviceX11::write_buffer 2");
658                         output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
659                 }
660         }
661         else
662         if(bitmap->hardware_scaling())
663         {
664                 output->get_canvas()->draw_bitmap(bitmap,
665                         !device->single_frame,
666                         (int)canvas_x1,
667                         (int)canvas_y1,
668                         (int)(canvas_x2 - canvas_x1),
669                         (int)(canvas_y2 - canvas_y1),
670                         (int)output_x1,
671                         (int)output_y1,
672                         (int)(output_x2 - output_x1),
673                         (int)(output_y2 - output_y1),
674                         0);
675         }
676         else
677         {
678                 output->get_canvas()->draw_bitmap(bitmap,
679                         !device->single_frame,
680                         (int)canvas_x1,
681                         (int)canvas_y1,
682                         (int)(canvas_x2 - canvas_x1),
683                         (int)(canvas_y2 - canvas_y1),
684                         0, 
685                         0, 
686                         (int)(canvas_x2 - canvas_x1),
687                         (int)(canvas_y2 - canvas_y1),
688                         0);
689         }
692         output->get_canvas()->unlock_window();
693         output->unlock_canvas();
694         return 0;
698 void VDeviceX11::clear_output()
700         is_cleared = 1;
702         output->mwindow->playback_3d->clear_output(output,
703                 output->get_canvas()->get_video_on() ? 0 : output_frame);
708 void VDeviceX11::clear_input(VFrame *frame)
710         this->output->mwindow->playback_3d->clear_input(this->output, frame);
713 void VDeviceX11::do_camera(VFrame *output,
714         VFrame *input,
715         float in_x1, 
716         float in_y1, 
717         float in_x2, 
718         float in_y2, 
719         float out_x1, 
720         float out_y1, 
721         float out_x2, 
722         float out_y2)
724         this->output->mwindow->playback_3d->do_camera(this->output, 
725                 output,
726                 input,
727                 in_x1, 
728                 in_y1, 
729                 in_x2, 
730                 in_y2, 
731                 out_x1, 
732                 out_y1, 
733                 out_x2, 
734                 out_y2);
738 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
740         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
743 void VDeviceX11::do_mask(VFrame *output_temp, 
744                 int64_t start_position_project,
745                 MaskAutos *keyframe_set, 
746                 MaskAuto *keyframe,
747                 MaskAuto *default_auto)
749         this->output->mwindow->playback_3d->do_mask(output,
750                 output_temp,
751                 start_position_project,
752                 keyframe_set,
753                 keyframe,
754                 default_auto);
757 void VDeviceX11::overlay(VFrame *output_frame,
758                 VFrame *input, 
759 // This is the transfer from track to output frame
760                 float in_x1, 
761                 float in_y1, 
762                 float in_x2, 
763                 float in_y2, 
764                 float out_x1, 
765                 float out_y1, 
766                 float out_x2, 
767                 float out_y2, 
768                 float alpha,        // 0 - 1
769                 int mode,
770                 EDL *edl)
772         int interpolation_type = edl->session->interpolation_type;
774 // printf("VDeviceX11::overlay 1:\n"
775 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
776 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
777 // in_x1, 
778 // in_y1, 
779 // in_x2, 
780 // in_y2, 
781 // out_x1,
782 // out_y1,
783 // out_x2,
784 // out_y2);
785 // Convert node coords to canvas coords in here
786         output->lock_canvas("VDeviceX11::overlay");
787         output->get_canvas()->lock_window("VDeviceX11::overlay");
789 // This is the transfer from output frame to canvas
790         output->get_transfers(edl, 
791                 output_x1, 
792                 output_y1, 
793                 output_x2, 
794                 output_y2, 
795                 canvas_x1, 
796                 canvas_y1, 
797                 canvas_x2, 
798                 canvas_y2,
799                 -1,
800                 -1);
802         output->get_canvas()->unlock_window();
803         output->unlock_canvas();
806 // If single frame playback, use full sized PBuffer as output.
807         if(device->single_frame)
808         {
809                 output->mwindow->playback_3d->overlay(output, 
810                         input,
811                         in_x1, 
812                         in_y1, 
813                         in_x2, 
814                         in_y2, 
815                         out_x1,
816                         out_y1,
817                         out_x2,
818                         out_y2,
819                         alpha,            // 0 - 1
820                         mode,
821                         interpolation_type,
822                         output_frame);
823 // printf("VDeviceX11::overlay 1 %p %d %d %d\n", 
824 // output_frame, 
825 // output_frame->get_w(),
826 // output_frame->get_h(),
827 // output_frame->get_opengl_state());
828         }
829         else
830         {
832 // Get transfer from track to canvas
833                 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
834                 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
835                 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
836                 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
839 // Get coordinates of canvas relative to track frame
840                 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
841                 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
842                 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
843                 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
845 // Clamp canvas coords to track boundary
846                 if(track_x1 < 0)
847                 {
848                         float difference = -track_x1;
849                         track_x1 += difference;
850                         canvas_x1 += difference * track_xscale * canvas_xscale;
851                 }
852                 if(track_y1 < 0)
853                 {
854                         float difference = -track_y1;
855                         track_y1 += difference;
856                         canvas_y1 += difference * track_yscale * canvas_yscale;
857                 }
859                 if(track_x2 > input->get_w())
860                 {
861                         float difference = track_x2 - input->get_w();
862                         track_x2 -= difference;
863                         canvas_x2 -= difference * track_xscale * canvas_xscale;
864                 }
865                 if(track_y2 > input->get_h())
866                 {
867                         float difference = track_y2 - input->get_h();
868                         track_y2 -= difference;
869                         canvas_y2 -= difference * track_yscale * canvas_yscale;
870                 }
876 // Overlay directly from track buffer to canvas, skipping output buffer
877                 if(track_x2 > track_x1 && 
878                         track_y2 > track_y1 &&
879                         canvas_x2 > canvas_x1 &&
880                         canvas_y2 > canvas_y1)
881                 {
882                         output->mwindow->playback_3d->overlay(output, 
883                                 input,
884                                 track_x1, 
885                                 track_y1, 
886                                 track_x2, 
887                                 track_y2, 
888                                 canvas_x1,
889                                 canvas_y1,
890                                 canvas_x2,
891                                 canvas_y2,
892                                 alpha,            // 0 - 1
893                                 mode,
894                                 interpolation_type);
895                 }
896         }
899 void VDeviceX11::run_plugin(PluginClient *client)
901         output->mwindow->playback_3d->run_plugin(output, client);
904 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
906         output->mwindow->playback_3d->copy_from(output, dst, src, 1);