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