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