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