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