rework keyframe hide popup, keyframe auto render, textbox set_selection wide text
[goodguy/history.git] / cinelerra-5.1 / cinelerra / recordmonitor.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2011 Adam Williams <broadcast at earthling dot net>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU General Public License as published by
7  * the Free Software Foundation; either version 2 of the License, or
8  * (at your option) any later version.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU General Public License for more details.
14  *
15  * You should have received a copy of the GNU General Public License
16  * along with this program; if not, write to the Free Software
17  * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18  *
19  */
20
21 #include "asset.h"
22 #include "bcdialog.h"
23 #include "bcsignals.h"
24 #include "channelpicker.h"
25 #include "condition.h"
26 #include "cursors.h"
27 #include "devicedvbinput.h"
28 #include "libdv.h"
29 #include "edl.h"
30 #include "edlsession.h"
31 #include "keys.h"
32 #include "language.h"
33 #include "mainsession.h"
34 #include "meterpanel.h"
35 #include "mwindow.h"
36 #include "playbackconfig.h"
37 #include "preferences.h"
38 #include "record.h"
39 #include "recordconfig.h"
40 #include "recordgui.h"
41 #include "recordscopes.h"
42 #include "recordtransport.h"
43 #include "recordmonitor.h"
44 #include "theme.h"
45 #include "videodevice.inc"
46 #include "vframe.h"
47 #include "videodevice.h"
48 #include "vdevicedvb.h"
49
50
51 RecordMonitor::RecordMonitor(MWindow *mwindow, Record *record)
52  : Thread(1, 0, 0)
53 {
54         this->mwindow = mwindow;
55         this->record = record;
56         device = 0;
57         thread = 0;
58         scope_thread = 0;
59 }
60
61
62 RecordMonitor::~RecordMonitor()
63 {
64         delete thread;
65         window->set_done(0);
66         Thread::join();
67         if( device ) {
68                 device->close_all();
69                 delete device;
70         }
71         delete scope_thread;
72         delete window;
73 }
74
75 void RecordMonitor::create_objects()
76 {
77         int min_w = 150;
78         mwindow->session->rwindow_fullscreen = 0;
79
80         if( !record->default_asset->video_data )
81                 min_w = MeterPanel::get_meters_width(
82                         mwindow->theme,
83                         record->default_asset->channels, 1);
84
85
86
87 //SET_TRACE
88         window = new RecordMonitorGUI(mwindow, record, this, min_w);
89 //SET_TRACE
90         window->create_objects();
91 //SET_TRACE
92
93         if( record->default_asset->video_data ) {
94 // Configure the output for record monitoring
95                 VideoOutConfig config;
96 //SET_TRACE
97                 device = new VideoDevice;
98 //SET_TRACE
99
100
101
102 // Override default device for X11 drivers
103                 if(mwindow->edl->session->playback_config->vconfig->driver ==
104                         PLAYBACK_X11_XV) config.driver = PLAYBACK_X11_XV;
105                 config.x11_use_fields = 0;
106
107 //SET_TRACE
108
109                 device->open_output(&config,
110                         record->default_asset->frame_rate,
111                         record->default_asset->width,
112                         record->default_asset->height,
113                         window->canvas, 0);
114 //SET_TRACE
115
116                 scope_thread = new RecordScopeThread(mwindow, this);
117
118                 if(mwindow->session->record_scope)
119                 {
120                         scope_thread->start();
121                 }
122
123
124                 thread = new RecordMonitorThread(mwindow, record, this);
125 //SET_TRACE
126                 thread->start_playback();
127 //SET_TRACE
128         }
129 //SET_TRACE
130
131         Thread::start();
132 }
133
134
135 void RecordMonitor::run()
136 {
137         window->run_window();
138         close_threads();
139 }
140
141 void RecordMonitor::close_threads()
142 {
143         if(window->channel_picker) window->channel_picker->close_threads();
144 }
145
146 int RecordMonitor::update(VFrame *vframe)
147 {
148         return thread->write_frame(vframe);
149 }
150
151 void RecordMonitor::update_channel(char *text)
152 {
153         if( window->channel_picker )
154                 window->channel_picker->channel_text->update(text);
155 }
156
157 int RecordMonitor::get_mbuttons_height()
158 {
159         return RECBUTTON_HEIGHT;
160 }
161
162 void RecordMonitor::fix_size(int &w, int &h, int width_given, float aspect_ratio)
163 {
164         w = width_given;
165         h = (int)((float)width_given / aspect_ratio);
166 }
167
168 float RecordMonitor::get_scale(int w)
169 {
170         if( mwindow->edl->get_aspect_ratio() >
171                 (float)record->frame_w / record->frame_h ) {
172                 return (float)w /
173                         ((float)record->frame_h *
174                         mwindow->edl->get_aspect_ratio());
175         }
176         else {
177                 return (float)w / record->frame_w;
178         }
179 }
180
181 int RecordMonitor::get_canvas_height()
182 {
183         return window->get_h() - get_mbuttons_height();
184 }
185
186 int RecordMonitor::get_channel_x()
187 {
188 //      return 240;
189         return 5;
190 }
191
192 int RecordMonitor::get_channel_y()
193 {
194         return 2;
195 }
196
197 void RecordMonitor::stop_playback()
198 {
199         if( !thread || thread->finished() ) return;
200         window->enable_signal_status(0);
201         if( thread ) {
202                 thread->stop_playback();
203         }
204 }
205
206 void RecordMonitor::start_playback()
207 {
208         if( thread ) {
209                 thread->output_lock->reset();
210                 thread->start_playback();
211         }
212         window->enable_signal_status(1);
213 }
214
215
216 void RecordMonitor::reconfig()
217 {
218         stop_playback();
219         VideoOutConfig config = *device->out_config;
220         device->close_all();
221         device->open_output(&config,
222                 record->default_asset->frame_rate,
223                 record->default_asset->width,
224                 record->default_asset->height,
225                 window->canvas, 0);
226         start_playback();
227         redraw();
228 }
229
230 void RecordMonitor::redraw()
231 {
232         if( thread && window && thread->record->video_window_open )
233                 window->redraw();
234 }
235
236 void RecordMonitor::display_vframe(VFrame *in, int x, int y,
237                 int alpha, double secs, double scale)
238 {
239         if( !thread ) return;
240         thread->display_vframe(in, x, y, alpha, secs, scale);
241 }
242
243 void RecordMonitor::undisplay_vframe()
244 {
245         if( !thread ) return;
246         thread->undisplay_vframe();
247 }
248
249 RecordMonitorGUI::RecordMonitorGUI(MWindow *mwindow,
250         Record *record, RecordMonitor *thread, int min_w)
251  : BC_Window(_(PROGRAM_NAME ": Video in"),
252                         mwindow->session->rmonitor_x,
253                         mwindow->session->rmonitor_y,
254                         mwindow->session->rmonitor_w,
255                         mwindow->session->rmonitor_h,
256                         min_w, 50, 1, 1, 1, -1,
257                         mwindow->get_cwindow_display())
258 {
259 //printf("%d %d\n", mwindow->session->rmonitor_w, mwindow->theme->rmonitor_meter_x);
260         this->mwindow = mwindow;
261         this->thread = thread;
262         this->record = record;
263 #ifdef HAVE_FIREWIRE
264         avc = 0;
265         avc1394_transport = 0;
266         avc1394transport_title = 0;
267         avc1394transport_timecode = 0;
268         avc1394transport_thread = 0;
269 #endif
270         bitmap = 0;
271         channel_picker = 0;
272         reverse_interlace = 0;
273         meters = 0;
274         canvas = 0;
275         current_operation = MONITOR_NONE;
276         signal_status = 0;
277 }
278
279 RecordMonitorGUI::~RecordMonitorGUI()
280 {
281         lock_window("RecordMonitorGUI::~RecordMonitorGUI");
282         delete signal_status;
283         delete canvas;
284         if( bitmap ) delete bitmap;
285         if( channel_picker ) delete channel_picker;
286         if( avc1394transport_thread )
287 #ifdef HAVE_FIREWIRE
288                 delete avc1394transport_thread;
289         if( avc ) {
290                 delete avc;
291         }
292         if( avc1394_transport ) {
293                 delete avc1394_transport;
294         }
295         if( avc1394transport_title )
296                 delete avc1394transport_title;
297 #endif
298         unlock_window();
299 }
300
301 void RecordMonitorGUI::create_objects()
302 {
303 // y offset for video canvas if we have the transport controls
304         lock_window("RecordMonitorGUI::create_objects");
305         int driver = mwindow->edl->session->vconfig_in->driver;
306         int do_channel = (driver == VIDEO4LINUX ||
307                         driver == CAPTURE_BUZ ||
308                         driver == CAPTURE_DVB ||
309                         driver == VIDEO4LINUX2 ||
310                         driver == VIDEO4LINUX2JPEG ||
311                         driver == VIDEO4LINUX2MPEG ||
312                         driver == CAPTURE_JPEG_WEBCAM ||
313                         driver == CAPTURE_YUYV_WEBCAM);
314         int do_scopes = do_channel || driver == SCREENCAPTURE;
315         int do_interlace = (driver == CAPTURE_BUZ ||
316                 driver == VIDEO4LINUX2JPEG);
317         int background_done = 0;
318         int do_audio = record->default_asset->audio_data;
319         int do_video = record->default_asset->video_data;
320         int do_meters = record->metering_audio;
321         int channels = !do_meters ? 0 : record->default_asset->channels;
322
323         mwindow->theme->get_rmonitor_sizes(do_meters, do_video,
324                 do_channel || do_scopes, do_interlace, 0, channels);
325
326
327         if(do_video) {
328 #ifdef HAVE_FIREWIRE
329                 if( driver == CAPTURE_FIREWIRE || driver == CAPTURE_IEC61883 ) {
330                         avc = new AVC1394Control;
331                         if( avc->device > -1 ) {
332                                 mwindow->theme->get_rmonitor_sizes(do_meters, do_video,
333                                          do_channel, do_interlace, 1, channels);
334                                 mwindow->theme->draw_rmonitor_bg(this);
335                                 background_done = 1;
336
337                                 avc1394_transport = new AVC1394Transport(mwindow,
338                                         avc,
339                                         this,
340                                         mwindow->theme->rmonitor_tx_x,
341                                         mwindow->theme->rmonitor_tx_y);
342                                 avc1394_transport->create_objects();
343
344                                 add_subwindow(avc1394transport_timecode =
345                                         new BC_Title(avc1394_transport->x_end,
346                                                 mwindow->theme->rmonitor_tx_y + 10,
347                                                 _("00:00:00:00"),
348                                                 MEDIUM_7SEGMENT,
349                                                 BLACK));
350
351                                 avc1394transport_thread =
352                                         new AVC1394TransportThread(avc1394transport_timecode,
353                                                 avc);
354
355                                 avc1394transport_thread->start();
356
357                         }
358                 }
359 #endif
360
361                 if( !background_done ) {
362                         mwindow->theme->draw_rmonitor_bg(this);
363                         background_done = 1;
364                 }
365
366                 mwindow->theme->rmonitor_canvas_w = MAX(10, mwindow->theme->rmonitor_canvas_w);
367                 mwindow->theme->rmonitor_canvas_h = MAX(10, mwindow->theme->rmonitor_canvas_h);
368                 canvas = new RecordMonitorCanvas(mwindow, this, record,
369                         mwindow->theme->rmonitor_canvas_x,
370                         mwindow->theme->rmonitor_canvas_y,
371                         mwindow->theme->rmonitor_canvas_w,
372                         mwindow->theme->rmonitor_canvas_h);
373                 canvas->create_objects(0);
374                 canvas->use_rwindow();
375
376                 if( driver == CAPTURE_DVB ) {
377                         int ssw = SignalStatus::calculate_w(this);
378                         signal_status = new SignalStatus(this, get_w()-ssw-3, 0);
379                         add_subwindow(signal_status);
380                         signal_status->create_objects();
381                 }
382
383                 int x = mwindow->theme->widget_border;
384                 int y = mwindow->theme->widget_border;
385                 if( do_channel ) {
386                         channel_picker = new RecordChannelPicker(mwindow,
387                                 record, thread, this, record->channeldb,
388                                 mwindow->theme->rmonitor_channel_x,
389                                 mwindow->theme->rmonitor_channel_y);
390                         channel_picker->create_objects();
391                         x += channel_picker->get_w() + mwindow->theme->widget_border;
392                 }
393                 if( driver == CAPTURE_BUZ ||
394                         driver == VIDEO4LINUX2JPEG ) {
395                         add_subwindow(reverse_interlace = new ReverseInterlace(record,
396                                 mwindow->theme->rmonitor_interlace_x,
397                                 mwindow->theme->rmonitor_interlace_y));
398                         x += reverse_interlace->get_w() + mwindow->theme->widget_border;
399                 }
400
401                 if(do_scopes)
402                 {
403                         scope_toggle = new ScopeEnable(mwindow, thread, x, y);
404                         add_subwindow(scope_toggle);
405                         x += scope_toggle->get_w() + mwindow->theme->widget_border;
406                 }
407
408                 add_subwindow(monitor_menu = new BC_PopupMenu(0, 0, 0, "", 0));
409                 monitor_menu->add_item(new RecordMonitorFullsize(mwindow, this));
410         }
411
412
413         if( !background_done ) {
414                 mwindow->theme->draw_rmonitor_bg(this);
415                 background_done = 1;
416         }
417
418         if( do_audio ) {
419                 meters = new MeterPanel(mwindow,
420                         this,
421                         mwindow->theme->rmonitor_meter_x,
422                         mwindow->theme->rmonitor_meter_y,
423                         record->default_asset->video_data ? -1 : mwindow->theme->rmonitor_meter_w,
424                         mwindow->theme->rmonitor_meter_h,
425                         channels, do_meters, 1, 0);
426                 meters->create_objects();
427         }
428         unlock_window();
429 }
430
431 int RecordMonitorGUI::button_press_event()
432 {
433         if(mwindow->session->rwindow_fullscreen && canvas && canvas->get_canvas())
434                 return canvas->button_press_event_base(canvas->get_canvas());
435
436         if( get_buttonpress() == 2 ) {
437                 return 0;
438         }
439         else
440 // Right button
441         if( get_buttonpress() == 3 ) {
442                 monitor_menu->activate_menu();
443                 return 1;
444         }
445         return 0;
446 }
447
448 int RecordMonitorGUI::cursor_leave_event()
449 {
450         if(canvas && canvas->get_canvas())
451                 return canvas->cursor_leave_event_base(canvas->get_canvas());
452         return 0;
453 }
454
455 int RecordMonitorGUI::cursor_enter_event()
456 {
457         if( canvas && canvas->get_canvas() )
458                 return canvas->cursor_enter_event_base(canvas->get_canvas());
459         return 0;
460 }
461
462 int RecordMonitorGUI::button_release_event()
463 {
464         if( canvas && canvas->get_canvas() )
465                 return canvas->button_release_event();
466         return 0;
467 }
468
469 int RecordMonitorGUI::cursor_motion_event()
470 {
471 //SET_TRACE
472         if( canvas && canvas->get_canvas() ) {
473                 canvas->get_canvas()->unhide_cursor();
474 //SET_TRACE
475                 return canvas->cursor_motion_event();
476         }
477         return 0;
478 }
479
480 int RecordMonitorGUI::keypress_event()
481 {
482         int result = 0;
483
484         switch(get_keypress()) {
485         case LEFT:
486                 if( !ctrl_down() ) {
487                         record->record_gui->set_translation(--(record->video_x), record->video_y, record->video_zoom);
488                 }
489                 else {
490                         record->video_zoom -= 0.1;
491                         record->record_gui->set_translation(record->video_x, record->video_y, record->video_zoom);
492                 }
493                 result = 1;
494                 break;
495         case RIGHT:
496                 if( !ctrl_down() ) {
497                         record->record_gui->set_translation(++(record->video_x), record->video_y, record->video_zoom);
498                 }
499                 else {
500                         record->video_zoom += 0.1;
501                         record->record_gui->set_translation(record->video_x, record->video_y, record->video_zoom);
502                 }
503                 result = 1;
504                 break;
505         case UP:
506                 if( !ctrl_down() ) {
507                         record->record_gui->set_translation(record->video_x, --(record->video_y), record->video_zoom);
508                 }
509                 else {
510                         record->video_zoom -= 0.1;
511                         record->record_gui->set_translation(record->video_x, record->video_y, record->video_zoom);
512                 }
513                 result = 1;
514                 break;
515         case DOWN:
516                 if( !ctrl_down() ) {
517                         record->record_gui->set_translation(record->video_x, ++(record->video_y), record->video_zoom);
518                 }
519                 else {
520                         record->video_zoom += 0.1;
521                         record->record_gui->set_translation(record->video_x, record->video_y, record->video_zoom);
522                 }
523                 result = 1;
524                 break;
525         case 'w':
526                 close_event();
527                 break;
528
529         default:
530                 if(canvas) result = canvas->keypress_event(this);
531                 if(!result && avc1394_transport)
532                         result = avc1394_transport->keypress_event(get_keypress());
533                 break;
534         }
535
536         return result;
537 }
538
539
540 int RecordMonitorGUI::translation_event()
541 {
542 //printf("MWindowGUI::translation_event 1 %d %d\n", get_x(), get_y());
543         mwindow->session->rmonitor_x = get_x();
544         mwindow->session->rmonitor_y = get_y();
545         return 0;
546 }
547
548 int RecordMonitorGUI::resize_event(int w, int h)
549 {
550         int driver = mwindow->edl->session->vconfig_in->driver;
551         int do_channel = (driver == VIDEO4LINUX ||
552                         driver == CAPTURE_BUZ ||
553                         driver == CAPTURE_DVB ||
554                         driver == VIDEO4LINUX2 ||
555                         driver == VIDEO4LINUX2JPEG ||
556                         driver == VIDEO4LINUX2MPEG ||
557                         driver == CAPTURE_JPEG_WEBCAM ||
558                         driver == CAPTURE_YUYV_WEBCAM);
559         int do_scopes = do_channel || driver == SCREENCAPTURE;
560         int do_interlace = (driver == CAPTURE_BUZ ||
561                 driver == VIDEO4LINUX2JPEG);
562         int do_avc = 0;
563 #ifdef HAVE_FIREWIRE
564         do_avc = avc1394_transport ? 1 : 0;
565 #endif
566         int do_meters = meters && record->default_asset->audio_data &&
567                 record->metering_audio;
568         int do_video = record->default_asset->video_data;
569
570         mwindow->session->rmonitor_x = get_x();
571         mwindow->session->rmonitor_y = get_y();
572         mwindow->session->rmonitor_w = w;
573         mwindow->session->rmonitor_h = h;
574
575         mwindow->theme->get_rmonitor_sizes(do_meters, do_video,
576                 do_channel || do_scopes, do_interlace, do_avc,
577                 record->default_asset->channels);
578         mwindow->theme->draw_rmonitor_bg(this);
579
580
581 //      record_transport->reposition_window(mwindow->theme->rmonitor_tx_x,
582 //              mwindow->theme->rmonitor_tx_y);
583 #ifdef HAVE_FIREWIRE
584         if(avc1394_transport)
585         {
586                 avc1394_transport->reposition_window(mwindow->theme->rmonitor_tx_x,
587                         mwindow->theme->rmonitor_tx_y);
588         }
589 #endif
590
591         if(channel_picker) channel_picker->reposition();
592         if(reverse_interlace) reverse_interlace->reposition_window(reverse_interlace->get_x(),
593                 reverse_interlace->get_y());
594         if(canvas && do_video)
595         {
596                 canvas->reposition_window(0,
597                         mwindow->theme->rmonitor_canvas_x,
598                         mwindow->theme->rmonitor_canvas_y,
599                         mwindow->theme->rmonitor_canvas_w,
600                         mwindow->theme->rmonitor_canvas_h);
601         }
602
603         if(do_meters) {
604                 meters->reposition_window(mwindow->theme->rmonitor_meter_x,
605                         mwindow->theme->rmonitor_meter_y,
606                         do_video ? -1 : mwindow->theme->rmonitor_meter_w,
607                         mwindow->theme->rmonitor_meter_h);
608                 meters->set_meters(record->default_asset->channels,1);
609         }
610         else if(meters) {
611                 meters->set_meters(0,0);
612         }
613
614         set_title();
615         BC_WindowBase::resize_event(w, h);
616         flash();
617         return 1;
618 }
619
620 int RecordMonitorGUI::redraw()
621 {
622         lock_window("RecordMonitorGUI::redraw");
623         int w = mwindow->session->rmonitor_w;
624         int h = mwindow->session->rmonitor_h;
625         int result = resize_event(w, h);
626         unlock_window();
627         return result;
628 }
629
630 int RecordMonitorGUI::set_title()
631 {
632 return 0;
633         char string[1024];
634         int scale;
635
636         scale = (int)(thread->get_scale(thread->record->video_window_w) * 100 + 0.5);
637
638         sprintf(string, _(PROGRAM_NAME ": Video in %d%%"), scale);
639         BC_Window::set_title(string);
640         return 0;
641 }
642
643 int RecordMonitorGUI::close_event()
644 {
645         thread->record->set_video_monitoring(0);
646         thread->record->set_audio_monitoring(0);
647         thread->record->video_window_open = 0;
648         unlock_window();
649         lock_window("RecordMonitorGUI::close_event");
650         hide_window();
651         return 0;
652 }
653
654 int RecordMonitorGUI::create_bitmap()
655 {
656         if(bitmap && (bitmap->get_w() != get_w() ||
657                         bitmap->get_h() != thread->get_canvas_height())) {
658                 delete bitmap;
659                 bitmap = 0;
660         }
661
662         if( !bitmap && canvas ) {
663 //              bitmap = canvas->new_bitmap(get_w(), thread->get_canvas_height());
664         }
665         return 0;
666 }
667
668 void RecordMonitorGUI::enable_signal_status(int enable)
669 {
670         if( !signal_status ) return;
671         signal_status->lock_window("RecordMonitorGUI::enable_signal_status");
672         if( !enable )
673                 signal_status->hide_window();
674         else
675                 signal_status->show_window();
676         signal_status->unlock_window();
677         DeviceDVBInput *dvb_input = record->dvb_device();
678         if( dvb_input )
679                 dvb_input->set_signal_status(!enable ? 0 : signal_status);
680 }
681
682 void RecordMonitorGUI::
683 display_video_text(int x, int y, const char *text, int font,
684         int bg_color, int color, int alpha, double secs, double scale)
685 {
686         lock_window("RecordMonitorGUI::display_text");
687         set_font(font);
688         int ch = get_text_height(font);
689         int h = get_text_height(font,text) + ch/2;
690         int w = get_text_width(font, text) + ch;
691         BC_Pixmap pixmap(this, w, h);
692         set_opaque();
693         set_color(bg_color);
694         draw_box(0, 0, w, h, &pixmap);
695         set_color(color);
696         draw_text(ch/2, ch, text, strlen(text), &pixmap);
697         BC_Bitmap bitmap(this, w, h, BC_RGB888, 0);
698         VFrame in(&bitmap, w, h, BC_RGB888, -1);
699         Drawable drawable = pixmap.get_pixmap();
700         bitmap.read_drawable(drawable, 0, 0, &in);
701         unlock_window();
702         record->display_vframe(&in, x, y, alpha, secs, scale);
703 }
704
705 ReverseInterlace::ReverseInterlace(Record *record, int x, int y)
706  : BC_CheckBox(x, y, record->reverse_interlace, _("Swap fields"))
707 {
708         this->record = record;
709 }
710
711 ReverseInterlace::~ReverseInterlace()
712 {
713 }
714
715 int ReverseInterlace::handle_event()
716 {
717         record->reverse_interlace = get_value();
718         return 0;
719 }
720
721 RecordMonitorCanvas::RecordMonitorCanvas(MWindow *mwindow,
722         RecordMonitorGUI *window, Record *record,
723         int x, int y, int w, int h)
724  : Canvas(mwindow, window, x, y, w, h,
725         record->default_asset->width,
726         record->default_asset->height,
727         0)
728 {
729         this->window = window;
730         this->mwindow = mwindow;
731         this->record = record;
732 //printf("RecordMonitorCanvas::RecordMonitorCanvas 1 %d %d %d %d\n",
733 //x, y, w, h);
734 //printf("RecordMonitorCanvas::RecordMonitorCanvas 2\n");
735 }
736
737 RecordMonitorCanvas::~RecordMonitorCanvas()
738 {
739 }
740
741 int RecordMonitorCanvas::get_output_w()
742 {
743         return record->default_asset->width;
744 }
745
746 int RecordMonitorCanvas::get_output_h()
747 {
748         return record->default_asset->height;
749 }
750
751
752 int RecordMonitorCanvas::button_press_event()
753 {
754
755         if(Canvas::button_press_event()) return 1;
756         if( mwindow->edl->session->vconfig_in->driver == SCREENCAPTURE ) {
757                 window->current_operation = MONITOR_TRANSLATE;
758                 window->translate_x_origin = record->video_x;
759                 window->translate_y_origin = record->video_y;
760                 window->cursor_x_origin = get_cursor_x();
761                 window->cursor_y_origin = get_cursor_y();
762         }
763
764         return 0;
765 }
766
767 void RecordMonitorCanvas::zoom_resize_window(float percentage)
768 {
769         int canvas_w, canvas_h;
770         calculate_sizes(mwindow->edl->get_aspect_ratio(),
771                 record->default_asset->width, record->default_asset->height,
772                 percentage, canvas_w, canvas_h);
773         int new_w, new_h;
774         new_w = canvas_w + (window->get_w() - mwindow->theme->rmonitor_canvas_w);
775         new_h = canvas_h + (window->get_h() - mwindow->theme->rmonitor_canvas_h);
776         window->resize_window(new_w, new_h);
777         window->resize_event(new_w, new_h);
778 }
779
780 int RecordMonitorCanvas::get_fullscreen()
781 {
782         return mwindow->session->rwindow_fullscreen;
783 }
784
785 void RecordMonitorCanvas::set_fullscreen(int value)
786 {
787         mwindow->session->rwindow_fullscreen = value;
788 }
789
790
791 int RecordMonitorCanvas::button_release_event()
792 {
793         window->current_operation = MONITOR_NONE;
794         return 0;
795 }
796
797 int RecordMonitorCanvas::cursor_motion_event()
798 {
799 //SET_TRACE
800         if( window->current_operation == MONITOR_TRANSLATE ) {
801 //SET_TRACE
802                 record->set_translation(
803                         get_cursor_x() - window->cursor_x_origin + window->translate_x_origin,
804                         get_cursor_y() - window->cursor_y_origin + window->translate_y_origin);
805 //SET_TRACE
806         }
807
808         return 0;
809 }
810
811 int RecordMonitorCanvas::cursor_enter_event()
812 {
813         if(mwindow->edl->session->vconfig_in->driver == SCREENCAPTURE)
814                 set_cursor(MOVE_CURSOR);
815         return 0;
816 }
817
818 void RecordMonitorCanvas::reset_translation()
819 {
820         record->set_translation(0, 0);
821 }
822
823 int RecordMonitorCanvas::keypress_event()
824 {
825         if( !get_canvas() ) return 0;
826
827         switch(get_canvas()->get_keypress()) {
828         case LEFT:
829                 record->set_translation(--record->video_x, record->video_y);
830                 break;
831         case RIGHT:
832                 record->set_translation(++record->video_x, record->video_y);
833                 break;
834         case UP:
835                 record->set_translation(record->video_x, --record->video_y);
836                 break;
837         case DOWN:
838                 record->set_translation(record->video_x, ++record->video_y);
839                 break;
840         default:
841                 return 0;
842         }
843         return 1;
844 }
845
846
847 RecordMonitorFullsize::RecordMonitorFullsize(MWindow *mwindow,
848         RecordMonitorGUI *window)
849  : BC_MenuItem(_("Zoom 100%"))
850 {
851         this->mwindow = mwindow;
852         this->window = window;
853 }
854 int RecordMonitorFullsize::handle_event()
855 {
856         return 1;
857 }
858
859
860
861
862
863
864
865
866 // ================================== slippery playback ============================
867
868
869 RecordMonitorThread::RecordMonitorThread(MWindow *mwindow,
870         Record *record,
871         RecordMonitor *record_monitor)
872  : Thread(1, 0, 0)
873 {
874         this->mwindow = mwindow;
875         this->record_monitor = record_monitor;
876         this->record = record;
877         this->ovly = 0;
878         reset_parameters();
879         output_lock = new Condition(1, "RecordMonitor::output_lock");
880         input_lock = new Condition(1, "RecordMonitor::input_lock");
881 }
882
883 void RecordMonitorThread::reset_parameters()
884 {
885         input_frame = 0;
886         output_frame = 0;
887         shared_data = 0;
888         jpeg_engine = 0;
889         dv_engine = 0;
890         ready = 0;
891         done = 1;
892 }
893
894
895 RecordMonitorThread::~RecordMonitorThread()
896 {
897         stop_playback();
898         if( input_frame && !shared_data )
899                 delete input_frame;
900         delete ovly;
901         delete output_lock;
902         delete input_lock;
903 }
904
905 void RecordMonitorThread::init_output_format()
906 {
907 //printf("RecordMonitorThread::init_output_format 1\n");
908         switch(mwindow->edl->session->vconfig_in->driver) {
909         case SCREENCAPTURE:
910                 output_colormodel = record->vdevice->get_best_colormodel(record->default_asset);
911                 break;
912
913         case CAPTURE_BUZ:
914         case VIDEO4LINUX2JPEG:
915                 jpeg_engine = new RecVideoMJPGThread(record, this,
916                         mwindow->edl->session->vconfig_in->v4l2jpeg_in_fields);
917                 jpeg_engine->start_rendering();
918                 output_colormodel = BC_YUV422P;
919                 break;
920
921         case CAPTURE_FIREWIRE:
922         case CAPTURE_IEC61883:
923                 dv_engine = new RecVideoDVThread(record, this);
924                 dv_engine->start_rendering();
925                 output_colormodel = BC_YUV422P;
926                 break;
927
928         case CAPTURE_JPEG_WEBCAM:
929                 jpeg_engine = new RecVideoMJPGThread(record, this, 1);
930                 jpeg_engine->start_rendering();
931                 output_colormodel = BC_YUV420P;
932                 break;
933
934         case CAPTURE_YUYV_WEBCAM:
935                 output_colormodel = BC_YUV422;
936                 break;
937
938
939         case CAPTURE_DVB:
940         case VIDEO4LINUX:
941         case VIDEO4LINUX2:
942         case VIDEO4LINUX2MPEG:
943                 output_colormodel = record->vdevice->get_best_colormodel(record->default_asset);
944 //printf("RecordMonitorThread::init_output_format 2 %d\n", output_colormodel);
945                 break;
946         }
947 }
948
949 int RecordMonitorThread::start_playback()
950 {
951         ready = 1;
952         done = 0;
953         output_frame = 0;
954         output_lock->lock("RecordMonitorThread::start_playback");
955         Thread::start();
956         return 0;
957 }
958
959 int RecordMonitorThread::stop_playback()
960 {
961         if( done ) return 0;
962         done = 1;
963         output_lock->unlock();
964         Thread::join();
965 //printf("RecordMonitorThread::stop_playback 1\n");
966
967         switch(mwindow->edl->session->vconfig_in->driver) {
968         case CAPTURE_BUZ:
969         case VIDEO4LINUX2JPEG:
970                 if( jpeg_engine ) {
971                         jpeg_engine->stop_rendering();
972                         delete jpeg_engine;
973                         jpeg_engine = 0;
974                 }
975                 break;
976
977         case CAPTURE_FIREWIRE:
978         case CAPTURE_IEC61883:
979                 if( dv_engine ) {
980                         dv_engine->stop_rendering();
981                         delete dv_engine;
982                         dv_engine = 0;
983                 }
984                 break;
985         case CAPTURE_DVB:
986         case VIDEO4LINUX2MPEG:
987                 break;
988         }
989 //printf("RecordMonitorThread::stop_playback 4\n");
990
991         return 0;
992 }
993
994 int RecordMonitorThread::write_frame(VFrame *new_frame)
995 {
996         if( ready ) {
997                 ready = 0;
998                 shared_data = (new_frame->get_color_model() != BC_COMPRESSED);
999
1000
1001 // Need to wait until after Record creates the input device before starting monitor
1002 // because the input device deterimes the output format.
1003 // First time
1004                 if( !output_frame ) init_output_format();
1005                 if( !shared_data ) {
1006                         if(!input_frame) input_frame = new VFrame;
1007                         input_frame->allocate_compressed_data(new_frame->get_compressed_size());
1008                         memcpy(input_frame->get_data(),
1009                                 new_frame->get_data(),
1010                                 new_frame->get_compressed_size());
1011                         input_frame->set_compressed_size(new_frame->get_compressed_size());
1012                         input_frame->set_field2_offset(new_frame->get_field2_offset());
1013                 }
1014                 else {
1015                         input_lock->lock("RecordMonitorThread::write_frame");
1016                         input_frame = new_frame;
1017                 }
1018                 output_lock->unlock();
1019         }
1020         return 0;
1021 }
1022
1023 int RecordMonitorThread::render_jpeg()
1024 {
1025 //printf("RecordMonitorThread::render_jpeg 1\n");
1026         jpeg_engine->render_frame(input_frame, input_frame->get_compressed_size());
1027 //printf("RecordMonitorThread::render_jpeg 2\n");
1028         return 0;
1029 }
1030
1031 int RecordMonitorThread::render_dv()
1032 {
1033         dv_engine->render_frame(input_frame, input_frame->get_compressed_size());
1034         return 0;
1035 }
1036
1037 void RecordMonitorThread::render_uncompressed()
1038 {
1039         output_frame->copy_from(input_frame);
1040 }
1041
1042 void RecordMonitorThread::show_output_frame()
1043 {
1044         if( ovly && ovly->overlay(output_frame) )
1045                 undisplay_vframe();
1046         record_monitor->device->write_buffer(output_frame, record->edl);
1047 }
1048
1049
1050 void RecordMonitorThread::unlock_input()
1051 {
1052         if(shared_data) input_lock->unlock();
1053 }
1054
1055 void RecordMonitorThread::lock_input()
1056 {
1057         if(shared_data) input_lock->lock();
1058 }
1059
1060 int RecordMonitorThread::render_frame()
1061 {
1062         switch(mwindow->edl->session->vconfig_in->driver) {
1063         case CAPTURE_BUZ:
1064         case VIDEO4LINUX2JPEG:
1065         case CAPTURE_JPEG_WEBCAM:
1066                 render_jpeg();
1067                 break;
1068
1069         case CAPTURE_FIREWIRE:
1070         case CAPTURE_IEC61883:
1071                 render_dv();
1072                 break;
1073
1074         default:
1075                 render_uncompressed();
1076                 break;
1077         }
1078
1079         return 0;
1080 }
1081
1082 void RecordMonitorThread::new_output_frame()
1083 {
1084         record_monitor->device->new_output_buffer(&output_frame, output_colormodel);
1085 }
1086
1087 void RecordMonitorThread::
1088 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1089 {
1090         delete ovly;
1091         int ticks = secs * SESSION->vconfig_in->in_framerate;
1092         scale *= SESSION->vconfig_in->h / 1080.;
1093         ovly = new RecVideoOverlay(in, x, y, ticks, scale, alpha/255.);
1094 }
1095
1096 RecVideoOverlay::
1097 RecVideoOverlay(VFrame *vframe, int x, int y, int ticks, float scale, float alpha)
1098 {
1099         this->x = x;
1100         this->y = y;
1101         this->ticks = ticks;
1102         this->scale = scale;
1103         this->alpha = alpha;
1104         this->vframe = new VFrame(*vframe);
1105 }
1106
1107 RecVideoOverlay::
1108 ~RecVideoOverlay()
1109 {
1110         delete vframe;
1111 }
1112
1113 int RecVideoOverlay::
1114 overlay(VFrame *out)
1115 {
1116         VFrame *in = vframe;
1117         int xx = x * scale, yy = y * scale;
1118         int w = in->get_w(), h = in->get_h();
1119         int ww = w * scale, hh = h * scale;
1120         BC_CModels::transfer(out->get_rows(), in->get_rows(),
1121                 out->get_y(), out->get_u(), out->get_v(),
1122                 in->get_y(), in->get_u(), in->get_v(),
1123                 0, 0, w, h, xx, yy, ww, hh,
1124                 in->get_color_model(), out->get_color_model(), 0,
1125                 in->get_bytes_per_line(), out->get_bytes_per_line());
1126         return ticks > 0 && --ticks == 0 ? 1 : 0;
1127 }
1128
1129 void RecordMonitorThread::
1130 undisplay_vframe()
1131 {
1132         delete ovly;  ovly = 0;
1133 }
1134
1135 void RecordMonitorThread::run()
1136 {
1137 //printf("RecordMonitorThread::run 1 %d\n", getpid());
1138         while(!done) {
1139 // Wait for next frame
1140 //SET_TRACE
1141                 output_lock->lock("RecordMonitorThread::run");
1142
1143                 if(done) {
1144                         unlock_input();
1145                         return;
1146                 }
1147 //SET_TRACE
1148                 new_output_frame();
1149 //SET_TRACE
1150                 render_frame();
1151 //SET_TRACE
1152                 record_monitor->scope_thread->process(output_frame);
1153 //SET_TRACE
1154                 show_output_frame();
1155 //SET_TRACE
1156                 unlock_input();
1157 // Get next frame
1158                 ready = 1;
1159         }
1160 }
1161
1162
1163
1164 RecVideoMJPGThread::RecVideoMJPGThread(Record *record,
1165         RecordMonitorThread *thread,
1166         int fields)
1167 {
1168         this->record = record;
1169         this->thread = thread;
1170         mjpeg = 0;
1171         this->fields = fields;
1172 }
1173
1174 RecVideoMJPGThread::~RecVideoMJPGThread()
1175 {
1176 }
1177
1178 int RecVideoMJPGThread::start_rendering()
1179 {
1180         mjpeg = mjpeg_new(record->default_asset->width,
1181                 record->default_asset->height,
1182                 fields);
1183 //printf("RecVideoMJPGThread::start_rendering 1 %p\n", mjpeg);
1184         return 0;
1185 }
1186
1187 int RecVideoMJPGThread::stop_rendering()
1188 {
1189 //printf("RecVideoMJPGThread::stop_rendering 1 %p\n", mjpeg);
1190         if(mjpeg) mjpeg_delete(mjpeg);
1191 //printf("RecVideoMJPGThread::stop_rendering 2\n");
1192         return 0;
1193 }
1194
1195 int RecVideoMJPGThread::render_frame(VFrame *frame, long size)
1196 {
1197 // printf("RecVideoMJPGThread::render_frame %d %02x%02x %02x%02x\n",
1198 // frame->get_field2_offset(),
1199 // frame->get_data()[0],
1200 // frame->get_data()[1],
1201 // frame->get_data()[frame->get_field2_offset()],
1202 // frame->get_data()[frame->get_field2_offset() + 1]);
1203 //frame->set_field2_offset(0);
1204         mjpeg_decompress(mjpeg,
1205                 frame->get_data(),
1206                 frame->get_compressed_size(),
1207                 frame->get_field2_offset(),
1208                 thread->output_frame->get_rows(),
1209                 thread->output_frame->get_y(),
1210                 thread->output_frame->get_u(),
1211                 thread->output_frame->get_v(),
1212                 thread->output_frame->get_color_model(),
1213                 record->mwindow->preferences->processors);
1214         return 0;
1215 }
1216
1217
1218
1219
1220 RecVideoDVThread::RecVideoDVThread(Record *record, RecordMonitorThread *thread)
1221 {
1222         this->record = record;
1223         this->thread = thread;
1224         dv = 0;
1225 }
1226
1227 RecVideoDVThread::~RecVideoDVThread()
1228 {
1229 }
1230
1231
1232 int RecVideoDVThread::start_rendering()
1233 {
1234         dv = dv_new();
1235         return 0;
1236 }
1237
1238 int RecVideoDVThread::stop_rendering()
1239 {
1240         if( dv ) { dv_delete(((dv_t*)dv));  dv = 0; }
1241         return 0;
1242 }
1243
1244 int RecVideoDVThread::render_frame(VFrame *frame, long size)
1245 {
1246         unsigned char *yuv_planes[3];
1247         yuv_planes[0] = thread->output_frame->get_y();
1248         yuv_planes[1] = thread->output_frame->get_u();
1249         yuv_planes[2] = thread->output_frame->get_v();
1250         dv_read_video(((dv_t*)dv),
1251                 yuv_planes,
1252                 frame->get_data(),
1253                 frame->get_compressed_size(),
1254                 thread->output_frame->get_color_model());
1255
1256         return 0;
1257 }
1258