4 * Copyright (C) 2008-2017 Adam Williams <broadcast at earthling dot net>
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.
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.
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
24 #include "bccapture.h"
25 #include "bccmodels.h"
26 #include "bcdisplayinfo.h"
27 #include "bcsignals.h"
30 #include "edlsession.h"
33 #include "maskautos.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"
43 #include "videodevice.h"
44 #include "videowindow.h"
45 #include "videowindowgui.h"
50 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
54 this->output = output;
57 VDeviceX11::~VDeviceX11()
62 int VDeviceX11::reset_parameters()
79 color_model_selected = 0;
84 int VDeviceX11::open_input()
86 //printf("VDeviceX11::open_input 1\n");
87 capture_bitmap = new BC_Capture(device->in_config->w,
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);
98 int VDeviceX11::open_output()
100 if( !output ) return 0;
101 BC_WindowBase *window =
102 output->lock_canvas("VDeviceX11::open_output");
104 if( !device->single_frame )
105 output->start_video();
107 output->start_single();
109 output->unlock_canvas();
114 int VDeviceX11::output_visible()
118 BC_WindowBase *window =
119 output->lock_canvas("VDeviceX11::output_visible");
120 ret = !window || window->get_hidden() ? 0 : 1;
121 output->unlock_canvas();
127 int VDeviceX11::close_all()
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();
137 output->stop_single();
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);
146 delete bitmap; bitmap = 0;
147 delete output_frame; output_frame = 0;
148 delete capture_bitmap; capture_bitmap = 0;
151 output->unlock_canvas();
158 int VDeviceX11::read_buffer(VFrame *frame)
160 capture_bitmap->bars_reposition(
161 device->input_x, device->input_y,
162 device->in_config->w, device->in_config->h);
164 capture_bitmap->capture_frame(frame,
165 device->input_x, device->input_y, device->do_cursor);
170 int VDeviceX11::get_best_colormodel(Asset *asset)
172 return File::get_best_colormodel(asset, SCREENCAPTURE);
177 int VDeviceX11::get_display_colormodel(int file_colormodel)
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;
194 if( !device->single_frame ) {
195 switch( file_colormodel ) {
199 result = file_colormodel;
205 switch( file_colormodel ) {
212 result = file_colormodel;
216 BC_WindowBase *window = output->get_canvas();
217 result = window ? window->get_color_model() : BC_RGB888;
226 void VDeviceX11::new_output_buffer(VFrame **result, int file_colormodel, EDL *edl)
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);
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);
245 window_id = window->get_id();
246 output_frame->set_opengl_state(VFrame::RAM);
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
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;
263 // file wants direct frame but we need a temp
264 if( !direct_supported && file_colormodel == BC_BGR8888 )
265 file_colormodel = BC_RGB888;
267 // Conform existing bitmap to new colormodel and output size
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,);
272 bitmap->get_w() != canvas_w ||
273 bitmap->get_h() != canvas_h );
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
287 //printf("VDeviceX11::new_output_buffer %d w=%d h=%d "
288 // "canvas_x1=%d canvas_y1=%d canvas_x2=%d canvas_y2=%d\n",
289 // __LINE__, // (int)output->w, (int)output->h,
290 // (int)canvas_x1, (int)canvas_y1, (int)canvas_x2, (int)canvas_y2);
291 window->set_color(BLACK);
293 if( canvas_y1 > 0 ) {
294 window->draw_box(0, 0, output->w, canvas_y1);
295 window->flash(0, 0, output->w, canvas_y1);
298 if( canvas_y2 < output->h ) {
299 window->draw_box(0, canvas_y2, output->w, output->h - canvas_y2);
300 window->flash(0, canvas_y2, output->w, output->h - canvas_y2);
303 if( canvas_x1 > 0 ) {
304 window->draw_box(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
305 window->flash(0, canvas_y1, canvas_x1, canvas_y2 - canvas_y1);
308 if( canvas_x2 < output->w ) {
309 window->draw_box(canvas_x2, canvas_y1,
310 output->w - canvas_x2, canvas_y2 - canvas_y1);
311 window->flash(canvas_x2, canvas_y1,
312 output->w - canvas_x2, canvas_y2 - canvas_y1);
321 bitmap_type = BITMAP_TEMP;
322 //printf("VDeviceX11::new_output_buffer %d file_colormodel=%d display_colormodel=%d\n",
323 // __LINE__, file_colormodel, display_colormodel);
325 // Try hardware accelerated
326 switch( display_colormodel ) {
327 // blit from the codec directly to the window, using the standard X11 color model.
328 // Must scale in the codec. No cropping
330 if( direct_supported ) {
331 bitmap_type = BITMAP_PRIMARY;
337 if( device->out_config->driver == PLAYBACK_X11_XV &&
338 window->accel_available(display_colormodel, 0) &&
339 !output->use_scrollbars )
340 bitmap_type = BITMAP_PRIMARY;
344 if( device->out_config->driver == PLAYBACK_X11_XV &&
345 window->accel_available(display_colormodel, 0) &&
346 !output->use_scrollbars )
347 bitmap_type = BITMAP_PRIMARY;
348 else if( device->out_config->driver == PLAYBACK_X11_XV &&
349 window->accel_available(BC_YUV422, 0) ) {
350 bitmap = new BC_Bitmap(window,
351 device->out_w, device->out_h, BC_YUV422, 1);
356 if( device->out_config->driver == PLAYBACK_X11_XV &&
357 window->accel_available(display_colormodel, 0) &&
358 !output->use_scrollbars ) {
359 bitmap_type = BITMAP_PRIMARY;
361 else if( device->out_config->driver == PLAYBACK_X11_XV &&
362 window->accel_available(BC_YUV422P, 0) ) {
363 bitmap = new BC_Bitmap(window,
364 device->out_w, device->out_h, BC_YUV422P, 1);
368 if( bitmap_type == BITMAP_PRIMARY ) {
369 int bitmap_w = use_direct ? canvas_w : device->out_w;
370 int bitmap_h = use_direct ? canvas_h : device->out_h;
371 bitmap = new BC_Bitmap(window,
372 bitmap_w, bitmap_h, display_colormodel, -1);
373 output_frame = new VFrame(bitmap,
374 bitmap_w, bitmap_h, display_colormodel, -1);
376 // Make an intermediate frame
378 display_colormodel = window->get_color_model();
379 // printf("VDeviceX11::new_output_buffer %d creating temp display_colormodel=%d "
380 // "file_colormodel=%d %dx%d %dx%d %dx%d\n", __LINE__,
381 // display_colormodel, file_colormodel, device->out_w, device->out_h,
382 // window->get_w(), window->get_h(), canvas_w, canvas_h);
383 bitmap = new BC_Bitmap(window,
384 canvas_w, canvas_h, display_colormodel, 1);
385 bitmap_type = BITMAP_TEMP;
388 if( bitmap_type == BITMAP_TEMP ) {
389 // Intermediate frame
390 //printf("VDeviceX11::new_output_buffer %d creating output_frame\n", __LINE__);
391 output_frame = new VFrame(device->out_w, device->out_h, file_colormodel);
393 color_model_selected = 1;
395 else if( bitmap_type == BITMAP_PRIMARY ) {
396 output_frame->set_memory(bitmap);
400 *result = output_frame;
401 //printf("VDeviceX11::new_output_buffer 10 %d\n", window->get_window_lock());
403 output->unlock_canvas();
407 int VDeviceX11::start_playback()
409 // Record window is initialized when its monitor starts.
410 if( !device->single_frame )
411 output->start_video();
415 int VDeviceX11::stop_playback()
417 if( !device->single_frame )
418 output->stop_video();
419 // Record window goes back to monitoring
420 // get the last frame played and store it in the video_out
424 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
426 BC_WindowBase *window =
427 output->lock_canvas("VDeviceX11::write_buffer");
428 // if( device->out_config->driver == PLAYBACK_X11_GL &&
429 // output_frame->get_color_model() != BC_RGB888 ) {
430 // this is handled by overlay call in virtualvnode, using flatten alpha
431 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
434 // printf("VDeviceX11::write_buffer %d %d bitmap_type=%d\n",
436 // window->get_video_on(),
439 // int use_bitmap_extents = 0;
440 // canvas_w = -1; canvas_h = -1;
441 // // Canvas may be a different size than the temporary bitmap for pure software
442 // if( bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling() ) {
443 // canvas_w = bitmap->get_w();
444 // canvas_h = bitmap->get_h();
447 // output->get_transfers(edl,
448 // output_x1, output_y1, output_x2, output_y2,
449 // canvas_x1, canvas_y1, canvas_x2, canvas_y2,
450 // canvas_w, canvas_h);
452 // Convert colormodel
453 if( bitmap_type == BITMAP_TEMP ) {
454 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
455 // output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h);
458 // printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
459 // printf("VDeviceX11::write_buffer %d input color_model=%d output color_model=%d\n",
460 // __LINE__, output_channels->get_color_model(), bitmap->get_color_model());
461 if( bitmap->hardware_scaling() ) {
462 BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
463 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
464 0, 0, output_channels->get_w(), output_channels->get_h(),
465 0, 0, bitmap->get_w(), bitmap->get_h(),
466 output_channels->get_color_model(), bitmap->get_color_model(),
467 -1, output_channels->get_w(), bitmap->get_w());
470 BC_CModels::transfer(bitmap->get_row_pointers(), output_channels->get_rows(), 0, 0, 0,
471 output_channels->get_y(), output_channels->get_u(), output_channels->get_v(),
472 (int)output_x1, (int)output_y1, (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
473 0, 0, (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
474 output_channels->get_color_model(), bitmap->get_color_model(),
475 -1, output_channels->get_w(), bitmap->get_w());
479 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
480 //for( i = 0; i < 1000; i += 4 ) bitmap->get_data()[i] = 128;
481 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
482 // bitmap->get_color_model(),
483 // output->get_color_model());fflush(stdout);
485 // printf("VDeviceX11::write_buffer %d %dx%d %f %f %f %f -> %f %f %f %f\n",
486 // __LINE__, // output->w, output->h,
487 // output_x1, output_y1, output_x2, output_y2,
488 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
490 // Cause X server to display it
491 if( device->out_config->driver == PLAYBACK_X11_GL ) {
492 // Output is drawn in close_all if no video.
493 if( window->get_video_on() ) {
494 canvas_w = -1; canvas_h = -1;
495 // Canvas may be a different size than the temporary bitmap for pure software
496 if( bitmap_type == BITMAP_TEMP &&
497 !bitmap->hardware_scaling() ) {
498 canvas_w = bitmap->get_w();
499 canvas_h = bitmap->get_h();
502 output->get_transfers(edl,
503 output_x1, output_y1, output_x2, output_y2,
504 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
507 //printf("VDeviceX11::write_buffer %d\n", __LINE__);
508 // Draw output frame directly. Not used for compositing.
509 output->unlock_canvas();
510 output->mwindow->playback_3d->write_buffer(output, output_frame,
511 output_x1, output_y1, output_x2, output_y2,
512 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
519 if( bitmap->hardware_scaling() ) {
520 window->draw_bitmap(bitmap, !device->single_frame,
521 (int)canvas_x1, (int)canvas_y1,
522 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
523 (int)output_x1, (int)output_y1,
524 (int)(output_x2 - output_x1), (int)(output_y2 - output_y1),
528 //printf("VDeviceX11::write_buffer %d x=%d y=%d w=%d h=%d\n",
529 // __LINE__, (int)canvas_x1, (int)canvas_y1,
530 // window->get_w(), window->get_h());
531 window->draw_bitmap(bitmap, !device->single_frame,
532 (int)canvas_x1, (int)canvas_y1,
533 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
535 (int)(canvas_x2 - canvas_x1), (int)(canvas_y2 - canvas_y1),
537 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
541 output->unlock_canvas();
546 void VDeviceX11::clear_output()
549 output->mwindow->playback_3d->clear_output(output, 0);
550 output->mwindow->playback_3d->clear_output(output, output_frame);
554 void VDeviceX11::clear_input(VFrame *frame)
556 this->output->mwindow->playback_3d->clear_input(this->output, frame);
559 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
561 this->output->mwindow->playback_3d->convert_cmodel(this->output,
566 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
567 float in_x1, float in_y1, float in_x2, float in_y2,
568 float out_x1, float out_y1, float out_x2, float out_y2)
570 this->output->mwindow->playback_3d->do_camera(this->output,
572 in_x1, in_y1, in_x2, in_y2,
573 out_x1, out_y1, out_x2, out_y2);
577 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
579 this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
582 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
584 if( strncmp(BC_DisplayInfo::get_gl_shader_version(), "4.3", 3) < 0 )
587 MaskAuto *keyframe = (MaskAuto*)keyframe_set->
588 get_prev_auto(start_position_project, PLAY_FORWARD, current);
589 return keyframe->disable_opengl_masking ? 0 : 1;
592 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
593 MaskAutos *keyframe_set, MaskAuto *keyframe, MaskAuto *default_auto)
595 this->output->mwindow->playback_3d->do_mask(output, output_temp,
596 start_position_project, keyframe_set, keyframe, default_auto);
599 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
600 float in_x1, float in_y1, float in_x2, float in_y2,
601 float out_x1, float out_y1, float out_x2, float out_y2,
602 float alpha, int mode, EDL *edl, int is_nested)
604 int interpolation_type = edl->session->interpolation_type;
605 output->mwindow->playback_3d->overlay(output, input,
606 in_x1, in_y1, in_x2, in_y2,
607 out_x1, out_y1, out_x2, out_y2, alpha, // 0 - 1
608 mode, interpolation_type, output_frame, is_nested);
611 void VDeviceX11::run_plugin(PluginClient *client)
613 output->mwindow->playback_3d->run_plugin(output, client);
616 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
618 output->mwindow->playback_3d->copy_from(output, dst, src, 1);