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