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