4 * Copyright (C) 2008 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 "bcsignals.h"
27 #include "bccmodels.h"
29 #include "edlsession.h"
30 #include "maskautos.h"
33 #include "playback3d.h"
34 #include "playbackconfig.h"
35 #include "preferences.h"
36 #include "recordconfig.h"
37 #include "strategies.inc"
38 #include "vdevicex11.h"
40 #include "videodevice.h"
41 #include "videowindow.h"
42 #include "videowindowgui.h"
47 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
51 this->output = output;
54 VDeviceX11::~VDeviceX11()
59 int VDeviceX11::reset_parameters()
76 color_model_selected = 0;
81 int VDeviceX11::open_input()
83 //printf("VDeviceX11::open_input 1\n");
84 capture_bitmap = new BC_Capture(device->in_config->w,
86 device->in_config->screencapture_display);
87 //printf("VDeviceX11::open_input 2\n");
92 int VDeviceX11::open_output()
96 output->lock_canvas("VDeviceX11::open_output");
97 output->get_canvas()->lock_window("VDeviceX11::open_output");
98 if(!device->single_frame)
99 output->start_video();
101 output->start_single();
102 output->get_canvas()->unlock_window();
104 // Enable opengl in the first routine that needs it, to reduce the complexity.
106 output->unlock_canvas();
112 int VDeviceX11::output_visible()
114 if(!output) return 0;
116 output->lock_canvas("VDeviceX11::output_visible");
117 if(output->get_canvas()->get_hidden())
119 output->unlock_canvas();
124 output->unlock_canvas();
130 int VDeviceX11::close_all()
134 output->lock_canvas("VDeviceX11::close_all 1");
135 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
138 if(output && output_frame)
140 // Copy our output frame buffer to the canvas's permanent frame buffer.
141 // They must be different buffers because the output frame is being written
142 // while the user is redrawing the canvas frame buffer over and over.
144 int use_opengl = device->out_config->driver == PLAYBACK_X11_GL &&
145 output_frame->get_opengl_state() == VFrame::SCREEN;
146 int best_color_model = output_frame->get_color_model();
148 // OpenGL does YUV->RGB in the compositing step
150 best_color_model = BC_RGB888;
152 if(output->refresh_frame &&
153 (output->refresh_frame->get_w() != device->out_w ||
154 output->refresh_frame->get_h() != device->out_h ||
155 output->refresh_frame->get_color_model() != best_color_model))
157 delete output->refresh_frame;
158 output->refresh_frame = 0;
161 if(!output->refresh_frame)
163 output->refresh_frame = new VFrame(0, -1,
164 device->out_w, device->out_h,
165 best_color_model, -1);
170 output->get_canvas()->unlock_window();
171 output->unlock_canvas();
173 output->mwindow->playback_3d->copy_from(output,
174 output->refresh_frame, output_frame, 0);
175 output->lock_canvas("VDeviceX11::close_all 2");
176 output->get_canvas()->lock_window("VDeviceX11::close_all 2");
179 output->refresh_frame->copy_from(output_frame);
181 // // Update the status bug
182 // if(!device->single_frame)
184 // output->stop_video();
188 // output->stop_single();
191 // Draw the first refresh with new frame.
192 // Doesn't work if video and openGL because OpenGL doesn't have
193 // the output buffer for video.
194 // Not necessary for any case if we mandate a frame advance after
196 if(/* device->out_config->driver != PLAYBACK_X11_GL ||
197 */ device->single_frame)
198 output->draw_refresh();
216 if(capture_bitmap) delete capture_bitmap;
221 // Update the status bug
222 if(!device->single_frame)
224 output->stop_video();
228 output->stop_single();
231 output->get_canvas()->unlock_window();
232 output->unlock_canvas();
240 int VDeviceX11::read_buffer(VFrame *frame)
242 capture_bitmap->capture_frame(frame, device->input_x, device->input_y);
247 int VDeviceX11::get_best_colormodel(Asset *asset)
253 int VDeviceX11::get_best_colormodel(int colormodel)
257 if(device->out_config->driver == PLAYBACK_X11_GL)
259 if(colormodel == BC_RGB888 ||
260 colormodel == BC_RGBA8888 ||
261 colormodel == BC_YUV888 ||
262 colormodel == BC_YUVA8888 ||
263 colormodel == BC_RGB_FLOAT ||
264 colormodel == BC_RGBA_FLOAT)
271 if(!device->single_frame)
283 // 2 more colormodels are supported by OpenGL
284 if(device->out_config->driver == PLAYBACK_X11_GL)
286 if(colormodel == BC_RGB_FLOAT ||
287 colormodel == BC_RGBA_FLOAT)
303 output->lock_canvas("VDeviceX11::get_best_colormodel");
304 result = output->get_canvas()->get_color_model();
305 output->unlock_canvas();
314 void VDeviceX11::new_output_buffer(VFrame **result, int colormodel)
316 //printf("VDeviceX11::new_output_buffer 1\n");
317 output->lock_canvas("VDeviceX11::new_output_buffer");
318 output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
320 // Get the best colormodel the display can handle.
321 int best_colormodel = get_best_colormodel(colormodel);
323 // Only create OpenGL Pbuffer and texture.
324 if(device->out_config->driver == PLAYBACK_X11_GL)
326 // Create bitmap for initial load into texture.
327 // Not necessary to do through Playback3D.....yet
330 output_frame = new VFrame(0, -1,
331 device->out_w, device->out_h,
333 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 1");
336 window_id = output->get_canvas()->get_id();
337 output_frame->set_opengl_state(VFrame::RAM);
341 // Conform existing bitmap to new colormodel and output size
344 // Restart if output size changed or output colormodel changed.
345 // May have to recreate if transferring between windowed and fullscreen.
346 if(!color_model_selected ||
347 (!bitmap->hardware_scaling() &&
348 (bitmap->get_w() != output->get_canvas()->get_w() ||
349 bitmap->get_h() != output->get_canvas()->get_h())) ||
350 colormodel != output_frame->get_color_model())
352 int size_change = (bitmap->get_w() != output->get_canvas()->get_w() ||
353 bitmap->get_h() != output->get_canvas()->get_h());
354 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
360 // Blank only if size changed
363 output->get_canvas()->set_color(BLACK);
364 output->get_canvas()->draw_box(0, 0, output->w, output->h);
365 output->get_canvas()->flash();
369 // Update the ring buffer
370 if(bitmap_type == BITMAP_PRIMARY)
372 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
373 output_frame->set_memory(bitmap);
380 // Try hardware accelerated
381 switch(best_colormodel)
384 if(device->out_config->driver == PLAYBACK_X11_XV &&
385 output->get_canvas()->accel_available(best_colormodel, 0) &&
386 !output->use_scrollbars)
388 bitmap = new BC_Bitmap(output->get_canvas(),
389 device->out_w, device->out_h,
391 output_frame = new VFrame(bitmap,
392 device->out_w, device->out_h,
393 best_colormodel, -1);
394 bitmap_type = BITMAP_PRIMARY;
399 if(device->out_config->driver == PLAYBACK_X11_XV &&
400 output->get_canvas()->accel_available(best_colormodel, 0) &&
401 !output->use_scrollbars)
403 bitmap = new BC_Bitmap(output->get_canvas(),
404 device->out_w, device->out_h,
406 output_frame = new VFrame(bitmap,
407 device->out_w, device->out_h,
408 best_colormodel, -1);
409 bitmap_type = BITMAP_PRIMARY;
412 if(device->out_config->driver == PLAYBACK_X11_XV &&
413 output->get_canvas()->accel_available(BC_YUV422, 0))
415 bitmap = new BC_Bitmap(output->get_canvas(),
420 bitmap_type = BITMAP_TEMP;
425 if(device->out_config->driver == PLAYBACK_X11_XV &&
426 output->get_canvas()->accel_available(best_colormodel, 0) &&
427 !output->use_scrollbars)
429 bitmap = new BC_Bitmap(output->get_canvas(),
430 device->out_w, device->out_h,
432 output_frame = new VFrame(bitmap,
433 device->out_w, device->out_h,
434 best_colormodel, -1);
435 bitmap_type = BITMAP_PRIMARY;
438 if(device->out_config->driver == PLAYBACK_X11_XV &&
439 output->get_canvas()->accel_available(BC_YUV422P, 0))
441 bitmap = new BC_Bitmap(output->get_canvas(),
442 device->out_w, device->out_h,
444 bitmap_type = BITMAP_TEMP;
449 // Try default colormodel
452 best_colormodel = output->get_canvas()->get_color_model();
453 bitmap = new BC_Bitmap(output->get_canvas(),
454 output->get_canvas()->get_w(),
455 output->get_canvas()->get_h(),
457 bitmap_type = BITMAP_TEMP;
460 if(bitmap_type == BITMAP_TEMP)
462 // Intermediate frame
463 output_frame = new VFrame(0, -1,
464 device->out_w, device->out_h,
466 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 2");
467 bitmap_type = BITMAP_TEMP;
469 color_model_selected = 1;
473 *result = output_frame;
474 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
476 output->get_canvas()->unlock_window();
477 output->unlock_canvas();
481 int VDeviceX11::start_playback()
483 // Record window is initialized when its monitor starts.
484 if(!device->single_frame)
485 output->start_video();
489 int VDeviceX11::stop_playback()
491 if(!device->single_frame)
492 output->stop_video();
493 // Record window goes back to monitoring
494 // get the last frame played and store it in the video_out
498 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
500 // The reason for not drawing single frame is that it is _always_ drawn
501 // when drawing draw_refresh in cwindowgui and vwindowgui
502 if (device->single_frame)
505 output->lock_canvas("VDeviceX11::write_buffer");
506 output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
508 // Canvas may be a different size than the temporary bitmap for pure software
510 if(bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) {
511 xfr_w = bitmap->get_w();
512 xfr_h = bitmap->get_h();
517 //printf("VDeviceX11::write_buffer %d %d\n", __LINE__, output->get_canvas()->get_video_on());
518 output->get_transfers(edl, output_x1, output_y1, output_x2, output_y2,
519 canvas_x1, canvas_y1, canvas_x2, canvas_y2, xfr_w, xfr_h);
521 // Convert colormodel
523 // this is handled by overlay call in virtualvnode, using flatten alpha
524 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
525 if(device->out_config->driver == PLAYBACK_X11_GL &&
526 output_frame->get_color_model() != BC_RGB888) {
527 int cmodel = BC_RGB888;
528 output->get_canvas()->unlock_window();
529 output->unlock_canvas();
530 output->mwindow->playback_3d->convert_cmodel(output, output_frame, cmodel);
531 output_frame->reallocate(0,-1,0,0,0,output_frame->get_w(),output_frame->get_h(),cmodel,-1);
532 output->lock_canvas("VDeviceX11::write_buffer 3");
533 output->get_canvas()->lock_window("VDeviceX11::write_buffer 3");
537 if(bitmap_type == BITMAP_TEMP) {
538 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
539 // output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h );
541 //printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
544 if(bitmap->hardware_scaling())
546 BC_CModels::transfer(bitmap->get_row_pointers(),
547 output_channels->get_rows(), 0, 0, 0,
548 output_channels->get_y(),
549 output_channels->get_u(),
550 output_channels->get_v(),
552 output_channels->get_w(),
553 output_channels->get_h(),
557 output_channels->get_color_model(),
558 bitmap->get_color_model(),
560 output_channels->get_w(),
565 BC_CModels::transfer(bitmap->get_row_pointers(),
566 output_channels->get_rows(), 0, 0, 0,
567 output_channels->get_y(),
568 output_channels->get_u(),
569 output_channels->get_v(),
572 (int)(output_x2 - output_x1),
573 (int)(output_y2 - output_y1),
575 (int)(canvas_x2 - canvas_x1),
576 (int)(canvas_y2 - canvas_y1),
577 output_channels->get_color_model(),
578 bitmap->get_color_model(),
580 output_channels->get_w(),
585 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
586 //for(i = 0; i < 1000; i += 4) bitmap->get_data()[i] = 128;
587 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
588 // bitmap->get_color_model(), output->get_color_model());
590 //printf("VDeviceX11::write_buffer 2 %d %d, %f %f %f %f -> %f %f %f %f\n",
591 // output->w, output->h, output_x1, output_y1, output_x2, output_y2,
592 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
594 // Cause X server to display it
595 if(device->out_config->driver == PLAYBACK_X11_GL)
597 // Output is drawn in close_all if no video.
598 if(output->get_canvas()->get_video_on())
600 // Draw output frame directly. Not used for compositing.
601 output->get_canvas()->unlock_window();
602 output->unlock_canvas();
603 output->mwindow->playback_3d->write_buffer(output,
604 output_frame, output_x1, output_y1, output_x2, output_y2,
605 canvas_x1, canvas_y1, canvas_x2, canvas_y2, is_cleared);
607 output->lock_canvas("VDeviceX11::write_buffer 2");
608 output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
612 if(bitmap->hardware_scaling())
614 output->get_canvas()->draw_bitmap(bitmap,
615 !device->single_frame,
616 (int)canvas_x1, (int)canvas_y1,
617 (int)(canvas_x2 - canvas_x1),
618 (int)(canvas_y2 - canvas_y1),
619 (int)output_x1, (int)output_y1,
620 (int)(output_x2 - output_x1),
621 (int)(output_y2 - output_y1),
626 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
627 output->get_canvas()->draw_bitmap(bitmap,
628 !device->single_frame,
629 (int)canvas_x1, (int)canvas_y1,
630 (int)(canvas_x2 - canvas_x1),
631 (int)(canvas_y2 - canvas_y1),
633 (int)(canvas_x2 - canvas_x1),
634 (int)(canvas_y2 - canvas_y1),
636 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
640 output->get_canvas()->unlock_window();
641 output->unlock_canvas();
646 void VDeviceX11::clear_output()
650 output->mwindow->playback_3d->clear_output(output,
651 output->get_canvas()->get_video_on() ? 0 : output_frame);
656 void VDeviceX11::clear_input(VFrame *frame)
658 this->output->mwindow->playback_3d->clear_input(this->output, frame);
661 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
663 this->output->mwindow->playback_3d->convert_cmodel(this->output,
668 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
669 float in_x1, float in_y1, float in_x2, float in_y2,
670 float out_x1, float out_y1, float out_x2, float out_y2)
672 this->output->mwindow->playback_3d->do_camera(
673 this->output, output, input,
674 in_x1, in_y1, in_x2, in_y2,
675 out_x1, out_y1, out_x2, out_y2);
679 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
681 this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
684 bool VDeviceX11::can_mask(int64_t start_position_project, MaskAutos *keyframe_set)
687 MaskAuto *keyframe = (MaskAuto*)keyframe_set->
688 get_prev_auto(start_position_project, PLAY_FORWARD, current);
689 return keyframe->disable_opengl_masking ? 0 : 1;
692 void VDeviceX11::do_mask(VFrame *output_temp,
693 int64_t start_position_project, MaskAutos *keyframe_set,
694 MaskAuto *keyframe, MaskAuto *default_auto)
696 this->output->mwindow->playback_3d->do_mask(output,
697 output_temp, start_position_project,
698 keyframe_set, keyframe, default_auto);
701 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
702 // This is the transfer from track to output frame
703 float in_x1, float in_y1, float in_x2, float in_y2,
704 float out_x1, float out_y1, float out_x2, float out_y2,
705 float alpha /*0-1*/, int mode, EDL *edl, int is_nested)
707 int interpolation_type = edl->session->interpolation_type;
709 // printf("VDeviceX11::overlay 1:\n"
710 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
711 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
712 // in_x1, in_y1, in_x2, in_y2,
713 // out_x1, out_y1, out_x2, out_y2);
714 // Convert node coords to canvas coords in here
716 // If single frame playback or nested EDL, use full sized PBuffer as output.
717 if(device->single_frame || is_nested > 0)
719 output->mwindow->playback_3d->overlay(output, input,
720 in_x1, in_y1, in_x2, in_y2,
721 out_x1, out_y1, out_x2, out_y2,
722 alpha, mode, interpolation_type,
723 output_frame, is_nested);
724 // printf("VDeviceX11::overlay 1 %p %d %d %d\n",
726 // output_frame->get_w(),
727 // output_frame->get_h(),
728 // output_frame->get_opengl_state());
732 output->lock_canvas("VDeviceX11::overlay");
733 output->get_canvas()->lock_window("VDeviceX11::overlay");
735 // This is the transfer from output frame to canvas
736 output->get_transfers(edl,
737 output_x1, output_y1, output_x2, output_y2,
738 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
741 output->get_canvas()->unlock_window();
742 output->unlock_canvas();
745 // Get transfer from track to canvas
746 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
747 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
748 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
749 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
752 // Get coordinates of canvas relative to track frame
753 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
754 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
755 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
756 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
758 // Clamp canvas coords to track boundary
761 float difference = -track_x1;
762 track_x1 += difference;
763 canvas_x1 += difference * track_xscale * canvas_xscale;
767 float difference = -track_y1;
768 track_y1 += difference;
769 canvas_y1 += difference * track_yscale * canvas_yscale;
772 if(track_x2 > input->get_w())
774 float difference = track_x2 - input->get_w();
775 track_x2 -= difference;
776 canvas_x2 -= difference * track_xscale * canvas_xscale;
778 if(track_y2 > input->get_h())
780 float difference = track_y2 - input->get_h();
781 track_y2 -= difference;
782 canvas_y2 -= difference * track_yscale * canvas_yscale;
785 // Overlay directly from track buffer to canvas, skipping output buffer
786 if(track_x2 > track_x1 && track_y2 > track_y1 &&
787 canvas_x2 > canvas_x1 && canvas_y2 > canvas_y1)
789 output->mwindow->playback_3d->overlay(output, input,
790 track_x1, track_y1, track_x2, track_y2,
791 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
792 alpha, mode, interpolation_type, 0, is_nested);
797 void VDeviceX11::run_plugin(PluginClient *client)
799 output->mwindow->playback_3d->run_plugin(output, client);
802 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
804 output->mwindow->playback_3d->copy_from(output, dst, src, 1);