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