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