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