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