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
23 #include "bccapture.h"
24 #include "bcsignals.h"
26 #include "colormodels.h"
28 #include "edlsession.h"
30 #include "playback3d.h"
31 #include "playbackconfig.h"
32 #include "preferences.h"
33 #include "recordconfig.h"
34 #include "strategies.inc"
35 #include "vdevicex11.h"
37 #include "videodevice.h"
38 #include "videowindow.h"
39 #include "videowindowgui.h"
44 VDeviceX11::VDeviceX11(VideoDevice *device, Canvas *output)
48 this->output = output;
51 VDeviceX11::~VDeviceX11()
56 int VDeviceX11::reset_parameters()
73 color_model_selected = 0;
78 int VDeviceX11::open_input()
80 //printf("VDeviceX11::open_input 1\n");
81 capture_bitmap = new BC_Capture(device->in_config->w,
83 device->in_config->screencapture_display);
84 //printf("VDeviceX11::open_input 2\n");
89 int VDeviceX11::open_output()
93 output->lock_canvas("VDeviceX11::open_output");
94 output->get_canvas()->lock_window("VDeviceX11::open_output");
95 if(!device->single_frame)
96 output->start_video();
98 output->start_single();
99 output->get_canvas()->unlock_window();
101 // Enable opengl in the first routine that needs it, to reduce the complexity.
103 output->unlock_canvas();
109 int VDeviceX11::output_visible()
111 if(!output) return 0;
113 output->lock_canvas("VDeviceX11::output_visible");
114 if(output->get_canvas()->get_hidden())
116 output->unlock_canvas();
121 output->unlock_canvas();
127 int VDeviceX11::close_all()
131 output->lock_canvas("VDeviceX11::close_all 1");
132 output->get_canvas()->lock_window("VDeviceX11::close_all 1");
135 if(output && output_frame)
137 // Copy our output frame buffer to the canvas's permanent frame buffer.
138 // They must be different buffers because the output frame is being written
139 // while the user is redrawing the canvas frame buffer over and over.
141 int use_opengl = device->out_config->driver == PLAYBACK_X11_GL &&
142 output_frame->get_opengl_state() == VFrame::SCREEN;
143 int best_color_model = output_frame->get_color_model();
145 // OpenGL does YUV->RGB in the compositing step
147 best_color_model = BC_RGB888;
149 if(output->refresh_frame &&
150 (output->refresh_frame->get_w() != device->out_w ||
151 output->refresh_frame->get_h() != device->out_h ||
152 output->refresh_frame->get_color_model() != best_color_model))
154 delete output->refresh_frame;
155 output->refresh_frame = 0;
158 if(!output->refresh_frame)
160 output->refresh_frame = new VFrame(0, -1,
161 device->out_w, device->out_h,
162 best_color_model, -1);
167 output->get_canvas()->unlock_window();
168 output->unlock_canvas();
170 output->mwindow->playback_3d->copy_from(output,
171 output->refresh_frame, output_frame, 0);
172 output->lock_canvas("VDeviceX11::close_all 2");
173 output->get_canvas()->lock_window("VDeviceX11::close_all 2");
176 output->refresh_frame->copy_from(output_frame);
178 // // Update the status bug
179 // if(!device->single_frame)
181 // output->stop_video();
185 // output->stop_single();
188 // Draw the first refresh with new frame.
189 // Doesn't work if video and openGL because OpenGL doesn't have
190 // the output buffer for video.
191 // Not necessary for any case if we mandate a frame advance after
193 if(/* device->out_config->driver != PLAYBACK_X11_GL ||
194 */ device->single_frame)
195 output->draw_refresh();
213 if(capture_bitmap) delete capture_bitmap;
218 // Update the status bug
219 if(!device->single_frame)
221 output->stop_video();
225 output->stop_single();
228 output->get_canvas()->unlock_window();
229 output->unlock_canvas();
237 int VDeviceX11::read_buffer(VFrame *frame)
239 capture_bitmap->capture_frame(frame, device->input_x, device->input_y);
244 int VDeviceX11::get_best_colormodel(Asset *asset)
250 int VDeviceX11::get_best_colormodel(int colormodel)
254 if(device->out_config->driver == PLAYBACK_X11_GL)
256 if(colormodel == BC_RGB888 ||
257 colormodel == BC_RGBA8888 ||
258 colormodel == BC_YUV888 ||
259 colormodel == BC_YUVA8888 ||
260 colormodel == BC_RGB_FLOAT ||
261 colormodel == BC_RGBA_FLOAT)
268 if(!device->single_frame)
280 // 2 more colormodels are supported by OpenGL
281 if(device->out_config->driver == PLAYBACK_X11_GL)
283 if(colormodel == BC_RGB_FLOAT ||
284 colormodel == BC_RGBA_FLOAT)
300 output->lock_canvas("VDeviceX11::get_best_colormodel");
301 result = output->get_canvas()->get_color_model();
302 output->unlock_canvas();
311 void VDeviceX11::new_output_buffer(VFrame **result, int colormodel)
313 //printf("VDeviceX11::new_output_buffer 1\n");
314 output->lock_canvas("VDeviceX11::new_output_buffer");
315 output->get_canvas()->lock_window("VDeviceX11::new_output_buffer 1");
317 // Get the best colormodel the display can handle.
318 int best_colormodel = get_best_colormodel(colormodel);
320 // Only create OpenGL Pbuffer and texture.
321 if(device->out_config->driver == PLAYBACK_X11_GL)
323 // Create bitmap for initial load into texture.
324 // Not necessary to do through Playback3D.....yet
327 output_frame = new VFrame(0, -1,
328 device->out_w, device->out_h,
330 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 1");
333 window_id = output->get_canvas()->get_id();
334 output_frame->set_opengl_state(VFrame::RAM);
338 // Conform existing bitmap to new colormodel and output size
341 // Restart if output size changed or output colormodel changed.
342 // May have to recreate if transferring between windowed and fullscreen.
343 if(!color_model_selected ||
344 (!bitmap->hardware_scaling() &&
345 (bitmap->get_w() != output->get_canvas()->get_w() ||
346 bitmap->get_h() != output->get_canvas()->get_h())) ||
347 colormodel != output_frame->get_color_model())
349 int size_change = (bitmap->get_w() != output->get_canvas()->get_w() ||
350 bitmap->get_h() != output->get_canvas()->get_h());
351 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
357 // Blank only if size changed
360 output->get_canvas()->set_color(BLACK);
361 output->get_canvas()->draw_box(0, 0, output->w, output->h);
362 output->get_canvas()->flash();
366 // Update the ring buffer
367 if(bitmap_type == BITMAP_PRIMARY)
369 //printf("VDeviceX11::new_output_buffer %d\n", __LINE__);
370 output_frame->set_memory(bitmap);
377 // Try hardware accelerated
378 switch(best_colormodel)
381 if(device->out_config->driver == PLAYBACK_X11_XV &&
382 output->get_canvas()->accel_available(best_colormodel, 0) &&
383 !output->use_scrollbars)
385 bitmap = new BC_Bitmap(output->get_canvas(),
386 device->out_w, device->out_h,
388 output_frame = new VFrame(bitmap,
389 device->out_w, device->out_h,
390 best_colormodel, -1);
391 bitmap_type = BITMAP_PRIMARY;
396 if(device->out_config->driver == PLAYBACK_X11_XV &&
397 output->get_canvas()->accel_available(best_colormodel, 0) &&
398 !output->use_scrollbars)
400 bitmap = new BC_Bitmap(output->get_canvas(),
401 device->out_w, device->out_h,
403 output_frame = new VFrame(bitmap,
404 device->out_w, device->out_h,
405 best_colormodel, -1);
406 bitmap_type = BITMAP_PRIMARY;
409 if(device->out_config->driver == PLAYBACK_X11_XV &&
410 output->get_canvas()->accel_available(BC_YUV422, 0))
412 bitmap = new BC_Bitmap(output->get_canvas(),
417 bitmap_type = BITMAP_TEMP;
422 if(device->out_config->driver == PLAYBACK_X11_XV &&
423 output->get_canvas()->accel_available(best_colormodel, 0) &&
424 !output->use_scrollbars)
426 bitmap = new BC_Bitmap(output->get_canvas(),
427 device->out_w, device->out_h,
429 output_frame = new VFrame(bitmap,
430 device->out_w, device->out_h,
431 best_colormodel, -1);
432 bitmap_type = BITMAP_PRIMARY;
435 if(device->out_config->driver == PLAYBACK_X11_XV &&
436 output->get_canvas()->accel_available(BC_YUV422P, 0))
438 bitmap = new BC_Bitmap(output->get_canvas(),
439 device->out_w, device->out_h,
441 bitmap_type = BITMAP_TEMP;
446 // Try default colormodel
449 best_colormodel = output->get_canvas()->get_color_model();
450 bitmap = new BC_Bitmap(output->get_canvas(),
451 output->get_canvas()->get_w(),
452 output->get_canvas()->get_h(),
454 bitmap_type = BITMAP_TEMP;
457 if(bitmap_type == BITMAP_TEMP)
459 // Intermediate frame
460 output_frame = new VFrame(0, -1,
461 device->out_w, device->out_h,
463 //BUFFER2(output_frame->get_rows()[0], "VDeviceX11::new_output_buffer 2");
464 bitmap_type = BITMAP_TEMP;
466 color_model_selected = 1;
470 *result = output_frame;
471 //printf("VDeviceX11::new_output_buffer 10 %d\n", output->get_canvas()->get_window_lock());
473 output->get_canvas()->unlock_window();
474 output->unlock_canvas();
478 int VDeviceX11::start_playback()
480 // Record window is initialized when its monitor starts.
481 if(!device->single_frame)
482 output->start_video();
486 int VDeviceX11::stop_playback()
488 if(!device->single_frame)
489 output->stop_video();
490 // Record window goes back to monitoring
491 // get the last frame played and store it in the video_out
495 int VDeviceX11::write_buffer(VFrame *output_channels, EDL *edl)
497 output->lock_canvas("VDeviceX11::write_buffer");
498 output->get_canvas()->lock_window("VDeviceX11::write_buffer 1");
500 // Canvas may be a different size than the temporary bitmap for pure software
502 if(bitmap_type == BITMAP_TEMP && !bitmap->hardware_scaling()) {
503 xfr_w = bitmap->get_w();
504 xfr_h = bitmap->get_h();
509 //printf("VDeviceX11::write_buffer %d %d\n", __LINE__, output->get_canvas()->get_video_on());
510 output->get_transfers(edl, output_x1, output_y1, output_x2, output_y2,
511 canvas_x1, canvas_y1, canvas_x2, canvas_y2, xfr_w, xfr_h);
513 // Convert colormodel
515 // this is handled by overlay call in virtualvnode, using flatten alpha
516 // invoked when is_nested = -1 is passed to vdevicex11->overlay(...)
517 if(device->out_config->driver == PLAYBACK_X11_GL &&
518 output_frame->get_color_model() != BC_RGB888) {
519 int cmodel = BC_RGB888;
520 output->get_canvas()->unlock_window();
521 output->unlock_canvas();
522 output->mwindow->playback_3d->convert_cmodel(output, output_frame, cmodel);
523 output_frame->reallocate(0,-1,0,0,0,output_frame->get_w(),output_frame->get_h(),cmodel,-1);
524 output->lock_canvas("VDeviceX11::write_buffer 3");
525 output->get_canvas()->lock_window("VDeviceX11::write_buffer 3");
529 if(bitmap_type == BITMAP_TEMP) {
530 // printf("VDeviceX11::write_buffer 1 %d %d, %d %d %d %d -> %d %d %d %d\n",
531 // output->w, output->h, in_x, in_y, in_w, in_h, out_x, out_y, out_w, out_h );
533 //printf("VDeviceX11::write_buffer %d output_channels=%p\n", __LINE__, output_channels);
536 if(bitmap->hardware_scaling())
538 BC_CModels::transfer(bitmap->get_row_pointers(),
539 output_channels->get_rows(), 0, 0, 0,
540 output_channels->get_y(),
541 output_channels->get_u(),
542 output_channels->get_v(),
544 output_channels->get_w(),
545 output_channels->get_h(),
549 output_channels->get_color_model(),
550 bitmap->get_color_model(),
552 output_channels->get_w(),
557 BC_CModels::transfer(bitmap->get_row_pointers(),
558 output_channels->get_rows(), 0, 0, 0,
559 output_channels->get_y(),
560 output_channels->get_u(),
561 output_channels->get_v(),
564 (int)(output_x2 - output_x1),
565 (int)(output_y2 - output_y1),
567 (int)(canvas_x2 - canvas_x1),
568 (int)(canvas_y2 - canvas_y1),
569 output_channels->get_color_model(),
570 bitmap->get_color_model(),
572 output_channels->get_w(),
577 //printf("VDeviceX11::write_buffer 4 %p\n", bitmap);
578 //for(i = 0; i < 1000; i += 4) bitmap->get_data()[i] = 128;
579 //printf("VDeviceX11::write_buffer 2 %d %d %d\n", bitmap_type,
580 // bitmap->get_color_model(), output->get_color_model());
582 //printf("VDeviceX11::write_buffer 2 %d %d, %f %f %f %f -> %f %f %f %f\n",
583 // output->w, output->h, output_x1, output_y1, output_x2, output_y2,
584 // canvas_x1, canvas_y1, canvas_x2, canvas_y2);
586 // Cause X server to display it
587 if(device->out_config->driver == PLAYBACK_X11_GL)
589 // Output is drawn in close_all if no video.
590 if(output->get_canvas()->get_video_on())
592 // Draw output frame directly. Not used for compositing.
593 output->get_canvas()->unlock_window();
594 output->unlock_canvas();
595 output->mwindow->playback_3d->write_buffer(output,
596 output_frame, output_x1, output_y1, output_x2, output_y2,
597 canvas_x1, canvas_y1, canvas_x2, canvas_y2, is_cleared);
599 output->lock_canvas("VDeviceX11::write_buffer 2");
600 output->get_canvas()->lock_window("VDeviceX11::write_buffer 2");
604 if(bitmap->hardware_scaling())
606 output->get_canvas()->draw_bitmap(bitmap,
607 !device->single_frame,
608 (int)canvas_x1, (int)canvas_y1,
609 (int)(canvas_x2 - canvas_x1),
610 (int)(canvas_y2 - canvas_y1),
611 (int)output_x1, (int)output_y1,
612 (int)(output_x2 - output_x1),
613 (int)(output_y2 - output_y1),
618 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
619 output->get_canvas()->draw_bitmap(bitmap,
620 !device->single_frame,
621 (int)canvas_x1, (int)canvas_y1,
622 (int)(canvas_x2 - canvas_x1),
623 (int)(canvas_y2 - canvas_y1),
625 (int)(canvas_x2 - canvas_x1),
626 (int)(canvas_y2 - canvas_y1),
628 //printf("VDeviceX11::write_buffer %d bitmap=%p\n", __LINE__, bitmap);
632 output->get_canvas()->unlock_window();
633 output->unlock_canvas();
638 void VDeviceX11::clear_output()
642 output->mwindow->playback_3d->clear_output(output,
643 output->get_canvas()->get_video_on() ? 0 : output_frame);
648 void VDeviceX11::clear_input(VFrame *frame)
650 this->output->mwindow->playback_3d->clear_input(this->output, frame);
653 void VDeviceX11::convert_cmodel(VFrame *output, int dst_cmodel)
655 this->output->mwindow->playback_3d->convert_cmodel(this->output,
660 void VDeviceX11::do_camera(VFrame *output, VFrame *input,
661 float in_x1, float in_y1, float in_x2, float in_y2,
662 float out_x1, float out_y1, float out_x2, float out_y2)
664 this->output->mwindow->playback_3d->do_camera(
665 this->output, output, input,
666 in_x1, in_y1, in_x2, in_y2,
667 out_x1, out_y1, out_x2, out_y2);
671 void VDeviceX11::do_fade(VFrame *output_temp, float fade)
673 this->output->mwindow->playback_3d->do_fade(this->output, output_temp, fade);
676 void VDeviceX11::do_mask(VFrame *output_temp, int64_t start_position_project,
677 MaskAutos *keyframe_set, MaskAuto *keyframe,
678 MaskAuto *default_auto)
680 this->output->mwindow->playback_3d->do_mask(output,
681 output_temp, start_position_project,
682 keyframe_set, keyframe, default_auto);
685 void VDeviceX11::overlay(VFrame *output_frame, VFrame *input,
686 // This is the transfer from track to output frame
687 float in_x1, float in_y1, float in_x2, float in_y2,
688 float out_x1, float out_y1, float out_x2, float out_y2,
689 float alpha /*0-1*/, int mode, EDL *edl, int is_nested)
691 int interpolation_type = edl->session->interpolation_type;
693 // printf("VDeviceX11::overlay 1:\n"
694 // "in_x1=%f in_y1=%f in_x2=%f in_y2=%f\n"
695 // "out_x1=%f out_y1=%f out_x2=%f out_y2=%f\n",
696 // in_x1, in_y1, in_x2, in_y2,
697 // out_x1, out_y1, out_x2, out_y2);
698 // Convert node coords to canvas coords in here
700 // If single frame playback or nested EDL, use full sized PBuffer as output.
701 if(device->single_frame || is_nested > 0)
703 output->mwindow->playback_3d->overlay(output, input,
704 in_x1, in_y1, in_x2, in_y2,
705 out_x1, out_y1, out_x2, out_y2,
706 alpha, mode, interpolation_type,
707 output_frame, is_nested);
708 // printf("VDeviceX11::overlay 1 %p %d %d %d\n",
710 // output_frame->get_w(),
711 // output_frame->get_h(),
712 // output_frame->get_opengl_state());
716 output->lock_canvas("VDeviceX11::overlay");
717 output->get_canvas()->lock_window("VDeviceX11::overlay");
719 // This is the transfer from output frame to canvas
720 output->get_transfers(edl,
721 output_x1, output_y1, output_x2, output_y2,
722 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
725 output->get_canvas()->unlock_window();
726 output->unlock_canvas();
729 // Get transfer from track to canvas
730 float track_xscale = (out_x2 - out_x1) / (in_x2 - in_x1);
731 float track_yscale = (out_y2 - out_y1) / (in_y2 - in_y1);
732 float canvas_xscale = (float)(canvas_x2 - canvas_x1) / (output_x2 - output_x1);
733 float canvas_yscale = (float)(canvas_y2 - canvas_y1) / (output_y2 - output_y1);
736 // Get coordinates of canvas relative to track frame
737 float track_x1 = (float)(output_x1 - out_x1) / track_xscale + in_x1;
738 float track_y1 = (float)(output_y1 - out_y1) / track_yscale + in_y1;
739 float track_x2 = (float)(output_x2 - out_x2) / track_xscale + in_x2;
740 float track_y2 = (float)(output_y2 - out_y2) / track_yscale + in_y2;
742 // Clamp canvas coords to track boundary
745 float difference = -track_x1;
746 track_x1 += difference;
747 canvas_x1 += difference * track_xscale * canvas_xscale;
751 float difference = -track_y1;
752 track_y1 += difference;
753 canvas_y1 += difference * track_yscale * canvas_yscale;
756 if(track_x2 > input->get_w())
758 float difference = track_x2 - input->get_w();
759 track_x2 -= difference;
760 canvas_x2 -= difference * track_xscale * canvas_xscale;
762 if(track_y2 > input->get_h())
764 float difference = track_y2 - input->get_h();
765 track_y2 -= difference;
766 canvas_y2 -= difference * track_yscale * canvas_yscale;
769 // Overlay directly from track buffer to canvas, skipping output buffer
770 if(track_x2 > track_x1 && track_y2 > track_y1 &&
771 canvas_x2 > canvas_x1 && canvas_y2 > canvas_y1)
773 output->mwindow->playback_3d->overlay(output, input,
774 track_x1, track_y1, track_x2, track_y2,
775 canvas_x1, canvas_y1, canvas_x2, canvas_y2,
776 alpha, mode, interpolation_type, 0, is_nested);
781 void VDeviceX11::run_plugin(PluginClient *client)
783 output->mwindow->playback_3d->run_plugin(output, client);
786 void VDeviceX11::copy_frame(VFrame *dst, VFrame *src)
788 output->mwindow->playback_3d->copy_from(output, dst, src, 1);