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