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