add missing GPL information in guicast program files
[goodguy/cinelerra.git] / cinelerra-5.1 / cinelerra / vdevicex11.C
1
2 /*
3  * CINELERRA
4  * Copyright (C) 2008-2017 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 "autos.h"
24 #include "bccapture.h"
25 #include "bccmodels.h"
26 #include "bcdisplayinfo.h"
27 #include "bcsignals.h"
28 #include "canvas.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "file.h"
32 #include "maskauto.h"
33 #include "maskautos.h"
34 #include "mwindow.h"
35 #include "mwindowgui.h"
36 #include "playback3d.h"
37 #include "playbackconfig.h"
38 #include "preferences.h"
39 #include "recordconfig.h"
40 #include "strategies.inc"
41 #include "vdevicex11.h"
42 #include "vframe.h"
43 #include "videodevice.h"
44 #include "videowindow.h"
45 #include "videowindowgui.h"
46
47 #include <string.h>
48 #include <unistd.h>
49
50 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
51  : VDeviceBase(device)
52 {
53         reset_parameters();
54         this->output = output;
55         opened = 0;
56 }
57
58 VDeviceX11::~VDeviceX11()
59 {
60         close_all();
61 }
62
63 int VDeviceX11::reset_parameters()
64 {
65         output_frame = 0;
66         window_id = 0;
67         bitmap = 0;
68         bitmap_type = 0;
69         bitmap_w = 0;
70         bitmap_h = 0;
71         output_x1 = 0;
72         output_y1 = 0;
73         output_x2 = 0;
74         output_y2 = 0;
75         canvas_x1 = 0;
76         canvas_y1 = 0;
77         canvas_x2 = 0;
78         canvas_y2 = 0;
79         capture_bitmap = 0;
80         color_model_selected = 0;
81         is_cleared = 0;
82         return 0;
83 }
84
85 int VDeviceX11::open_input()
86 {
87 //printf("VDeviceX11::open_input 1\n");
88         capture_bitmap = new BC_Capture(device->in_config->w,
89                 device->in_config->h,
90                 device->in_config->screencapture_display);
91 //printf("VDeviceX11::open_input 2\n");
92         capture_bitmap->bars_on(SCREENCAP_PIXELS, SCREENCAP_COLOR,
93                 device->input_x, device->input_y,
94                 device->in_config->w, device->in_config->h);
95         opened = 1;
96         return 0;
97 }
98
99 int VDeviceX11::open_output()
100 {
101         if( !output ) return 0;
102         BC_WindowBase *window =
103                 output->lock_canvas("VDeviceX11::open_output");
104         if( window ) {
105                 if( !device->single_frame )
106                         output->start_video();
107                 else
108                         output->start_single();
109         }
110         opened = 1;
111         output->unlock_canvas();
112         return 0;
113 }
114
115
116 int VDeviceX11::output_visible()
117 {
118         int ret = 0;
119         if( output ) {
120                 BC_WindowBase *window =
121                         output->lock_canvas("VDeviceX11::output_visible");
122                 ret = !window || window->get_hidden() ? 0 : 1;
123                 output->unlock_canvas();
124         }
125         return ret;
126 }
127
128
129 int VDeviceX11::close_all()
130 {
131         if( !opened ) return 1;
132         if( output ) {
133                 BC_WindowBase *window =
134                         output->lock_canvas("VDeviceX11::close_all");
135                 int video_on = window ? window->get_video_on() : 0;
136 // Update the status bug
137                 if( !device->single_frame )
138                         output->stop_video();
139                 else
140                         output->stop_single();
141
142                 if( output_frame )
143                         output->update_refresh(device, output_frame);
144 // if the last frame is good, don't draw over it
145                 if( !video_on || output->need_overlays() )
146                         output->draw_refresh(1);
147         }
148
149         delete bitmap;          bitmap = 0;
150         delete output_frame;    output_frame = 0;
151         delete capture_bitmap;  capture_bitmap = 0;
152         opened = 0;
153
154         if( output )
155                 output->unlock_canvas();
156
157         reset_parameters();
158         return 0;
159 }
160
161 int VDeviceX11::read_buffer(VFrame *frame)
162 {
163         capture_bitmap->bars_reposition(
164                 device->input_x, device->input_y,
165                 device->in_config->w, device->in_config->h);
166
167         capture_bitmap->capture_frame(frame,
168                 device->input_x, device->input_y, device->do_cursor);
169         return 0;
170 }
171
172
173 int VDeviceX11::get_best_colormodel(Asset *asset)
174 {
175         return File::get_best_colormodel(asset, SCREENCAPTURE);
176 //      return BC_RGB888;
177 }
178
179
180 int VDeviceX11::get_display_colormodel(int file_colormodel)
181 {
182         int result = -1;
183
184         if( device->out_config->driver == PLAYBACK_X11_GL ) {
185                 if( file_colormodel == BC_RGB888 ||
186                     file_colormodel == BC_RGBA8888 ||
187                     file_colormodel == BC_YUV888 ||
188                     file_colormodel == BC_YUVA8888 ||
189                     file_colormodel == BC_RGB_FLOAT ||
190                     file_colormodel == BC_RGBA_FLOAT ) {
191                         return file_colormodel;
192                 }
193
194                 return BC_RGB888;
195         }
196
197         if( !device->single_frame ) {
198                 switch( file_colormodel ) {
199                 case BC_YUV420P:
200                 case BC_YUV422P:
201                 case BC_YUV422:
202                         result = file_colormodel;
203                         break;
204                 }
205         }
206
207         if( result < 0 ) {
208                 switch( file_colormodel ) {
209                 case BC_RGB888:
210                 case BC_RGBA8888:
211                 case BC_YUV888:
212                 case BC_YUVA8888:
213                 case BC_RGB_FLOAT:
214                 case BC_RGBA_FLOAT:
215                         result = file_colormodel;
216                         break;
217
218                 default: {
219                         BC_WindowBase *window = output->get_canvas();
220                         result = window ? window->get_color_model() : BC_RGB888;
221                         break; }
222                 }
223         }
224
225         return result;
226 }
227
228
229 void VDeviceX11::new_output_buffer(VFrame **result, int file_colormodel, EDL *edl)
230 {
231 // printf("VDeviceX11::new_output_buffer %d hardware_scaling=%d\n",
232 // __LINE__, bitmap ? bitmap->hardware_scaling() : 0);
233         BC_WindowBase *window =
234                 output->lock_canvas("VDeviceX11::new_output_buffer");
235 // Get the best colormodel the display can handle.
236         int display_colormodel = get_display_colormodel(file_colormodel);
237
238 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
239 // __LINE__, file_colormodel, display_colormodel);
240 // Only create OpenGL Pbuffer and texture.
241         if( device->out_config->driver == PLAYBACK_X11_GL ) {
242 // Create bitmap for initial load into texture.
243 // Not necessary to do through Playback3D.....yet
244                 if( !output_frame ) {
245                         output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
246                 }
247
248                 window_id = window->get_id();
249                 output_frame->set_opengl_state(VFrame::RAM);
250         }
251         else {
252                 output->get_transfers(edl,
253                         output_x1, output_y1, output_x2, output_y2,
254                         canvas_x1, canvas_y1, canvas_x2, canvas_y2,
255 // Canvas may be a different size than the temporary bitmap for pure software
256                         -1, -1);
257                 canvas_w = canvas_x2 - canvas_x1;
258                 canvas_h = canvas_y2 - canvas_y1;
259 // can the direct frame be used?
260                 int direct_supported =
261                         device->out_config->use_direct_x11 &&
262                         !output->xscroll && !output->yscroll &&
263                         output_x1 == 0 && output_x2 == device->out_w &&
264                         output_y1 == 0 && output_y2 == device->out_h;
265
266 // file wants direct frame but we need a temp
267                 if( !direct_supported && file_colormodel == BC_BGR8888 )
268                         file_colormodel = BC_RGB888;
269
270 // Conform existing bitmap to new colormodel and output size
271                 if( bitmap ) {
272 // printf("VDeviceX11::new_output_buffer %d bitmap=%dx%d canvas=%dx%d canvas=%dx%d\n",
273 // __LINE__, bitmap->get_w(), bitmap->get_h(), canvas_w, canvas_h,);
274                         int size_change = (
275                                 bitmap->get_w() != canvas_w ||
276                                 bitmap->get_h() != canvas_h );
277
278 // Restart if output size changed or output colormodel changed.
279 // May have to recreate if transferring between windowed and fullscreen.
280                         if( !color_model_selected ||
281                             file_colormodel != output_frame->get_color_model() ||
282                             (!bitmap->hardware_scaling() && size_change) ) {
283 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d prev "
284 // "file_colormodel=%d bitmap=%p output_frame=%p\n", __LINE__,
285 // file_colormodel, output_frame->get_color_model(), bitmap, output_frame);
286                                 delete bitmap;        bitmap = 0;
287                                 delete output_frame;  output_frame = 0;
288 // Clear borders if size changed
289                                 if( size_change )
290                                         output->clear_borders(edl);
291                         }
292                 }
293
294 // Create new bitmap
295                 if( !bitmap ) {
296                         int use_direct = 0;
297                         bitmap_type = BITMAP_TEMP;
298 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
299 // __LINE__, file_colormodel, display_colormodel);
300
301 // Try hardware accelerated
302                         switch( display_colormodel ) {
303 // blit from the codec directly to the window, using the standard X11 color model.
304 // Must scale in the codec.  No cropping
305                         case BC_BGR8888:
306                                 if( direct_supported ) {
307                                         bitmap_type = BITMAP_PRIMARY;
308                                         use_direct = 1;
309                                 }
310                                 break;
311
312                         case BC_YUV420P:
313                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
314                                     window->accel_available(display_colormodel, 0) &&
315                                     !output->use_scrollbars )
316                                         bitmap_type = BITMAP_PRIMARY;
317                                 break;
318
319                         case BC_YUV422P:
320                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
321                                     window->accel_available(display_colormodel, 0) &&
322                                     !output->use_scrollbars )
323                                         bitmap_type = BITMAP_PRIMARY;
324                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
325                                     window->accel_available(BC_YUV422, 0) ) {
326                                         bitmap = new BC_Bitmap(window,
327                                                 device->out_w, device->out_h, BC_YUV422, 1);
328                                 }
329                                 break;
330
331                         case BC_YUV422:
332                                 if( device->out_config->driver == PLAYBACK_X11_XV &&
333                                     window->accel_available(display_colormodel, 0) &&
334                                     !output->use_scrollbars ) {
335                                         bitmap_type = BITMAP_PRIMARY;
336                                 }
337                                 else if( device->out_config->driver == PLAYBACK_X11_XV &&
338                                     window->accel_available(BC_YUV422P, 0) ) {
339                                         bitmap = new BC_Bitmap(window,
340                                                 device->out_w, device->out_h, BC_YUV422P, 1);
341                                 }
342                                 break;
343                         }
344                         if( bitmap_type == BITMAP_PRIMARY ) {
345                                 int bitmap_w = use_direct ? canvas_w : device->out_w;
346                                 int bitmap_h = use_direct ? canvas_h : device->out_h;
347                                 bitmap = new BC_Bitmap(window,
348                                         bitmap_w, bitmap_h,  display_colormodel, -1);
349                                 output_frame = new VFrame(bitmap,
350                                         bitmap_w, bitmap_h, display_colormodel, -1);
351                         }
352 // Make an intermediate frame
353                         if( !bitmap ) {
354                                 display_colormodel = window->get_color_model();
355 // printf("VDeviceX11::new_output_buffer %d creating temp display_colormodel=%d "
356 // "file_colormodel=%d %dx%d %dx%d %dx%d\n", __LINE__,
357 // display_colormodel, file_colormodel, device->out_w, device->out_h,
358 // window->get_w(), window->get_h(), canvas_w, canvas_h);
359                                 bitmap = new BC_Bitmap(window,
360                                         canvas_w, canvas_h, display_colormodel, 1);
361                                 bitmap_type = BITMAP_TEMP;
362                         }
363
364                         if( bitmap_type == BITMAP_TEMP ) {
365 // Intermediate frame
366 //printf("VDeviceX11::new_output_buffer %d creating output_frame\n", __LINE__);
367                                 output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
368                         }
369                         color_model_selected = 1;
370                 }
371                 else if( bitmap_type == BITMAP_PRIMARY ) {
372                         output_frame->set_memory(bitmap);
373                 }
374         }
375
376         *result = output_frame;
377 //printf("VDeviceX11::new_output_buffer 10 %d\n", window->get_window_lock());
378
379         output->unlock_canvas();
380 }
381
382
383 int VDeviceX11::start_playback()
384 {
385 // Record window is initialized when its monitor starts.
386         if( !device->single_frame )
387                 output->start_video();
388         return 0;
389 }
390
391 int VDeviceX11::stop_playback()
392 {
393         if( !device->single_frame )
394                 output->stop_video();
395 // Record window goes back to monitoring
396 // get the last frame played and store it in the video_out
397         return 0;
398 }
399
400 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
401 {
402         BC_WindowBase *window =
403                 output->lock_canvas("VDeviceX11::write_buffer");
404 //      if( device->out_config->driver == PLAYBACK_X11_GL &&
405 //          output_frame->get_color_model() != BC_RGB888 ) {
406 // this is handled by overlay call in virtualvnode, using flatten alpha
407 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
408 //      }
409
410 // printf("VDeviceX11::write_buffer %d %d bitmap_type=%d\n",
411 // __LINE__,
412 // window->get_video_on(),
413 // bitmap_type);
414
415 //      int use_bitmap_extents = 0;
416 //      canvas_w = -1;  canvas_h = -1;
417 // // Canvas may be a different size than the temporary bitmap for pure software
418 //      if( bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling() ) {
419 //              canvas_w = bitmap->get_w();
420 //              canvas_h = bitmap->get_h();
421 //      }
422 //
423 //      output->get_transfers(edl,
424 //              output_x1, output_y1, output_x2, output_y2,
425 //              canvas_x1, canvas_y1, canvas_x2, canvas_y2,
426 //              canvas_w, canvas_h);
427
428 // Convert colormodel
429         if( bitmap_type == BITMAP_TEMP ) {
430 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
431 //   output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
432 // fflush(stdout);
433
434 // printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
435 // printf("VDeviceX11::write_buffer %d input color_model=%d output color_model=%d\n",
436 // __LINE__, output_channels->get_color_model(), bitmap->get_color_model());
437                 if( bitmap->hardware_scaling() ) {
438                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
439                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
440                                 0, 0, output_channels->get_w(), output_channels->get_h(),
441                                 0, 0, bitmap->get_w(), bitmap->get_h(),
442                                 output_channels->get_color_model(), bitmap->get_color_model(),
443                                 -1, output_channels->get_w(), bitmap->get_w());
444                 }
445                 else {
446                         BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
447                                 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
448                                 (int)output_x1, (int)output_y1, (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
449                                 0, 0, (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
450                                 output_channels->get_color_model(), bitmap->get_color_model(),
451                                 -1, output_channels->get_w(), bitmap->get_w());
452                 }
453         }
454
455 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
456 //for( i = 0; i < 1000; i += 4 ) bitmap->get_data()[i] = 128;
457 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
458 //      bitmap->get_color_model(),
459 //      output->get_color_model());fflush(stdout);
460
461 // printf("VDeviceX11::write_buffer %d %dx%d %f %f %f %f -> %f %f %f %f\n",
462 // __LINE__, // output->w, output->h,
463 // output_x1, output_y1, output_x2, output_y2,
464 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
465
466 // Cause X server to display it
467         if( device->out_config->driver == PLAYBACK_X11_GL ) {
468 // Output is drawn in close_all if no video.
469                 if( window->get_video_on() ) {
470                         canvas_w = -1;  canvas_h = -1;
471 // Canvas may be a different size than the temporary bitmap for pure software
472                         if( bitmap_type == BITMAP_TEMP &&
473                                 !bitmap->hardware_scaling() ) {
474                                 canvas_w = bitmap->get_w();
475                                 canvas_h = bitmap->get_h();
476                         }
477
478                         output->get_transfers(edl,
479                                 output_x1, output_y1, output_x2, output_y2,
480                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
481                                 canvas_w, canvas_h);
482
483 //printf("VDeviceX11::write_buffer %d\n", __LINE__);
484 // Draw output frame directly.  Not used for compositing.
485                         output->unlock_canvas();
486                         output->mwindow->playback_3d->write_buffer(output, output_frame,
487                                 output_x1, output_y1, output_x2, output_y2,
488                                 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
489                                 is_cleared);
490                         is_cleared = 0;
491                         return 0;
492                 }
493         }
494         else {
495                 if( bitmap->hardware_scaling() ) {
496                         window->draw_bitmap(bitmap, !device->single_frame,
497                                 (int)canvas_x1, (int)canvas_y1,
498                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
499                                 (int)output_x1, (int)output_y1,
500                                 (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
501                                 0);
502                 }
503                 else {
504 //printf("VDeviceX11::write_buffer %d x=%d y=%d w=%d h=%d\n",
505 // __LINE__, (int)canvas_x1, (int)canvas_y1,
506 // window->get_w(), window->get_h());
507                         window->draw_bitmap(bitmap, !device->single_frame,
508                                 (int)canvas_x1, (int)canvas_y1,
509                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
510                                 0, 0,
511                                 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
512                                 0);
513 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
514                 }
515         }
516
517         output->unlock_canvas();
518         return 0;
519 }
520
521
522 void VDeviceX11::clear_output()
523 {
524         is_cleared = 1;
525 // clear front and back buffers
526         output->mwindow->playback_3d->clear_output(output, 0);
527         output->mwindow->playback_3d->clear_output(output, output_frame);
528 }
529
530
531 void VDeviceX11::clear_input(VFrame *frame)
532 {
533         this->output->mwindow->playback_3d->clear_input(this->output, frame);
534 }
535
536 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
537 {
538         this->output->mwindow->playback_3d->convert_cmodel(this->output,
539                 output, 
540                 dst_cmodel);
541 }
542
543 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
544         float in_x1, float in_y1, float in_x2, float in_y2,
545         float out_x1, float out_y1, float out_x2, float out_y2)
546 {
547         this->output->mwindow->playback_3d->do_camera(this->output,
548                 output, input,
549                 in_x1, in_y1, in_x2, in_y2,
550                 out_x1, out_y1, out_x2, out_y2);
551 }
552
553
554 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
555 {
556         this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
557 }
558
559 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
560 {
561         if( strncmp(BC_DisplayInfo::get_gl_shader_version(), "4.3", 3) < 0 )
562                 return 0;
563         Auto *current = 0;
564         MaskAuto *keyframe = (MaskAuto*)keyframe_set->
565                 get_prev_auto(start_position_project, PLAY_FORWARD, current);
566         return keyframe->disable_opengl_masking ? 0 : 1;
567 }
568
569 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
570                 MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto)
571 {
572         this->output->mwindow->playback_3d->do_mask(output, output_temp,
573                 start_position_project, keyframe_set, keyframe, default_auto);
574 }
575
576 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
577                 float in_x1, float in_y1, float in_x2, float in_y2,
578                 float out_x1, float out_y1, float out_x2, float out_y2,
579                 float alpha, int mode, EDL *edl, int is_nested)
580 {
581         int interpolation_type = edl->session->interpolation_type;
582         output->mwindow->playback_3d->overlay(output, input,
583                 in_x1, in_y1, in_x2, in_y2,
584                 out_x1, out_y1, out_x2, out_y2, alpha, // 0 - 1
585                 mode, interpolation_type, output_frame, is_nested);
586 }
587
588 void VDeviceX11::run_plugin(PluginClient *client)
589 {
590         output->mwindow->playback_3d->run_plugin(output, client);
591 }
592
593 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
594 {
595         output->mwindow->playback_3d->copy_from(output, dst, src, 1);
596 }
597