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