prevent popup deactivation while button_down
[goodguy/history.git] / cinelerra-5.0 / cinelerra / record.C
1 /*
2  * CINELERRA
3  * Copyright (C) 2009-2013 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 "assets.h"
23 #include "audiodevice.h"
24 #include "awindow.h"
25 #include "awindowgui.h"
26 #include "batch.h"
27 #include "bchash.h"
28 #include "channel.h"
29 #include "channeldb.h"
30 #include "channelpicker.h"
31 #include "clip.h"
32 #include "commercials.h"
33 #include "condition.h"
34 #include "cwindow.h"
35 #include "devicedvbinput.h"
36 #include "drivesync.h"
37 #include "edl.h"
38 #include "edlsession.h"
39 #include "errorbox.h"
40 #include "file.h"
41 #include "filexml.h"
42 #include "filesystem.h"
43 #include "filethread.h"
44 #include "format.inc"
45 #include "formatcheck.h"
46 #include "indexfile.h"
47 #include "keys.h"
48 #include "language.h"
49 #include "localsession.h"
50 #include "libdv.h"
51 #include "libmjpeg.h"
52 #include "mainmenu.h"
53 #include "mainundo.h"
54 #include "mwindow.h"
55 #include "mwindowgui.h"
56 #include "mutex.h"
57 #include "picture.h"
58 #include "playbackengine.h"
59 #include "preferences.h"
60 #include "record.h"
61 #include "recordaudio.h"
62 #include "recordconfig.h"
63 #include "recordgui.h"
64 #include "recordlabel.h"
65 #include "recordmonitor.h"
66 #include "recordprefs.inc"
67 #include "recordthread.h"
68 #include "recordvideo.h"
69 #include "removefile.h"
70 #include "mainsession.h"
71 #include "sighandler.h"
72 #include "testobject.h"
73 #include "theme.h"
74 #include "timebar.h"
75 #include "tracks.h"
76 #include "videoconfig.h"
77 #include "videodevice.h"
78
79 #include <string.h>
80 #include <sys/types.h>
81 #include <sys/wait.h>
82
83
84 RecordMenuItem::RecordMenuItem(MWindow *mwindow)
85  : BC_MenuItem(_("Record..."), "r", 'r')
86 {
87         this->mwindow = mwindow;
88         record = new Record(mwindow, this);
89 }
90
91 RecordMenuItem::~RecordMenuItem()
92 {
93         delete record;
94 }
95
96 int RecordMenuItem::handle_event()
97 {
98         record->start();
99         return 1;
100 }
101
102
103 Record::Record(MWindow *mwindow, RecordMenuItem *menu_item)
104  : Thread(1, 0, 0),
105    record_batches(mwindow)
106 {
107         this->mwindow = mwindow;
108         this->menu_item = menu_item;
109         mwindow->gui->record = this;
110         adevice = 0;
111         vdevice = 0;
112         file = 0;
113         picture = new PictureConfig();
114         channeldb = new ChannelDB;
115         master_channel = new Channel;
116         record_channel = new RecordChannel(this);
117         channel = 0;
118         current_channel = 0;
119         default_asset = 0;
120         load_mode = 0 ;
121         pause_lock = new Mutex("Record::pause_lock");
122         init_lock = new Condition(0,"Record::init_lock");
123         record_audio = 0;
124         record_video = 0;
125         record_thread = 0;
126         record_monitor = 0;
127         record_gui = 0;
128         session_sample_offset = 0;
129         device_sample_offset = 0;
130         recording = 0;
131         capturing = 0;
132         single_frame = 0;
133         writing_file = 0;
134         drop_overrun_frames = 0;
135         fill_underrun_frames = 0;
136         power_off = 0;
137         commercial_check = skimming_active = 0;
138         commercial_start_time = -1;
139         commercial_fd = -1;
140         deletions = 0;
141         status_color = -1;
142         keybfr[0] = 0;
143         last_key = -1;
144         do_audio = 0;
145         do_video = 0;
146         current_frame = written_frames = total_frames = 0;
147         current_sample = written_samples = total_samples = 0;
148         audio_time = video_time = -1.;
149         play_gain = mute_gain = 1.;
150         drivesync = 0;
151         input_threads_pausing = 0;
152         window_lock = new Mutex("Record::window_lock");
153         timer_lock = new Mutex("Record::timer_lock");
154         file_lock = new Mutex("Record::file_lock");
155         adevice_lock = new Mutex("Record::adevice_lock");
156         vdevice_lock = new Mutex("Record::vdevice_lock");
157         batch_lock = new Mutex("Record::batch_lock");
158         skim_thread = new SkimDbThread();
159         cutads_status = new RecordCutAdsStatus(this);
160         blink_status = new RecordBlinkStatus(this);
161 }
162
163 Record::~Record()
164 {
165         mwindow->gui->record = 0;
166         stop();  join();
167         delete blink_status;
168         delete cutads_status;
169         stop_skimming();
170         delete skim_thread;
171         delete deletions;
172         delete picture;
173         delete channeldb;
174         delete record_channel;
175         delete master_channel;
176         delete window_lock;
177         delete timer_lock;
178         delete record_audio;
179         delete record_video;
180         delete adevice_lock;
181         delete vdevice_lock;
182         delete batch_lock;
183         delete file_lock;
184         delete pause_lock;
185         delete init_lock;
186 }
187
188 int Record::load_defaults()
189 {
190
191         char string[BCTEXTLEN];
192         BC_Hash *defaults = mwindow->defaults;
193         EDLSession *session = SESSION;
194         default_asset->copy_from(session->recording_format, 0);
195         default_asset->channels = session->aconfig_in->channels;
196         default_asset->sample_rate = session->aconfig_in->in_samplerate;
197         default_asset->frame_rate = session->vconfig_in->in_framerate;
198         default_asset->width = session->vconfig_in->w;
199         default_asset->height = session->vconfig_in->h;
200         default_asset->layers = 1;
201 // Fix encoding parameters depending on driver.
202 // These are locked by a specific driver.
203         const char *vcodec = 0;
204         switch( session->vconfig_in->driver ) {
205         case CAPTURE_LML:
206         case CAPTURE_BUZ:
207                 vcodec = CODEC_TAG_MJPEG;
208                 break;
209         case CAPTURE_DVB:
210         case VIDEO4LINUX2MPEG:
211                 break;
212         case VIDEO4LINUX2JPEG:
213                 vcodec = CODEC_TAG_MJPEG;
214                 break;
215         case CAPTURE_FIREWIRE:
216         case CAPTURE_IEC61883:
217                 vcodec = CODEC_TAG_DVSD;
218                 break;
219         }
220         if( vcodec )
221                 strcpy(default_asset->vcodec, vcodec);
222
223         record_batches.load_defaults(channeldb, this);
224
225         int cur_chan_no = defaults->get("RECORD_CURRENT_CHANNEL", 0);
226         current_channel = channeldb->get(cur_chan_no);
227         load_mode = defaults->get("RECORD_LOADMODE", LOADMODE_PASTE);
228         monitor_audio = defaults->get("RECORD_MONITOR_AUDIO", 1);
229         metering_audio = defaults->get("RECORD_METERING_AUDIO", 1);
230         monitor_video = defaults->get("RECORD_MONITOR_VIDEO", 1);
231         video_window_open = defaults->get("RECORD_MONITOR_OPEN", 1);
232         video_x = defaults->get("RECORD_VIDEO_X", 0);
233         video_y = defaults->get("RECORD_VIDEO_Y", 0);
234         video_zoom = defaults->get("RECORD_VIDEO_Z", (float)1);
235         picture->load_defaults();
236         reverse_interlace = defaults->get("REVERSE_INTERLACE", 0);
237         for( int i=0; i<MAXCHANNELS; ++i ) {
238                 sprintf(string, "RECORD_DCOFFSET_%d", i);
239                 dc_offset[i] = defaults->get(string, 0);
240         }
241         drop_overrun_frames = defaults->get("DROP_OVERRUN_FRAMES", 0);
242         fill_underrun_frames = defaults->get("FILL_UNDERRUN_FRAMES", 0);
243         commercial_check = defaults->get("COMMERCIAL_CHECK", 0);
244         return 0;
245 }
246
247 int Record::save_defaults()
248 {
249         char string[BCTEXTLEN];
250         BC_Hash *defaults = mwindow->defaults;
251         set_editing_batch(0);
252 // Save default asset path but not the format because that's
253 // overridden by the driver.
254 // The format is saved in preferences.
255         if( record_batches.total() )
256                 strcpy(default_asset->path, record_batches[0]->asset->path);
257         default_asset->save_defaults(defaults, "RECORD_", 0, 0, 0, 0, 0);
258
259         record_batches.save_defaults(channeldb);
260
261         int cur_chan_no = channeldb->number_of(current_channel);
262         defaults->update("RECORD_CURRENT_CHANNEL", cur_chan_no);
263         defaults->update("RECORD_LOADMODE", load_mode);
264         defaults->update("RECORD_MONITOR_AUDIO", monitor_audio);
265         defaults->update("RECORD_METERING_AUDIO", metering_audio);
266         defaults->update("RECORD_MONITOR_VIDEO", monitor_video);
267         defaults->update("RECORD_MONITOR_OPEN", video_window_open);
268         defaults->update("RECORD_VIDEO_X", video_x);
269         defaults->update("RECORD_VIDEO_Y", video_y);
270         defaults->update("RECORD_VIDEO_Z", video_zoom);
271         picture->save_defaults();
272         defaults->update("REVERSE_INTERLACE", reverse_interlace);
273         for( int i=0; i<MAXCHANNELS; ++i ) {
274                 sprintf(string, "RECORD_DCOFFSET_%d", i);
275                 defaults->update(string, dc_offset[i]);
276         }
277         defaults->update("DROP_OVERRUN_FRAMES", drop_overrun_frames);
278         defaults->update("FILL_UNDERRUN_FRAMES", fill_underrun_frames);
279         defaults->update("COMMERCIAL_CHECK", commercial_check);
280 SET_TRACE
281
282         return 0;
283 }
284
285 void Record::configure_batches()
286 {
287 // printf("Record::configure_batches %d\n",__LINE__);
288 // default_assset->dump();
289         strcpy(record_batches[0]->asset->path, default_asset->path);
290         int total_batches = record_batches.total();
291         for( int i=0; i<total_batches; ++i ) {
292                 Batch *batch = record_batches[i];
293                 batch->asset->copy_format(default_asset);
294         }
295 }
296
297 void Record::run()
298 {
299         int result = 0;
300         record_gui = 0;
301 // Default asset forms the first path in the batch capture
302 // and the file format for all operations.
303         default_asset = new Asset;
304
305 // Determine information about the device.
306         AudioInConfig *aconfig_in = SESSION->aconfig_in;
307         VideoInConfig *vconfig_in = SESSION->vconfig_in;
308         int driver = vconfig_in->driver;
309         VideoDevice::load_channeldb(channeldb, vconfig_in);
310         fixed_compression = VideoDevice::is_compressed(driver, 0, 1);
311         load_defaults();
312 // Apply a major kludge
313         if( fixed_compression ) {
314                 VideoDevice device;
315                 device.fix_asset(default_asset, driver);
316         }
317         default_asset->channels = aconfig_in->channels;
318         VideoDevice::save_channeldb(channeldb, vconfig_in);
319         save_defaults();
320         mwindow->save_defaults();
321         configure_batches();
322         set_current_batch(0);
323         set_editing_batch(0);
324
325 // Run recordgui
326         edl = new EDL;
327         edl->create_objects();
328         edl->session->output_w = default_asset->width;
329         edl->session->output_h = default_asset->height;
330         edl->session->aspect_w = SESSION->aspect_w;
331         edl->session->aspect_h = SESSION->aspect_h;
332
333         window_lock->lock("Record::run 3");
334         record_gui = new RecordGUI(mwindow, this);
335         record_gui->create_objects();
336
337         record_monitor = new RecordMonitor(mwindow, this);
338         record_monitor->create_objects();
339         record_gui->update_batch_sources();
340
341         record_gui->show_window();
342         record_gui->flush();
343
344         if( mwindow->gui->remote_control->deactivate() )
345                 mwindow->gui->record_remote_handler->activate();
346
347         if( video_window_open ) {
348                 record_monitor->window->show_window();
349                 record_monitor->window->raise_window();
350                 record_monitor->window->flush();
351         }
352
353         window_lock->unlock();
354         channel = 0;
355         start_input_threads();
356         update_position();
357         init_lock->unlock();
358
359         result = record_gui->run_window();
360 // record gui operates here until window is closed
361 // wait for it
362         if( record_gui->get_window_lock() ) {
363                 record_gui->lock_window();
364                 record_gui->unlock_window();
365         }
366
367 // Need to stop everything this time
368
369         stop_commercial_capture(0);
370         int video_stream = -1;
371         if( default_asset->format == FILE_MPEG ) {
372                 Channel *channel = get_current_channel();
373                 if( channel )
374                         video_stream = channel->video_stream;
375         }
376         stop();
377         edl->Garbage::remove_user();
378
379         if( mwindow->gui->remote_control->deactivate() )
380                 mwindow->gui->cwindow_remote_handler->activate();
381
382 // Save everything again
383         save_defaults();
384
385 // Paste into EDL
386         if( !result && load_mode != LOADMODE_NOTHING ) {
387                 mwindow->gui->lock_window("Record::run");
388                 ArrayList<EDL*> new_edls;
389 // Paste assets
390                 int total_batches = record_batches.total();
391                 for( int i=0; i<total_batches; ++i ) {
392                         Batch *batch = record_batches[i];
393                         Asset *asset = batch->asset;
394                         if( batch->recorded ) {
395                                 EDL *new_edl = new EDL;
396                                 mwindow->remove_asset_from_caches(asset);
397                                 new_edl->create_objects();
398                                 new_edl->copy_session(mwindow->edl);
399                                 mwindow->asset_to_edl(new_edl, asset, batch->labels);
400                                 new_edls.append(new_edl);
401                         }
402                 }
403
404                 if(new_edls.total) {
405                         mwindow->undo->update_undo_before();
406 // For pasting, clear the active region
407                         if(load_mode == LOADMODE_PASTE)
408                                 mwindow->clear(0);
409
410                         mwindow->paste_edls(&new_edls, load_mode, 0, -1,
411                                 SESSION->labels_follow_edits,
412                                 SESSION->plugins_follow_edits,
413                                 SESSION->autos_follow_edits);
414                         for( int i=0; i<new_edls.total; ++i )
415                                 new_edls.get(i)->Garbage::remove_user();
416                         new_edls.remove_all();
417                         if( video_stream >= 0 ) {
418                                 mwindow->select_asset(video_stream, -1);
419                                 mwindow->fit_selection();
420                         }
421                         mwindow->save_backup();
422                         mwindow->undo->update_undo_after(_("record"), LOAD_ALL);
423                         mwindow->restart_brender();
424                         mwindow->update_plugin_guis();
425                         mwindow->gui->update(1, 2, 1, 1, 1, 1, 0);
426                         mwindow->sync_parameters(CHANGE_ALL);
427                 }
428                 mwindow->gui->unlock_window();
429
430                 AWindowGUI *agui = mwindow->awindow->gui;
431                 agui->lock_window("Record::record");
432                 agui->update_assets();
433                 agui->flush();
434                 agui->unlock_window();
435         }
436
437 // Delete everything
438         record_batches.clear();
439         default_asset->Garbage::remove_user();
440 }
441
442 void Record::stop()
443 {
444         stop_operation();
445         window_lock->lock("Record::stop");
446         delete record_thread;   record_thread = 0;
447         delete record_monitor;  record_monitor = 0;
448         delete record_gui;      record_gui = 0;
449         window_lock->unlock();
450 }
451
452 void Record::activate_batch(int number)
453 {
454         if( number != current_batch() ) {
455                 stop_writing();
456                 set_current_batch(number);
457                 record_gui->update_batches();
458                 record_gui->update_position(current_display_position());
459                 record_gui->update_batch_tools();
460         }
461 }
462
463
464 void Record::delete_index_file(Asset *asset)
465 {
466         IndexFile::delete_index(mwindow->preferences, asset, ".toc");
467         IndexFile::delete_index(mwindow->preferences, asset, ".idx");
468         IndexFile::delete_index(mwindow->preferences, asset, ".mkr");
469 }
470
471 void Record::delete_batch()
472 {
473 // Abort if one batch left
474         int edit_batch = editing_batch();
475         int total_batches = record_batches.total();
476         if( total_batches > 1 && edit_batch < total_batches ) {
477                 int cur_batch = current_batch();
478                 Batch *batch = record_batches[edit_batch];
479                 record_batches.remove(batch);  delete batch;
480                 if( cur_batch == edit_batch ) stop_writing();
481                 record_gui->update_batches();
482                 record_gui->update_batch_tools();
483         }
484 }
485
486 void Record::change_editing_batch(int number)
487 {
488         set_editing_batch(number);
489         record_gui->update_batch_tools();
490 }
491
492 Batch* Record::new_batch()
493 {
494         Batch *batch = new Batch(mwindow, this);
495 //printf("Record::new_batch 1\n");
496         batch->create_objects();
497         record_batches.append(batch);
498         batch->asset->copy_format(default_asset);
499
500 //printf("Record::new_batch 1\n");
501         batch->create_default_path();
502         Batch *edit_batch = get_editing_batch();
503         if( edit_batch )
504                 batch->copy_from(edit_batch);
505         int total_batches = record_batches.total();
506         set_editing_batch(total_batches - 1);
507 //printf("Record::new_batch 1\n");
508 // Update GUI if created yet
509         if(record_gui)
510                 record_gui->update_batch_tools();
511 //printf("Record::new_batch 2\n");
512         return batch;
513 }
514
515 int Record::current_batch()
516 {
517         return record_batches.current_item;
518 }
519
520 int Record::set_current_batch(int i)
521 {
522         return record_batches.current_item = i;
523 }
524
525 int Record::editing_batch()
526 {
527         return record_batches.editing_item;
528 }
529
530 int Record::set_editing_batch(int i)
531 {
532         return record_batches.editing_item = i;
533 }
534
535 int Record::delete_output_file()
536 {
537         Batch *batch = get_current_batch();
538 // Delete old file
539         if( !file && batch && !access(batch->asset->path, F_OK) ) {
540                 batch->set_notice(_("Deleting"));
541                 record_gui->update_batches();
542                 Asset *asset = batch->asset;
543                 remove_file(asset->path);
544                 mwindow->remove_asset_from_caches(asset);
545                 delete_index_file(asset);
546                 batch->clear_notice();
547                 record_gui->update_batches();
548         } while(0);
549         return 0;
550 }
551
552 int Record::open_output_file()
553 {
554         int result = 0;
555         file_lock->lock();
556         Batch *batch = get_current_batch();
557         if( !file && batch ) {
558                 delete_output_file();
559                 Asset *asset = batch->asset;
560                 asset->frame_rate = default_asset->frame_rate;
561                 asset->sample_rate = default_asset->sample_rate;
562                 asset->width = default_asset->width;
563                 asset->height = default_asset->height;
564                 int wr = 1;
565                 if( default_asset->format == FILE_MPEG ) {
566                         asset->layers = vdevice ? vdevice->total_video_streams() : 0;
567                         asset->channels = adevice ? adevice->total_audio_channels() : 0;
568                         wr = 0;
569                 }
570                 file = new File;
571                 result = file->open_file(mwindow->preferences, asset, 0, wr);
572                 if( !result ) {
573                         mwindow->sighandler->push_file(file);
574                         batch->recorded = 1;
575                         file->set_processors(mwindow->preferences->real_processors);
576                         record_gui->update_batches();
577                 }
578                 else {
579                         delete file;
580                         file = 0;
581                 }
582         }
583         file_lock->unlock();
584         return result;
585 }
586
587 void Record::start()
588 {
589         if( running() ) {
590                 window_lock->lock("Record::start");
591                 record_gui->lock_window("Record::start");
592                 record_gui->raise_window();
593                 record_gui->unlock_window();
594                 window_lock->unlock();
595         }
596         else {
597                 stop();  join();
598                 init_lock->reset();
599                 Thread::start();
600         }
601 }
602
603 void Record::start_over()
604 {
605         stop_writing();
606         Batch *batch = get_current_batch();
607         if( batch ) batch->start_over();
608         record_gui->update_batches();
609 }
610
611 void Record::stop_operation()
612 {
613         stop_writing();
614         stop_input_threads();
615 }
616
617 int Record::cron_active()
618 {
619         return !record_thread ? 0 : record_thread->cron_active;
620 }
621
622 void Record::close_output_file()
623 {
624         file_lock->lock();
625         if( file ) {
626                 mwindow->sighandler->pull_file(file);
627                 file->close_file();
628                 delete file;
629                 file = 0;
630         }
631         file_lock->unlock();
632         record_gui->update_batches();
633 }
634
635 void Record::toggle_label()
636 {
637         Batch *batch = get_current_batch();
638         if( batch ) batch->toggle_label(current_display_position());
639         record_gui->update_labels(current_display_position());
640 }
641
642 void Record::clear_labels()
643 {
644         Batch *batch = get_current_batch();
645         if( batch ) batch->clear_labels();
646         record_gui->update_labels(0);
647 }
648
649 int Record::get_fragment_samples()
650 {
651         const int min_samples = 1024, max_samples = 32768;
652         int samples, low_bit;
653         samples = default_asset->sample_rate / SESSION->record_speed;
654         if( samples < min_samples ) samples = min_samples;
655         else if( samples > max_samples ) samples = max_samples;
656         // loop until only one bit left standing
657         while( (low_bit=(samples & ~(samples-1))) != samples )
658                 samples += low_bit;
659         return samples;
660 }
661
662 int Record::get_buffer_samples()
663 {
664         int fragment_samples = get_fragment_samples();
665         if( !fragment_samples ) return 0;
666         int fragments = (SESSION->record_write_length+fragment_samples-1) / fragment_samples;
667         if( fragments < 1 ) fragments = 1;
668         return fragments * fragment_samples;
669 }
670
671 Batch* Record::get_current_batch()
672 {
673         return record_batches.get_current_batch();
674 }
675
676 Batch* Record::get_editing_batch()
677 {
678         return record_batches.get_editing_batch();
679 }
680
681 int Record::get_next_batch(int incr)
682 {
683         int i = current_batch();
684         if( i >= 0 ) {
685                 i += incr;
686                 int total_batches = record_batches.total();
687                 while( i < total_batches ) {
688                         if( record_batches[i]->enabled ) return i;
689                         ++i;
690                 }
691         }
692         return -1;
693 }
694
695 const char* Record::current_mode()
696 {
697         Batch *batch = get_current_batch();
698         return batch ? Batch::mode_to_text(batch->record_mode) : "";
699 }
700
701 double Record::current_display_position()
702 {
703 //printf("Record::current_display_position "
704 //  _LD " " _LD "\n", total_samples, total_frames)
705         double result = -1.;
706         Asset *asset = default_asset;
707         if( writing_file ) {
708                 if( asset->video_data && record_video )
709                         result = (double) written_frames / asset->frame_rate;
710                 else if( asset->audio_data && record_audio )
711                         result = (double) written_samples / asset->sample_rate;
712         }
713         if( result < 0. ) {
714                 if( asset->video_data && record_video )
715                         result = (double) total_frames / asset->frame_rate;
716                 else if( asset->audio_data && record_audio )
717                         result = (double) total_samples / asset->sample_rate;
718                 else
719                         result = (double) total_time.get_difference() / 1000.;
720         }
721         return result;
722 }
723
724 const char* Record::current_source()
725 {
726         Batch *batch = get_current_batch();
727         return batch ? batch->get_source_text() : _("Unknown");
728 }
729
730 Asset* Record::current_asset()
731 {
732         Batch *batch = get_current_batch();
733         return batch ? batch->asset : 0;
734 }
735
736 Channel *Record::get_current_channel()
737 {
738         return current_channel;
739 }
740
741 Channel *Record::get_editing_channel()
742 {
743         Batch *batch = get_editing_batch();
744         return batch ? batch->channel : 0;
745 }
746
747 ArrayList<Channel*>* Record::get_video_inputs() 
748
749         return default_asset->video_data && vdevice ? vdevice->get_inputs() : 0;
750 }
751
752
753 int64_t Record::timer_position()
754 {
755         timer_lock->lock("RecordAudio::timer_positioin");
756         int samplerate = default_asset->sample_rate;
757         int64_t result = timer.get_scaled_difference(samplerate);
758         result += session_sample_offset;
759         timer_lock->unlock();
760         return result;
761 }
762
763 void Record::reset_position(int64_t position)
764 {
765         timer_lock->lock("RecordAudio::reset_position");
766         session_sample_offset = position;
767         device_sample_offset = adevice ? adevice->current_position() : 0;
768         timer.update();
769         timer_lock->unlock();
770 }
771
772 void Record::update_position()
773 {
774         int64_t position = sync_position();
775         reset_position(position);
776         current_frame = current_sample = 0;
777         audio_time = video_time = -1.;
778 }
779
780 int64_t Record::adevice_position()
781 {
782         timer_lock->lock("RecordAudio::adevice_position");
783         int64_t result = adevice->current_position();
784         result += session_sample_offset - device_sample_offset;
785         timer_lock->unlock();
786         return result;
787 }
788
789 int64_t Record::sync_position()
790 {
791         int64_t sync_position = -1;
792         double sync_time = -1.;
793         double next_audio_time = -1.;
794         double next_video_time = -1.;
795
796         if( current_frame == 0 && current_sample == 0 ) {
797                 audio_time = video_time = -1.;
798                 reset_position(0);
799         }
800         switch( SESSION->record_positioning ) {
801         case RECORD_POS_TIMESTAMPS:
802                 if( default_asset->video_data && record_video )
803                         next_video_time = vdevice->get_timestamp();
804                 if( default_asset->audio_data && record_audio ) {
805                         next_audio_time =
806                                  !adevice->is_monitoring() || writing_file > 0 ?
807                                         adevice->get_itimestamp() :
808                                         adevice->get_otimestamp();
809                 }
810                 if( next_audio_time >= 0. )
811                         sync_time = next_audio_time;
812                 else if( next_video_time > 0. )
813                         sync_time = next_video_time;
814                 if( sync_time >= 0. ) {
815                         sync_position = sync_time * default_asset->sample_rate;
816                 }
817                 if( sync_position >= 0 ) break;
818         case RECORD_POS_DEVICE:
819                 if( default_asset->audio_data && record_audio )
820                         sync_position = adevice_position();
821                 if( sync_position > 0 ) break;
822         case RECORD_POS_SOFTWARE:
823                 sync_position = timer_position();
824                 if( sync_position > 0 ) break;
825         case RECORD_POS_SAMPLE:
826         default:
827                 sync_position = current_sample;
828                 break;
829         }
830
831         if( next_video_time < 0. )
832                 next_video_time = current_frame / default_asset->frame_rate;
833         if( next_video_time > video_time )
834                 video_time = next_video_time;
835         if( next_audio_time < 0. )
836                 next_audio_time = (double)sync_position / default_asset->sample_rate;
837         if( next_audio_time > audio_time )
838                 audio_time = next_audio_time;
839
840         return sync_position;
841 }
842
843
844 void Record::adevice_drain()
845 {
846         if( adevice && record_audio ) {
847                 adevice->stop_audio(0);
848                 adevice->start_recording();
849         }
850 }
851
852
853 #define dbmsg if( debug ) printf
854 void Record::resync()
855 {
856         dropped = behind = 0;
857         int64_t audio_position = sync_position();
858         double audiotime = (double) audio_position / default_asset->sample_rate;
859         double diff = video_time - audiotime;
860         const int debug = 0;
861         dbmsg("resync video %f audio %f/%f diff %f",
862                 video_time, audiotime, audio_time, diff);
863         if( fabs(diff) > 5. ) {
864                 dbmsg("  drain audio");
865 // jam job dvb file tesing, comment next line
866                 record_channel->drain_audio();
867         }
868         else if( diff > 0. ) {
869                 int64_t delay = (int64_t)(1000.0 * diff);
870                 dbmsg("  delay " _LDv(8), delay);
871                 if( delay > 500 ) {
872                         video_time = audio_time = -1.;
873                         delay = 500;
874                 }
875                 if( delay > 1 )
876                         Timer::delay(delay);
877         }
878         else {
879                 behind = (int)(-diff * default_asset->frame_rate);
880                 dbmsg("  behind %d", behind);
881                 if( behind > 1 && fill_underrun_frames ) {
882                         dropped = behind > 3 ? 3 : behind-1;
883                         dbmsg("  dropped %d", dropped);
884                 }
885         }
886         dbmsg("\n");
887         int frames = dropped + 1;
888         current_frame += frames;
889         total_frames += frames;
890         record_gui->update_video(dropped, behind);
891         if( dropped > 0 && drop_overrun_frames )
892                 if( vdevice ) vdevice->drop_frames(dropped);
893 }
894
895
896 void Record::close_audio_input()
897 {
898         adevice_lock->lock();
899         if( adevice ) {
900                 adevice->close_all();
901                 delete adevice;
902                 adevice = 0;
903         }
904         adevice_lock->unlock();
905 }
906
907 void Record::close_video_input()
908 {
909         vdevice_lock->lock();
910         if( vdevice ) {
911                 vdevice->close_all();
912                 delete vdevice;
913                 vdevice = 0;
914         }
915         vdevice_lock->unlock();
916 }
917
918 void Record::close_input_devices()
919 {
920         close_audio_input();
921         close_video_input();
922 }
923
924 void Record::stop_audio_thread()
925 {
926         if( record_audio ) {
927                 record_audio->stop_recording();
928                 delete record_audio;
929                 record_audio = 0;
930         }
931         close_audio_input();
932         recording = 0;
933 }
934
935 void Record::stop_video_thread()
936 {
937         if( record_video ) {
938                 record_video->stop_recording();
939                 delete record_video;
940                 record_video = 0;
941         }
942         close_video_input();
943         capturing = 0;
944         single_frame = 0;
945 }
946
947 void Record::stop_input_threads()
948 {
949         pause_lock->lock("Record::stop_input_threads");
950         stop_skimming();
951         stop_playback();
952         stop_audio_thread();
953         stop_video_thread();
954         pause_lock->unlock();
955 }
956
957 void Record::stop_playback()
958 {
959         if( record_monitor )
960                 record_monitor->stop_playback();
961 }
962
963 void Record::open_audio_input()
964 {
965         close_audio_input();
966         adevice_lock->lock();
967 // Create devices
968         if( default_asset->audio_data )
969                 adevice = new AudioDevice(mwindow);
970 // Configure audio
971         if( adevice ) {
972                 int sw_pos = SESSION->record_positioning == RECORD_POS_SOFTWARE;
973                 adevice->set_software_positioning(sw_pos);
974                 adevice->open_input(SESSION->aconfig_in, SESSION->vconfig_in, 
975                         default_asset->sample_rate, get_fragment_samples(),
976                         default_asset->channels, SESSION->real_time_record);
977                 adevice->start_recording();
978                 adevice->open_monitor(SESSION->playback_config->aconfig,monitor_audio); 
979                 adevice->set_vdevice(vdevice);
980                 if( vdevice ) vdevice->set_adevice(adevice);
981         }
982         adevice_lock->unlock();
983 }
984
985 void Record::open_video_input()
986 {
987         close_video_input();
988         vdevice_lock->lock();
989         if( default_asset->video_data )
990                 vdevice = new VideoDevice(mwindow);
991 // Initialize video
992         if( vdevice ) {
993                 vdevice->set_quality(default_asset->jpeg_quality);
994                 vdevice->open_input(SESSION->vconfig_in, video_x, video_y,
995                         video_zoom, default_asset->frame_rate);
996 // Get configuration parameters from device probe
997                 color_model = vdevice->get_best_colormodel(default_asset);
998                 master_channel->copy_usage(vdevice->channel);
999                 picture->copy_usage(vdevice->picture);
1000                 vdevice->set_field_order(reverse_interlace);
1001                 vdevice->set_adevice(adevice);
1002                 if( adevice ) adevice->set_vdevice(vdevice);
1003                 set_dev_channel(get_current_channel());
1004         }
1005         vdevice_lock->unlock();
1006 }
1007
1008 void Record::start_audio_thread()
1009 {
1010         open_audio_input();
1011         if( !record_audio ) {
1012                 total_samples = current_sample = 0;  audio_time = -1.;
1013                 record_audio = new RecordAudio(mwindow,this);
1014                 record_audio->arm_recording();
1015                 record_audio->start_recording();
1016         }
1017         recording = 1;
1018 }
1019
1020 void Record::start_video_thread()
1021 {
1022         open_video_input();
1023         if( !record_video ) {
1024                 total_frames = current_frame = 0;  video_time = -1.;
1025                 record_video = new RecordVideo(mwindow,this);
1026                 record_video->arm_recording();
1027                 record_video->start_recording();
1028         }
1029         capturing = 1;
1030 }
1031
1032 void Record::start_input_threads()
1033 {
1034         behind = 0;
1035         input_threads_pausing = 0;
1036         if( default_asset->audio_data )
1037                 start_audio_thread();
1038         if( default_asset->video_data )
1039                 start_video_thread();
1040         start_skimming();
1041 }
1042
1043 void Record::pause_input_threads()
1044 {
1045         pause_lock->lock("Record::pause_input_threads");
1046         input_threads_pausing = 1;
1047         stop_skimming();
1048         adevice_lock->lock();
1049         vdevice_lock->lock();
1050         if( record_audio )
1051                 record_audio->pause_recording();
1052         if( record_video )
1053                 record_video->pause_recording();
1054 }
1055
1056 void Record::resume_input_threads()
1057 {
1058         if( record_audio )
1059                 record_audio->resume_recording();
1060         if( record_video )
1061                 record_video->resume_recording();
1062         vdevice_lock->unlock();
1063         adevice_lock->unlock();
1064         input_threads_pausing = 0;
1065         start_skimming();
1066         pause_lock->unlock();
1067
1068 }
1069
1070 int Record::start_toc()
1071 {
1072         if( !mwindow->edl->session->record_realtime_toc ) return 0;
1073         Batch *batch = get_current_batch();
1074         Asset *asset = batch->asset;
1075         char source_filename[BCTEXTLEN], toc_path[BCTEXTLEN];
1076         IndexFile::get_index_filename(source_filename,
1077                 mwindow->preferences->index_directory, 
1078                 toc_path, asset->path,".toc");
1079         if( default_asset->video_data )
1080                 return vdevice->start_toc(asset->path, toc_path);
1081         if( default_asset->audio_data )
1082                 return adevice->start_toc(asset->path, toc_path);
1083         return -1;
1084 }
1085
1086 int Record::start_record(int fd)
1087 {
1088         start_toc();
1089         if( default_asset->video_data )
1090                 return vdevice->start_record(fd);
1091         if( default_asset->audio_data )
1092                 return adevice->start_record(fd);
1093         return -1;
1094 }
1095
1096 void Record::start_writing_file()
1097 {
1098         if( !writing_file ) {
1099                 written_frames = 0;
1100                 written_samples = 0;
1101                 do_video = File::supports_video(default_asset->format);
1102                 do_audio = File::supports_audio(default_asset->format);
1103                 if( single_frame ) do_audio = 0;
1104                 if( !do_video && single_frame )
1105                         single_frame = 0;
1106                 else if( !open_output_file() )
1107                         writing_file = default_asset->format == FILE_MPEG ? -1 : 1;
1108                 if( do_audio && record_audio && writing_file > 0 ) {
1109                         int buffer_samples = get_buffer_samples();
1110                         record_audio->set_write_buffer_samples(buffer_samples);
1111                         file->start_audio_thread(buffer_samples, FILE_RING_BUFFERS);
1112                 }
1113                 if( do_video && record_video && writing_file > 0 ) {
1114                         int disk_frames = SESSION->video_write_length;
1115                         int cmodel = vdevice->get_best_colormodel(default_asset);
1116                         int cpress = vdevice->is_compressed(1, 0);
1117                         file->start_video_thread(disk_frames, cmodel, FILE_RING_BUFFERS, cpress);
1118                 }
1119                 if( writing_file < 0 ) {
1120                         int fd = file->record_fd();
1121                         if( fd >= 0 )
1122                                 start_record(fd);
1123                 }
1124                 if( writing_file ) {
1125                         record_gui->start_flash_batch();
1126                         if( SESSION->record_sync_drives ) {
1127                                 drivesync = new DriveSync();
1128                                 drivesync->start();
1129                         }
1130                 }
1131         }
1132         update_position();
1133 }
1134
1135 int Record::stop_record()
1136 {
1137         if( default_asset->video_data )
1138                 return vdevice->stop_record();
1139         if( default_asset->audio_data )
1140                 return adevice->stop_record();
1141         return -1;
1142 }
1143
1144 void Record::flush_buffer()
1145 {
1146         if( record_audio )
1147                 record_audio->flush_buffer();
1148         if( record_video )
1149                 record_video->flush_buffer();
1150 }
1151
1152 void Record::stop_writing_file()
1153 {
1154         record_gui->stop_flash_batch();
1155         if( !writing_file ) return;
1156         if( writing_file > 0 )
1157                 flush_buffer();
1158         if( writing_file < 0 )
1159                 stop_record();
1160         close_output_file();
1161         writing_file = 0;
1162         Asset *asset = current_asset();
1163         asset->audio_length = written_samples;
1164         asset->video_length = written_frames;
1165         record_gui->flash_batch();
1166         if( drivesync ) {
1167                 drivesync->done = 1;
1168                 delete drivesync;
1169                 drivesync = 0;
1170         }
1171 }
1172
1173 void Record::stop_writing()
1174 {
1175         if( writing_file ) {
1176                 pause_input_threads();
1177                 stop_writing_file();
1178                 resume_input_threads();
1179         }
1180 }
1181
1182
1183 void Record::start_cron_thread()
1184 {
1185         if( cron_active() < 0 ) {
1186                 delete record_thread;
1187                 record_thread = 0;
1188         }
1189         if( !record_thread ) {
1190                 record_thread = new RecordThread(mwindow,this);
1191                 record_thread->start();
1192                 record_gui->disable_batch_buttons();
1193                 record_gui->update_cron_status(_("Running"));
1194         }
1195 }
1196
1197 void Record::stop_cron_thread(const char *msg)
1198 {
1199         if( record_thread ) {
1200                 delete record_thread;
1201                 record_thread = 0;
1202                 record_gui->enable_batch_buttons();
1203                 record_gui->update_cron_status(msg);
1204         }
1205 }
1206
1207 void Record::set_power_off(int value)
1208 {
1209         power_off = value;
1210         record_gui->power_off->update(value);
1211 }
1212
1213 int Record::set_video_picture()
1214 {
1215         if( default_asset->video_data && vdevice )
1216                 vdevice->set_picture(picture);
1217         return 0;
1218 }
1219
1220 void Record::set_translation(int x, int y)
1221 {
1222         video_x = x;
1223         video_y = y;
1224         if(default_asset->video_data && vdevice)
1225                 vdevice->set_translation(video_x, video_y);
1226 }
1227
1228 int Record::set_channel(Channel *channel)
1229 {
1230         if( !channel ) return 1;
1231 printf("set_channel %s\n",channel->title);
1232         if( record_channel->set(channel) ) return 1;
1233         RecordMonitorGUI *window = record_monitor->window;
1234         window->lock_window("Record::set_channel");
1235         window->channel_picker->channel_text->update(channel->title);
1236         window->unlock_window();
1237         return 0;
1238 }
1239
1240 int Record::set_channel_no(int chan_no)
1241 {
1242         if( chan_no < 0 || chan_no >= channeldb->size() ) return 1;
1243         Channel *channel = channeldb->get(chan_no);
1244         return set_channel(channel);
1245 }
1246
1247 int Record::channel_down()
1248 {
1249         Channel *channel = get_current_channel();
1250         if( !channel || !channeldb->size() ) return 1;
1251         int n = channeldb->number_of(channel);
1252         if( n < 0 ) return 1;
1253         if( --n < 0 ) n =  channeldb->size() - 1;
1254         return set_channel_no(n);
1255 }
1256
1257 int Record::channel_up()
1258 {
1259         Channel *channel = get_current_channel();
1260         if( !channel || !channeldb->size() ) return 1;
1261         int n = channeldb->number_of(channel);
1262         if( n < 0 ) return 1;
1263         if( ++n >=  channeldb->size() ) n = 0;
1264         return set_channel_no(n);
1265 }
1266
1267 int Record::set_channel_name(const char *name)
1268 {
1269         Channel *channel = 0;
1270         int ch = 0, nch = channeldb->size();
1271         while( ch < nch ) {
1272                 channel = channeldb->get(ch);
1273                 if( channel && !channel->cstrcmp(name) ) break;
1274                 ++ch;
1275         }
1276         if( ch >= nch || !channel ) return 1;
1277         return set_channel(channel);
1278 }
1279
1280 void Record::set_batch_channel_no(int chan_no)
1281 {
1282         Channel *channel = channeldb->get(chan_no);
1283         if( channel ) {
1284                 Batch *batch = get_editing_batch();
1285                 if( batch ) batch->channel = channel;
1286                 record_gui->batch_source->update(channel->title);
1287         }
1288 }
1289
1290 void Record::set_dev_channel(Channel *channel)
1291 {
1292         // should be tuner device, not vdevice
1293         if( channel && vdevice &&
1294             (!this->channel || *channel != *this->channel) ) {
1295                 current_channel = channel;
1296                 if( this->channel ) delete this->channel;
1297                 this->channel = new Channel(channel);
1298                 vdevice->set_channel(channel);
1299                 int strk = !SESSION->decode_subtitles ? -1 : SESSION->subtitle_number;
1300                 vdevice->set_captioning(strk);
1301                 set_video_picture();
1302 printf("new channel %s, has_signal=%d\n",channel->title,vdevice->has_signal());
1303                 total_frames = 0;
1304                 total_samples = 0;
1305                 total_time.update();
1306         }
1307 }
1308
1309 /* widget holds xlock and set_channel pauses rendering, deadlock */
1310 /*   use a background thread to update channel after widget sets it */
1311 RecordChannel::RecordChannel(Record *record)
1312  : Thread(1, 0, 0)
1313 {
1314         this->record = record;
1315         change_channel = new Condition(0,"RecordSetChannel::change_channel");
1316         channel_lock = new Condition(1,"Record::channel_lock",1);
1317         new_channel = 0;
1318         Thread::start();
1319 }
1320
1321 RecordChannel::~RecordChannel()
1322 {
1323         done = 1;
1324         change_channel->unlock();
1325         Thread::join();
1326         delete change_channel;
1327         delete channel_lock;
1328 }
1329
1330 int RecordChannel::set(Channel *channel)
1331 {
1332         if( !channel || new_channel ) return 1;
1333         new_channel = channel;
1334         channel_lock->lock();        // block has_signal
1335         change_channel->unlock();    // resume channel changer thread
1336         return 0;
1337 }
1338
1339 void RecordChannel::drain_audio()
1340 {
1341         if( !audio_drain ) {
1342                 audio_drain = 1;
1343                 change_channel->unlock();
1344         }
1345 }
1346
1347 void RecordChannel::run()
1348 {
1349         done = 0;
1350         while( !done ) {
1351                 change_channel->lock();
1352                 if( done ) break;
1353                 if( !new_channel && !audio_drain ) continue;
1354                 record->pause_input_threads();
1355                 if( new_channel ) {
1356                         record->set_dev_channel(new_channel);
1357                         record->record_gui->reset_video();
1358                         record->record_gui->reset_audio();
1359                         audio_drain = 0;
1360                 }
1361                 if( audio_drain ) {
1362                         audio_drain = 0;
1363                         record->adevice_drain();
1364                 }
1365                 record->update_position();
1366                 record->resume_input_threads();
1367                 if( new_channel ) {
1368                         new_channel = 0;
1369                         channel_lock->unlock();
1370                 }
1371         }
1372 }
1373
1374 int Record::has_signal()
1375 {
1376         record_channel->channel_lock->lock("Record::has_signal");
1377         record_channel->channel_lock->unlock();
1378         vdevice_lock->lock();
1379         int result = vdevice ? vdevice->has_signal() : 0;
1380         vdevice_lock->unlock();
1381         return result;
1382 }
1383
1384 int Record::create_channeldb(ArrayList<Channel*> *channeldb)
1385 {
1386         return vdevice ? vdevice->create_channeldb(channeldb) : 1;
1387 }
1388
1389
1390 void Record::set_audio_monitoring(int mode)
1391 {
1392         update_position();
1393         monitor_audio = mode;
1394         if( record_audio )
1395                 record_audio->set_monitoring(mode);
1396         record_gui->lock_window("Record::set_audio_monitoring");
1397         if( record_gui->monitor_audio )
1398                 record_gui->monitor_audio->update(mode);
1399         record_gui->unlock_window();
1400 }
1401
1402 void Record::set_audio_metering(int mode)
1403 {
1404         metering_audio = mode;
1405         record_gui->lock_window("Record::set_audio_metering");
1406         if( record_gui->meter_audio )
1407                 record_gui->meter_audio->update(mode);
1408         record_gui->unlock_window();
1409         RecordMonitorGUI *window = record_monitor->window;
1410         window->lock_window("Record::set_audio_metering 1");
1411         window->resize_event(window->get_w(),window->get_h());
1412         window->unlock_window();
1413 }
1414
1415
1416 void Record::set_video_monitoring(int mode)
1417 {
1418         monitor_video = mode;
1419         record_gui->lock_window("Record::set_video_monitoring");
1420         if( record_gui->monitor_video )
1421                 record_gui->monitor_video->update(mode);
1422         record_gui->flush();
1423         record_gui->unlock_window();
1424 }
1425
1426 int Record::get_time_format()
1427 {
1428         return SESSION->time_format;
1429 }
1430
1431 int Record::set_record_mode(int value)
1432 {
1433         Batch *batch = get_editing_batch();
1434         batch->record_mode = value;
1435         record_gui->update_batches();
1436         return 0;
1437 }
1438
1439 int Record::check_batch_complete()
1440 {
1441         int result = 0;
1442         batch_lock->lock();
1443         if( writing_file && cron_active() > 0 ) {
1444                 Batch *batch = get_current_batch();
1445                 if( batch && batch->recorded > 0 &&
1446                         batch->record_mode == RECORD_TIMED &&
1447                         current_display_position() >= batch->record_duration ) {
1448                         batch->recorded = -1;
1449                         batch->enabled = 0;
1450                         record_gui->update_batches();
1451                         record_thread->batch_timed_lock->unlock();
1452                         result = 1;
1453                 }
1454         }
1455         batch_lock->unlock();
1456         return result;
1457 }
1458
1459
1460 int Record::skimming(void *vp, int track)
1461 {
1462         return ((Record*)vp)->skimming(track);
1463 }
1464
1465 int Record::skimming(int track)
1466 {
1467         int64_t framenum; uint8_t *tdat; int mw, mh;
1468         if( !vdevice ) return -1;
1469         if( vdevice->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
1470         int pid, width, height;  double framerate;
1471         if( vdevice->get_video_info(track, pid, framerate, width, height, 0) ) return 1;
1472         if( !framerate ) return 1;
1473         return skim_thread->skim(pid,framenum,framerate, tdat,mw,mh,width,height);
1474 }
1475
1476 void Record::start_skimming()
1477 {
1478         if( commercial_check && vdevice && !skimming_active ) {
1479                 skimming_active = 1;
1480                 skim_thread->start(mwindow->commercials);
1481                 vdevice->set_skimming(0, 0, skimming, this);
1482         }
1483 }
1484
1485 void Record::stop_skimming()
1486 {
1487         if( skimming_active && vdevice ) {
1488                 skimming_active = 0;
1489                 vdevice->set_skimming(0, 0, 0, 0);
1490                 skim_thread->stop();
1491         }
1492 }
1493
1494 void Record::update_skimming(int v)
1495 {
1496         if( (commercial_check=v) != 0 )
1497                 start_skimming();
1498         else
1499                 stop_skimming();
1500 }
1501
1502 RecordRemoteHandler::RecordRemoteHandler(RemoteControl *remote_control)
1503  : RemoteHandler(remote_control->gui, GREEN)
1504 {
1505 }
1506
1507 RecordRemoteHandler::~RecordRemoteHandler()
1508 {
1509 }
1510
1511 void Record::
1512 display_video_text(int x, int y, const char *text, int font,
1513         int bg_color, int color, int alpha, double secs, double scale)
1514 {
1515 // gotta have a window for resources
1516         record_monitor->window->
1517                 display_video_text(x, y, text, font,
1518                         bg_color, color, alpha, secs, scale);
1519 }
1520
1521 void Record::
1522 display_cut_icon(int x, int y)
1523 {
1524         VFrame *cut_icon = *mwindow->theme->get_image_set("commercial");
1525         double scale = 3;
1526         x += cut_icon->get_w()*scale;  y += cut_icon->get_h()*scale;
1527         display_vframe(cut_icon, x, y, 200, 1.0, scale);
1528 }
1529
1530 DeviceDVBInput *Record::
1531 dvb_device()
1532
1533         DeviceDVBInput *dvb_dev = !vdevice ? 0 :
1534                 (DeviceDVBInput *)vdevice->mpeg_device();
1535         if( !dvb_dev ) dvb_dev = !adevice ? 0 :
1536                 (DeviceDVBInput *)adevice->mpeg_device();
1537         return dvb_dev;
1538 }
1539
1540 #if 0
1541
1542 void Record::
1543 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1544 {
1545         if( !channel ) return;
1546         if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1547         DeviceDVBInput *dvb_input = dvb_device();
1548         if( !dvb_input ) return 1;
1549         zmpeg3_t *fd = dvb_input->get_src();
1550         if( !fd ) return;
1551         scale *= fd->video_height(channel->video_stream) / 1080.;
1552         int ww = in->get_w() * scale, hh = in->get_h() * scale;
1553         VFrame out(ww, hh, BC_YUV444P);
1554         BC_WindowBase::get_cmodels()->transfer(out.get_rows(), in->get_rows(),
1555                 out.get_y(), out.get_u(), out.get_v(),
1556                 in->get_y(), in->get_u(), in->get_v(),
1557                 0, 0, in->get_w(), in->get_h(),
1558                 0, 0, out.get_w(), out.get_h(),
1559                 in->get_color_model(), out.get_color_model(), 0,
1560                 in->get_bytes_per_line(), ww);
1561         int sz = ww * hh;  uint8_t *yuv = out.get_data(), aimg[sz];
1562         uint8_t *yp = yuv, *up = yuv+sz, *vp = yuv+2*sz, *ap = 0;
1563         if( alpha > 0 ) memset(ap=aimg, alpha, sz);
1564         else if( alpha < 0 ) ap = yp;
1565         fd->display_subtitle(channel->video_stream, 1, 1,
1566                                 yp,up,vp,ap, x,y,ww,hh, 0, secs*1000);
1567         dvb_input->put_src();
1568 }
1569
1570 void Record::
1571 undisplay_vframe()
1572 {
1573         if( !channel ) return;
1574         if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1575         DeviceDVBInput *dvb_input = dvb_device();
1576         if( !dvb_input ) return 1;
1577         zmpeg3_t *fd = dvb_input->get_src();
1578         if( !fd ) return;
1579         fd->delete_subtitle(channel->video_stream, 1, 1);
1580         dvb_input->put_src();
1581 }
1582
1583 #else
1584
1585 void Record::
1586 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1587 {
1588         record_monitor->display_vframe(in, x, y, alpha, secs, scale);
1589 }
1590
1591 void Record::
1592 undisplay_vframe()
1593 {
1594         record_monitor->undisplay_vframe();
1595 }
1596
1597 #endif
1598
1599 int Record::
1600 display_channel_info()
1601 {
1602         if( !channel ) return 1;
1603         if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1604         DeviceDVBInput *dvb_input = dvb_device();
1605         if( !dvb_input ) return 1;
1606         int elem = channel->element;
1607         time_t tt;  time(&tt);
1608         struct tm ttm;  localtime_r(&tt,&ttm);
1609         int result = 1;
1610         char text[BCTEXTLEN];
1611         zmpeg3_t *fd = dvb_input->get_src();
1612         if( !fd ) return 1;
1613         for( int ord=0, i=0; ord<0x80; ) {
1614                 char *cp = text;
1615                 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1616                 if( len < 0 ) { ++ord;  i = 0;  continue; }
1617                 struct tm stm = ttm, etm = ttm;
1618                 char wday[4], *bp = cp;  cp += len;
1619                 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1620                         &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1621                         &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1622                 while( bp<cp && *bp++!='\n' );
1623                 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1624                         &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1625                 stm.tm_year -= 1900;  stm.tm_mon -= 1;
1626                 etm.tm_year = stm.tm_year;
1627                 etm.tm_mon = stm.tm_mon;
1628                 etm.tm_mday = stm.tm_mday;
1629                 time_t st = mktime(&stm), et = mktime(&etm);
1630                 if( et < st ) et += 24*3600;
1631                 if( tt < st || tt >= et ) continue;
1632                 int major=0, minor=0;
1633                 fd->dvb.get_channel(elem, major, minor);
1634                 char chan[64];  sprintf(chan, "%3d.%1d", major, minor);
1635                 for( i=0; i<5 && chan[i]!=0; ++i ) *bp++ = chan[i];
1636                 while( bp<cp && *bp++!='\n' );
1637                 int n = 1;
1638                 for( char *lp=bp; bp<cp; ++bp ) {
1639                         if( *bp == '\n' || ((bp-lp)>=60 && *bp==' ') ) {
1640                                 if( ++n >= 10 ) break;
1641                                 *(lp=bp) = '\n';
1642                         }
1643                 }
1644                 *bp = 0;
1645                 while( bp > text && *--bp == '\n' ) *bp = 0;
1646                 result = 0;
1647                 break;
1648         }
1649         dvb_input->put_src();
1650         if( !result )
1651                 display_video_text(20, 20, text,
1652                                 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1653         return result;
1654 }
1655
1656 int Record::
1657 display_channel_schedule()
1658 {
1659         if( !channel ) return 1;
1660         if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1661         DeviceDVBInput *dvb_input = dvb_device();
1662         if( !dvb_input ) return 1;
1663         int elem = channel->element;
1664         time_t tt;  time(&tt);
1665         struct tm ttm;  localtime_r(&tt,&ttm);
1666         char text[BCTEXTLEN];
1667         zmpeg3_t *fd = dvb_input->get_src();
1668         if( !fd ) return 1;
1669         RecordSchedule channel_schedule;
1670         for( int ord=0, i=0; ord<0x80; ) {
1671                 char *cp = text;
1672                 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1673                 if( len < 0 ) { ++ord;  i = 0;  continue; }
1674                 struct tm stm = ttm, etm = ttm;
1675                 char wday[4], *bp = cp;  cp += len;
1676                 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1677                         &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1678                         &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1679                 while( bp<cp && *bp++!='\n' );
1680                 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1681                         &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1682                 stm.tm_year -= 1900;  stm.tm_mon -= 1;
1683                 etm.tm_year = stm.tm_year;
1684                 etm.tm_mon = stm.tm_mon;
1685                 etm.tm_mday = stm.tm_mday;
1686                 time_t st = mktime(&stm), et = mktime(&etm);
1687                 if( et < st ) et += 24*3600;
1688                 if( tt >= et ) continue;
1689                 if( bp > text )*--bp = 0;
1690                 channel_schedule.append(new RecordScheduleItem(st, text));
1691         }
1692         dvb_input->put_src();
1693
1694         channel_schedule.sort_times();
1695         char *cp = text, *ep = cp+sizeof(text)-1;
1696         for( int i=0, n=0; i<channel_schedule.size(); ++i ) {
1697                 RecordScheduleItem *item = channel_schedule.get(i);
1698                 for( char *bp=item->title; cp<ep && *bp!=0; ++bp ) *cp++ = *bp;
1699                 if( cp < ep ) *cp++ = '\n';
1700                 if( ++n >= 12 ) break;
1701         }
1702         *cp = 0;
1703         while( cp > text && *--cp == '\n' ) *cp = 0;
1704
1705         display_video_text(20, 20, text,
1706                                 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1707         return 0;
1708 }
1709
1710 void Record::clear_keybfr()
1711 {
1712         keybfr[0] = 0;
1713         undisplay_vframe();
1714 }
1715
1716 void Record::add_key(int ch)
1717 {
1718         int n = 0;
1719         while( n<(int)sizeof(keybfr)-2 && keybfr[n] ) ++n;
1720         keybfr[n++] = ch;  keybfr[n] = 0;
1721         display_video_text(20, 20, keybfr,
1722                                 BIGFONT, WHITE, BLACK, 0, 3., 2.);
1723 }
1724
1725 int RecordRemoteHandler::remote_process_key(RemoteControl *remote_control, int key)
1726 {
1727         Record *record = remote_control->mwindow_gui->record;
1728         return record->remote_process_key(remote_control, key);
1729 }
1730
1731 int Record::remote_process_key(RemoteControl *remote_control, int key)
1732 {
1733         int ch = key;
1734
1735         switch( key ) {
1736         case KPENTER:
1737                 if( last_key == KPENTER ) {
1738                         set_channel_name(keybfr);
1739                         clear_keybfr();
1740                         break;
1741                 }
1742                 ch = '.';  // fall through
1743         case '0': if( last_key == '0' && ch == '0' ) {
1744                 clear_keybfr();
1745                 break;
1746         }
1747         case '1': case '2': case '3': case '4':
1748         case '5': case '6': case '7': case '8': case '9':
1749                 add_key(ch);
1750                 break;
1751         //case UP: case DOWN: case LEFT: case RIGHT:
1752         //case KPPLAY: case KPBACK: case KPFORW:
1753         case KPRECD:  case 'c': // start capture, mark endpoint
1754                 if( !deletions ) {
1755                         start_commercial_capture();
1756                         if( adevice )
1757                                 set_play_gain(0.075);
1758                 }
1759                 else {
1760                         mark_commercial_capture(DEL_MARK);
1761                         blink_status->update();
1762                 }
1763                 display_cut_icon(10,20);
1764                 break;
1765         case KPSTOP:  case 'd': // end capture, start cutting
1766                 remote_control->set_color(YELLOW);
1767                 stop_commercial_capture(1);
1768                 break;
1769         case KPAUSE:  case 'x': // ignore current commercial
1770                 mark_commercial_capture(DEL_SKIP);
1771                 break;
1772         case KPBACK:  case 'a': // toggle mute audio
1773                 if( !monitor_audio ) { set_mute_gain(1);  set_play_gain(1); }
1774                 set_audio_monitoring(monitor_audio ? 0 : 1);
1775                 break;
1776         case 'm': // toggle metering audio
1777                 set_audio_metering(metering_audio ? 0 : 1);
1778                 break;
1779         case KPPLAY:  case 's': // ignore previous endpoint
1780                 mark_commercial_capture(DEL_OOPS);
1781                 break;
1782         case KPFWRD:  case KPSLASH:
1783                 display_channel_info();
1784                 break;
1785         case KPMAXW:  case KPSTAR:
1786                 display_channel_schedule();
1787                 break;
1788         case KPCHUP:  case KPPLUS:
1789                 channel_up();
1790                 break;
1791         case KPCHDN:  case KPMINUS:
1792                 channel_down();
1793                 break;
1794         case 'f': {
1795                 Canvas *canvas = record_monitor->window->canvas;
1796                 if( !canvas->get_fullscreen() )
1797                         canvas->start_fullscreen();
1798                 else
1799                         canvas->stop_fullscreen();
1800                 break; }
1801         default:
1802                 return -1;
1803         }
1804
1805         last_key = key;
1806         return 1;
1807 }
1808
1809
1810 int Record::start_commercial_capture()
1811 {
1812         if( deletions != 0 ) return 1;
1813         Channel *channel = get_current_channel();
1814         if( !channel ) return 1;
1815         int track = channel->video_stream;
1816         int pid = vdevice->get_video_pid(track);
1817         if( pid < 0 ) return 1;
1818         time_t st;  time(&st);
1819         struct tm stm;  localtime_r(&st, &stm);
1820         char file_path[BCTEXTLEN];
1821         sprintf(file_path,"/tmp/del%04d%02d%02d-%02d%02d%02d.ts",
1822                 stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
1823                 stm.tm_hour, stm.tm_min, stm.tm_sec);
1824         commercial_fd = open(file_path,O_RDWR+O_CREAT,0666);
1825         if( commercial_fd < 0 ) return 1;
1826         if( vdevice->start_record(commercial_fd, 0x800000) ) {
1827                 close(commercial_fd);
1828                 commercial_fd = -1;
1829                 return 1;
1830         }
1831         commercial_start_time = st;
1832         printf("del to %s\n", file_path);
1833         deletions = new Deletions(pid, file_path);
1834         mark_commercial_capture(DEL_START);
1835         blink_status->start();
1836         return 0;
1837 }
1838
1839 int Record::mark_commercial_capture(int action)
1840 {
1841         if( deletions == 0 ) return 1;
1842         double time = vdevice->get_timestamp();
1843         printf("dele %f\n", time);
1844         deletions->append(new Dele(time, action));
1845         return 0;
1846 }
1847
1848 void Record::remote_fill_color(int color)
1849 {
1850         mwindow->gui->remote_control->fill_color(color);
1851 }
1852
1853 void Record::set_status_color(int color)
1854 {
1855         status_color = color;
1856         remote_fill_color(status_color);
1857 }
1858
1859 void Record::set_mute_gain(double gain)
1860 {
1861         gain = (mute_gain = gain) * play_gain;
1862         if( adevice ) adevice->set_play_gain(gain);
1863 }
1864
1865 void Record::set_play_gain(double gain)
1866 {
1867         gain = mute_gain * (play_gain = gain);
1868         if( adevice ) adevice->set_play_gain(gain);
1869 }
1870
1871 int Record::stop_commercial_capture(int run_job)
1872 {
1873         if( deletions == 0 ) return 1;
1874         if( run_job ) blink_status->stop();
1875         set_play_gain(1);
1876
1877         vdevice->stop_record();
1878         commercial_start_time = -1;
1879         if( commercial_fd >= 0 ) {
1880                 close(commercial_fd);
1881                 commercial_fd = -1;
1882         }
1883         int result = -1;
1884         if( run_job ) {
1885                 char del_filename[BCTEXTLEN];
1886                 strcpy(del_filename, deletions->file_path());
1887                 strcpy(strrchr(del_filename, '.'),".del");
1888                 if( !deletions->write_dels(del_filename) ) {
1889                         int pid = spawn("cutads %s",del_filename);
1890                         if( pid > 0 ) {
1891                                 cut_pids.append(pid);
1892                                 cutads_status->start_waiting();
1893                                 result = 0;
1894                         }
1895                 }
1896         }
1897         else {
1898                 remove_file(deletions->filepath);
1899         }
1900         delete deletions;  deletions = 0;
1901         return result;
1902 }
1903
1904 int Record::
1905 spawn(const char *fmt, ...)
1906 {
1907         char exe_path[BCTEXTLEN], cmd[BCTEXTLEN];
1908         get_exe_path(exe_path);
1909         va_list ap;  va_start(ap, fmt);
1910         int n = snprintf(cmd, sizeof(cmd), "exec %s/", exe_path);
1911         vsnprintf(cmd+n, sizeof(cmd)-n, fmt, ap);  va_end(ap);
1912         pid_t pid = vfork();
1913         if( pid < 0 ) return -1;
1914         if( pid > 0 ) return pid;
1915         char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
1916         execvp(argv[0], &argv[0]);
1917         return -1;
1918 }
1919
1920 int Record::
1921 commercial_jobs()
1922 {
1923         for( int i=0; i<cut_pids.size(); ) {
1924                 int status, pid = cut_pids.get(i);
1925                 if( waitpid(pid, &status, WNOHANG) ) {
1926                         cut_pids.remove(pid);
1927                         continue;
1928                 }
1929                 ++i;
1930         }
1931         return cut_pids.size();
1932 }
1933
1934
1935 RecordCutAdsStatus::
1936 RecordCutAdsStatus(Record *record)
1937  : Thread(1, 0, 0)
1938 {
1939         this->record = record;
1940         wait_lock = new Condition(0,"RecordCutAdsStatus::wait_lock",0);
1941         done = 0;
1942         start();
1943 }
1944
1945 RecordCutAdsStatus::
1946 ~RecordCutAdsStatus()
1947 {
1948         if( running() ) {
1949                 done = 1;
1950                 wait_lock->unlock();
1951                 cancel();
1952                 join();
1953         }
1954         delete wait_lock;
1955 }
1956
1957 void RecordCutAdsStatus::
1958 start_waiting()
1959 {
1960         wait_lock->unlock();
1961 }
1962
1963 void RecordCutAdsStatus::
1964 run()
1965 {
1966         int status, pgrp = getpgrp();
1967         while(!done) {
1968                 wait_lock->lock("RecordCutAdsStatus::run");
1969                 if( done ) break;
1970                 if( !record->commercial_jobs() ) continue;
1971                 record->set_status_color(YELLOW);
1972                 while( !done ) {
1973                         enable_cancel();
1974                         waitpid(-pgrp, &status, 0);
1975                         disable_cancel();
1976                         if( !record->commercial_jobs() ) break;
1977                 }
1978                 record->set_status_color(GREEN);
1979         }
1980 }
1981
1982 void RecordBlinkStatus::
1983 remote_color(int color)
1984 {
1985         record->remote_fill_color(color);
1986 }
1987
1988 void RecordBlinkStatus::
1989 update()
1990 {
1991         timer.update();
1992 }
1993
1994 void RecordBlinkStatus::
1995 start()
1996 {
1997         done = 0;
1998         update();
1999         Thread::start();
2000 }
2001
2002 void RecordBlinkStatus::
2003 stop()
2004 {
2005         done = 1;
2006         if( running() ) {
2007                 cancel();
2008                 join();
2009         }
2010 }
2011
2012 RecordBlinkStatus::
2013 RecordBlinkStatus(Record *record)
2014  : Thread(1, 0, 0)
2015 {
2016         this->record = record;
2017 }
2018
2019 RecordBlinkStatus::
2020 ~RecordBlinkStatus()
2021 {
2022         stop();
2023 }
2024
2025 void RecordBlinkStatus::
2026 run()
2027 {
2028         int color = YELLOW;
2029         while( !done ) {
2030                 remote_color(color);
2031                 enable_cancel();
2032                 usleep(500000);
2033                 disable_cancel();
2034                 color ^= YELLOW ^ BLUE;
2035                 if( timer.get_difference() > 10*60*1000 ) { // 10 minites
2036                         record->stop_commercial_capture(0);
2037                         done = 1;
2038                 }
2039         }
2040         remote_color(record->status_color);
2041 }
2042