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