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