3 * Copyright (C) 2009-2013 Adam Williams <broadcast at earthling dot net>
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.
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.
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
23 #include "audiodevice.h"
25 #include "awindowgui.h"
29 #include "channeldb.h"
30 #include "channelpicker.h"
32 #include "commercials.h"
33 #include "condition.h"
35 #include "devicedvbinput.h"
36 #include "drivesync.h"
38 #include "edlsession.h"
42 #include "filesystem.h"
43 #include "filethread.h"
44 #include "formatcheck.h"
45 #include "indexfile.h"
48 #include "localsession.h"
54 #include "mwindowgui.h"
57 #include "playbackengine.h"
58 #include "preferences.h"
60 #include "recordaudio.h"
61 #include "recordconfig.h"
62 #include "recordgui.h"
63 #include "recordlabel.h"
64 #include "recordmonitor.h"
65 #include "recordprefs.inc"
66 #include "recordthread.h"
67 #include "recordvideo.h"
68 #include "removefile.h"
69 #include "mainsession.h"
70 #include "sighandler.h"
71 #include "testobject.h"
75 #include "videoconfig.h"
76 #include "videodevice.h"
79 #include <sys/types.h>
83 RecordMenuItem::RecordMenuItem(MWindow *mwindow)
84 : BC_MenuItem(_("Record..."), "r", 'r')
86 this->mwindow = mwindow;
87 record = new Record(mwindow, this);
90 RecordMenuItem::~RecordMenuItem()
95 int RecordMenuItem::handle_event()
102 Record::Record(MWindow *mwindow, RecordMenuItem *menu_item)
104 record_batches(mwindow)
106 this->mwindow = mwindow;
107 this->menu_item = menu_item;
108 mwindow->gui->record = this;
112 picture = new PictureConfig();
113 channeldb = new ChannelDB;
114 master_channel = new Channel;
115 record_channel = new RecordChannel(this);
120 pause_lock = new Mutex("Record::pause_lock");
121 init_lock = new Condition(0,"Record::init_lock");
127 session_sample_offset = 0;
128 device_sample_offset = 0;
133 drop_overrun_frames = 0;
134 fill_underrun_frames = 0;
136 commercial_check = skimming_active = 0;
137 commercial_start_time = -1;
145 current_frame = written_frames = total_frames = 0;
146 current_sample = written_samples = total_samples = 0;
147 audio_time = video_time = -1.;
148 play_gain = mute_gain = 1.;
150 input_threads_pausing = 0;
151 window_lock = new Mutex("Record::window_lock");
152 timer_lock = new Mutex("Record::timer_lock");
153 file_lock = new Mutex("Record::file_lock");
154 adevice_lock = new Mutex("Record::adevice_lock");
155 vdevice_lock = new Mutex("Record::vdevice_lock");
156 batch_lock = new Mutex("Record::batch_lock");
157 skim_thread = new SkimDbThread();
158 cutads_status = new RecordCutAdsStatus(this);
159 blink_status = new RecordBlinkStatus(this);
164 mwindow->gui->record = 0;
167 delete cutads_status;
173 delete record_channel;
174 delete master_channel;
187 int Record::load_defaults()
190 char string[BCTEXTLEN];
191 BC_Hash *defaults = mwindow->defaults;
192 EDLSession *session = SESSION;
193 default_asset->copy_from(session->recording_format, 0);
194 default_asset->channels = session->aconfig_in->channels;
195 default_asset->sample_rate = session->aconfig_in->in_samplerate;
196 default_asset->frame_rate = session->vconfig_in->in_framerate;
197 default_asset->width = session->vconfig_in->w;
198 default_asset->height = session->vconfig_in->h;
199 default_asset->layers = 1;
200 // Fix encoding parameters depending on driver.
201 // These are locked by a specific driver.
202 const char *vcodec = 0;
203 switch( session->vconfig_in->driver ) {
206 vcodec = CODEC_TAG_MJPEG;
209 case VIDEO4LINUX2MPEG:
211 case VIDEO4LINUX2JPEG:
212 vcodec = CODEC_TAG_MJPEG;
214 case CAPTURE_FIREWIRE:
215 case CAPTURE_IEC61883:
216 vcodec = CODEC_TAG_DVSD;
220 strcpy(default_asset->vcodec, vcodec);
222 record_batches.load_defaults(channeldb, this);
224 int cur_chan_no = defaults->get("RECORD_CURRENT_CHANNEL", 0);
225 current_channel = channeldb->get(cur_chan_no);
226 load_mode = defaults->get("RECORD_LOADMODE", LOADMODE_PASTE);
227 monitor_audio = defaults->get("RECORD_MONITOR_AUDIO", 1);
228 metering_audio = defaults->get("RECORD_METERING_AUDIO", 1);
229 monitor_video = defaults->get("RECORD_MONITOR_VIDEO", 1);
230 video_window_open = defaults->get("RECORD_MONITOR_OPEN", 1);
231 video_x = defaults->get("RECORD_VIDEO_X", 0);
232 video_y = defaults->get("RECORD_VIDEO_Y", 0);
233 video_zoom = defaults->get("RECORD_VIDEO_Z", (float)1);
234 picture->load_defaults();
235 reverse_interlace = defaults->get("REVERSE_INTERLACE", 0);
236 for( int i=0; i<MAXCHANNELS; ++i ) {
237 sprintf(string, "RECORD_DCOFFSET_%d", i);
238 dc_offset[i] = defaults->get(string, 0);
240 drop_overrun_frames = defaults->get("DROP_OVERRUN_FRAMES", 0);
241 fill_underrun_frames = defaults->get("FILL_UNDERRUN_FRAMES", 0);
242 commercial_check = defaults->get("COMMERCIAL_CHECK", 0);
246 int Record::save_defaults()
248 char string[BCTEXTLEN];
249 BC_Hash *defaults = mwindow->defaults;
250 set_editing_batch(0);
251 // Save default asset path but not the format because that's
252 // overridden by the driver.
253 // The format is saved in preferences.
254 if( record_batches.total() )
255 strcpy(default_asset->path, record_batches[0]->asset->path);
256 default_asset->save_defaults(defaults, "RECORD_", 0, 0, 0, 0, 0);
258 record_batches.save_defaults(channeldb);
260 int cur_chan_no = channeldb->number_of(current_channel);
261 defaults->update("RECORD_CURRENT_CHANNEL", cur_chan_no);
262 defaults->update("RECORD_LOADMODE", load_mode);
263 defaults->update("RECORD_MONITOR_AUDIO", monitor_audio);
264 defaults->update("RECORD_METERING_AUDIO", metering_audio);
265 defaults->update("RECORD_MONITOR_VIDEO", monitor_video);
266 defaults->update("RECORD_MONITOR_OPEN", video_window_open);
267 defaults->update("RECORD_VIDEO_X", video_x);
268 defaults->update("RECORD_VIDEO_Y", video_y);
269 defaults->update("RECORD_VIDEO_Z", video_zoom);
270 picture->save_defaults();
271 defaults->update("REVERSE_INTERLACE", reverse_interlace);
272 for( int i=0; i<MAXCHANNELS; ++i ) {
273 sprintf(string, "RECORD_DCOFFSET_%d", i);
274 defaults->update(string, dc_offset[i]);
276 defaults->update("DROP_OVERRUN_FRAMES", drop_overrun_frames);
277 defaults->update("FILL_UNDERRUN_FRAMES", fill_underrun_frames);
278 defaults->update("COMMERCIAL_CHECK", commercial_check);
284 void Record::configure_batches()
286 // printf("Record::configure_batches %d\n",__LINE__);
287 // default_assset->dump();
288 strcpy(record_batches[0]->asset->path, default_asset->path);
289 int total_batches = record_batches.total();
290 for( int i=0; i<total_batches; ++i ) {
291 Batch *batch = record_batches[i];
292 batch->asset->copy_format(default_asset);
300 // Default asset forms the first path in the batch capture
301 // and the file format for all operations.
302 default_asset = new Asset;
304 // Determine information about the device.
305 AudioInConfig *aconfig_in = SESSION->aconfig_in;
306 VideoInConfig *vconfig_in = SESSION->vconfig_in;
307 int driver = vconfig_in->driver;
308 VideoDevice::load_channeldb(channeldb, vconfig_in);
309 fixed_compression = VideoDevice::is_compressed(driver, 0, 1);
311 // Apply a major kludge
312 if( fixed_compression ) {
314 device.fix_asset(default_asset, driver);
316 default_asset->channels = aconfig_in->channels;
317 VideoDevice::save_channeldb(channeldb, vconfig_in);
319 mwindow->save_defaults();
321 set_current_batch(0);
322 set_editing_batch(0);
326 edl->create_objects();
327 edl->session->output_w = default_asset->width;
328 edl->session->output_h = default_asset->height;
329 edl->session->aspect_w = SESSION->aspect_w;
330 edl->session->aspect_h = SESSION->aspect_h;
332 window_lock->lock("Record::run 3");
333 record_gui = new RecordGUI(mwindow, this);
334 record_gui->create_objects();
336 record_monitor = new RecordMonitor(mwindow, this);
337 record_monitor->create_objects();
338 record_gui->update_batch_sources();
340 record_gui->show_window();
343 if( mwindow->gui->remote_control->deactivate() )
344 mwindow->gui->record_remote_handler->activate();
346 if( video_window_open ) {
347 record_monitor->window->show_window();
348 record_monitor->window->raise_window();
349 record_monitor->window->flush();
352 window_lock->unlock();
354 start_input_threads();
358 result = record_gui->run_window();
359 // record gui operates here until window is closed
361 if( record_gui->get_window_lock() ) {
362 record_gui->lock_window();
363 record_gui->unlock_window();
366 // Need to stop everything this time
368 stop_commercial_capture(0);
369 int video_stream = -1;
370 if( default_asset->format == FILE_MPEG ) {
371 Channel *channel = get_current_channel();
373 video_stream = channel->video_stream;
376 edl->Garbage::remove_user();
378 if( mwindow->gui->remote_control->deactivate() )
379 mwindow->gui->cwindow_remote_handler->activate();
381 // Save everything again
385 if( !result && load_mode != LOADMODE_NOTHING ) {
386 mwindow->gui->lock_window("Record::run");
387 ArrayList<EDL*> new_edls;
389 int total_batches = record_batches.total();
390 for( int i=0; i<total_batches; ++i ) {
391 Batch *batch = record_batches[i];
392 Asset *asset = batch->asset;
393 if( batch->recorded ) {
394 EDL *new_edl = new EDL;
395 mwindow->remove_asset_from_caches(asset);
396 new_edl->create_objects();
397 new_edl->copy_session(mwindow->edl);
398 mwindow->asset_to_edl(new_edl, asset, batch->labels);
399 new_edls.append(new_edl);
404 mwindow->undo->update_undo_before();
405 // For pasting, clear the active region
406 if(load_mode == LOADMODE_PASTE)
409 mwindow->paste_edls(&new_edls, load_mode, 0, -1,
410 SESSION->labels_follow_edits,
411 SESSION->plugins_follow_edits,
412 SESSION->autos_follow_edits,
414 for( int i=0; i<new_edls.total; ++i )
415 new_edls.get(i)->Garbage::remove_user();
416 new_edls.remove_all();
417 if( video_stream >= 0 ) {
418 mwindow->select_asset(video_stream, -1);
419 mwindow->fit_selection();
421 mwindow->save_backup();
422 mwindow->undo->update_undo_after(_("record"), LOAD_ALL);
423 mwindow->restart_brender();
424 mwindow->update_plugin_guis();
425 mwindow->gui->update(1, 2, 1, 1, 1, 1, 0);
426 mwindow->sync_parameters(CHANGE_ALL);
428 mwindow->gui->unlock_window();
430 AWindowGUI *agui = mwindow->awindow->gui;
431 agui->async_update_assets();
435 record_batches.clear();
436 default_asset->Garbage::remove_user();
442 window_lock->lock("Record::stop");
443 delete record_thread; record_thread = 0;
444 delete record_monitor; record_monitor = 0;
445 delete record_gui; record_gui = 0;
446 window_lock->unlock();
449 void Record::activate_batch(int number)
451 if( number != current_batch() ) {
453 set_current_batch(number);
454 record_gui->update_batches();
455 record_gui->update_position(current_display_position());
456 record_gui->update_batch_tools();
461 void Record::delete_index_file(Asset *asset)
463 IndexFile::delete_index(mwindow->preferences, asset, ".toc");
464 IndexFile::delete_index(mwindow->preferences, asset, ".idx");
465 IndexFile::delete_index(mwindow->preferences, asset, ".mkr");
468 void Record::delete_batch()
470 // Abort if one batch left
471 int edit_batch = editing_batch();
472 int total_batches = record_batches.total();
473 if( total_batches > 1 && edit_batch < total_batches ) {
474 int cur_batch = current_batch();
475 Batch *batch = record_batches[edit_batch];
476 record_batches.remove(batch); delete batch;
477 if( cur_batch == edit_batch ) stop_writing();
478 record_gui->update_batches();
479 record_gui->update_batch_tools();
483 void Record::change_editing_batch(int number)
485 set_editing_batch(number);
486 record_gui->update_batch_tools();
489 Batch* Record::new_batch()
491 Batch *batch = new Batch(mwindow, this);
492 //printf("Record::new_batch 1\n");
493 batch->create_objects();
494 record_batches.append(batch);
495 batch->asset->copy_format(default_asset);
497 //printf("Record::new_batch 1\n");
498 batch->create_default_path();
499 Batch *edit_batch = get_editing_batch();
501 batch->copy_from(edit_batch);
502 int total_batches = record_batches.total();
503 set_editing_batch(total_batches - 1);
504 //printf("Record::new_batch 1\n");
505 // Update GUI if created yet
507 record_gui->update_batch_tools();
508 //printf("Record::new_batch 2\n");
512 int Record::current_batch()
514 return record_batches.current_item;
517 int Record::set_current_batch(int i)
519 return record_batches.current_item = i;
522 int Record::editing_batch()
524 return record_batches.editing_item;
527 int Record::set_editing_batch(int i)
529 return record_batches.editing_item = i;
532 int Record::delete_output_file()
534 Batch *batch = get_current_batch();
536 if( !file && batch && !access(batch->asset->path, F_OK) ) {
537 batch->set_notice(_("Deleting"));
538 record_gui->update_batches();
539 Asset *asset = batch->asset;
540 remove_file(asset->path);
541 mwindow->remove_asset_from_caches(asset);
542 delete_index_file(asset);
543 batch->clear_notice();
544 record_gui->update_batches();
549 int Record::open_output_file()
553 Batch *batch = get_current_batch();
554 if( !file && batch ) {
555 delete_output_file();
556 Asset *asset = batch->asset;
557 asset->frame_rate = default_asset->frame_rate;
558 asset->sample_rate = default_asset->sample_rate;
559 asset->width = default_asset->width;
560 asset->height = default_asset->height;
562 if( default_asset->format == FILE_MPEG ) {
563 asset->layers = vdevice ? vdevice->total_video_streams() : 0;
564 asset->channels = adevice ? adevice->total_audio_channels() : 0;
568 result = file->open_file(mwindow->preferences, asset, 0, wr);
570 mwindow->sighandler->push_file(file);
572 file->set_processors(mwindow->preferences->real_processors);
573 record_gui->update_batches();
587 window_lock->lock("Record::start");
588 record_gui->lock_window("Record::start");
589 record_gui->raise_window();
590 record_gui->unlock_window();
591 window_lock->unlock();
600 void Record::start_over()
603 Batch *batch = get_current_batch();
604 if( batch ) batch->start_over();
605 record_gui->update_batches();
608 void Record::stop_operation()
611 stop_input_threads();
614 int Record::cron_active()
616 return !record_thread ? 0 : record_thread->cron_active;
619 void Record::close_output_file()
623 mwindow->sighandler->pull_file(file);
629 record_gui->update_batches();
632 void Record::toggle_label()
634 Batch *batch = get_current_batch();
635 if( batch ) batch->toggle_label(current_display_position());
636 record_gui->update_labels(current_display_position());
639 void Record::clear_labels()
641 Batch *batch = get_current_batch();
642 if( batch ) batch->clear_labels();
643 record_gui->update_labels(0);
646 int Record::get_fragment_samples()
648 const int min_samples = 1024, max_samples = 32768;
649 int samples, low_bit;
650 samples = default_asset->sample_rate / SESSION->record_speed;
651 if( samples < min_samples ) samples = min_samples;
652 else if( samples > max_samples ) samples = max_samples;
653 // loop until only one bit left standing
654 while( (low_bit=(samples & ~(samples-1))) != samples )
659 int Record::get_buffer_samples()
661 int fragment_samples = get_fragment_samples();
662 if( !fragment_samples ) return 0;
663 int fragments = (SESSION->record_write_length+fragment_samples-1) / fragment_samples;
664 if( fragments < 1 ) fragments = 1;
665 return fragments * fragment_samples;
668 Batch* Record::get_current_batch()
670 return record_batches.get_current_batch();
673 Batch* Record::get_editing_batch()
675 return record_batches.get_editing_batch();
678 int Record::get_next_batch(int incr)
680 int i = current_batch();
683 int total_batches = record_batches.total();
684 while( i < total_batches ) {
685 if( record_batches[i]->enabled ) return i;
692 const char* Record::current_mode()
694 Batch *batch = get_current_batch();
695 return batch ? Batch::mode_to_text(batch->record_mode) : "";
698 double Record::current_display_position()
700 //printf("Record::current_display_position "
701 // _LD " " _LD "\n", total_samples, total_frames)
703 Asset *asset = default_asset;
705 if( asset->video_data && record_video )
706 result = (double) written_frames / asset->frame_rate;
707 else if( asset->audio_data && record_audio )
708 result = (double) written_samples / asset->sample_rate;
711 if( asset->video_data && record_video )
712 result = (double) total_frames / asset->frame_rate;
713 else if( asset->audio_data && record_audio )
714 result = (double) total_samples / asset->sample_rate;
716 result = (double) total_time.get_difference() / 1000.;
721 const char* Record::current_source()
723 Batch *batch = get_current_batch();
724 return batch ? batch->get_source_text() : _("Unknown");
727 Asset* Record::current_asset()
729 Batch *batch = get_current_batch();
730 return batch ? batch->asset : 0;
733 Channel *Record::get_current_channel()
735 return current_channel;
738 Channel *Record::get_editing_channel()
740 Batch *batch = get_editing_batch();
741 return batch ? batch->channel : 0;
744 ArrayList<Channel*>* Record::get_video_inputs()
746 return default_asset->video_data && vdevice ? vdevice->get_inputs() : 0;
750 int64_t Record::timer_position()
752 timer_lock->lock("RecordAudio::timer_positioin");
753 int samplerate = default_asset->sample_rate;
754 int64_t result = timer.get_scaled_difference(samplerate);
755 result += session_sample_offset;
756 timer_lock->unlock();
760 void Record::reset_position(int64_t position)
762 timer_lock->lock("RecordAudio::reset_position");
763 session_sample_offset = position;
764 device_sample_offset = adevice ? adevice->current_position() : 0;
766 timer_lock->unlock();
769 void Record::update_position()
771 int64_t position = sync_position();
772 reset_position(position);
773 current_frame = current_sample = 0;
774 audio_time = video_time = -1.;
777 int64_t Record::adevice_position()
779 timer_lock->lock("RecordAudio::adevice_position");
780 int64_t result = adevice->current_position();
781 result += session_sample_offset - device_sample_offset;
782 timer_lock->unlock();
786 int64_t Record::sync_position()
788 int64_t sync_position = -1;
789 double sync_time = -1.;
790 double next_audio_time = -1.;
791 double next_video_time = -1.;
793 if( current_frame == 0 && current_sample == 0 ) {
794 audio_time = video_time = -1.;
797 switch( SESSION->record_positioning ) {
798 case RECORD_POS_TIMESTAMPS:
799 if( default_asset->video_data && record_video )
800 next_video_time = vdevice->get_timestamp();
801 if( default_asset->audio_data && record_audio ) {
803 !adevice->is_monitoring() || writing_file > 0 ?
804 adevice->get_itimestamp() :
805 adevice->get_otimestamp();
807 if( next_audio_time >= 0. )
808 sync_time = next_audio_time;
809 else if( next_video_time > 0. )
810 sync_time = next_video_time;
811 if( sync_time >= 0. ) {
812 sync_position = sync_time * default_asset->sample_rate;
814 if( sync_position >= 0 ) break;
815 case RECORD_POS_DEVICE:
816 if( default_asset->audio_data && record_audio )
817 sync_position = adevice_position();
818 if( sync_position > 0 ) break;
819 case RECORD_POS_SOFTWARE:
820 sync_position = timer_position();
821 if( sync_position > 0 ) break;
822 case RECORD_POS_SAMPLE:
824 sync_position = current_sample;
828 if( next_video_time < 0. )
829 next_video_time = current_frame / default_asset->frame_rate;
830 if( next_video_time > video_time )
831 video_time = next_video_time;
832 if( next_audio_time < 0. )
833 next_audio_time = (double)sync_position / default_asset->sample_rate;
834 if( next_audio_time > audio_time )
835 audio_time = next_audio_time;
837 return sync_position;
841 void Record::adevice_drain()
843 if( adevice && record_audio ) {
844 adevice->stop_audio(0);
845 adevice->start_recording();
850 #define dbmsg if( debug ) printf
851 void Record::resync()
853 dropped = behind = 0;
854 int64_t audio_position = sync_position();
855 double audiotime = (double) audio_position / default_asset->sample_rate;
856 double diff = video_time - audiotime;
858 dbmsg("resync video %f audio %f/%f diff %f",
859 video_time, audiotime, audio_time, diff);
860 if( fabs(diff) > 5. ) {
861 dbmsg(" drain audio");
862 // jam job dvb file tesing, comment next line
863 record_channel->drain_audio();
865 else if( diff > 0. ) {
866 int64_t delay = (int64_t)(1000.0 * diff);
867 dbmsg(" delay " _LDv(8), delay);
869 video_time = audio_time = -1.;
876 behind = (int)(-diff * default_asset->frame_rate);
877 dbmsg(" behind %d", behind);
878 if( behind > 1 && fill_underrun_frames ) {
879 dropped = behind > 3 ? 3 : behind-1;
880 dbmsg(" dropped %d", dropped);
884 int frames = dropped + 1;
885 current_frame += frames;
886 total_frames += frames;
887 record_gui->update_video(dropped, behind);
888 if( dropped > 0 && drop_overrun_frames )
889 if( vdevice ) vdevice->drop_frames(dropped);
893 void Record::close_audio_input()
895 adevice_lock->lock();
897 adevice->close_all();
901 adevice_lock->unlock();
904 void Record::close_video_input()
906 vdevice_lock->lock();
908 vdevice->close_all();
912 vdevice_lock->unlock();
915 void Record::close_input_devices()
921 void Record::stop_audio_thread()
924 record_audio->stop_recording();
932 void Record::stop_video_thread()
935 record_video->stop_recording();
944 void Record::stop_input_threads()
946 pause_lock->lock("Record::stop_input_threads");
951 pause_lock->unlock();
954 void Record::stop_playback()
957 record_monitor->stop_playback();
960 void Record::open_audio_input()
963 adevice_lock->lock();
965 if( default_asset->audio_data )
966 adevice = new AudioDevice(mwindow);
969 int sw_pos = SESSION->record_positioning == RECORD_POS_SOFTWARE;
970 adevice->set_software_positioning(sw_pos);
971 adevice->open_input(SESSION->aconfig_in, SESSION->vconfig_in,
972 default_asset->sample_rate, get_fragment_samples(),
973 default_asset->channels, SESSION->real_time_record);
974 adevice->start_recording();
975 adevice->open_monitor(SESSION->playback_config->aconfig,monitor_audio);
976 adevice->set_vdevice(vdevice);
977 if( vdevice ) vdevice->set_adevice(adevice);
979 adevice_lock->unlock();
982 void Record::open_video_input()
985 vdevice_lock->lock();
986 if( default_asset->video_data )
987 vdevice = new VideoDevice(mwindow);
990 vdevice->set_quality(default_asset->jpeg_quality);
991 vdevice->open_input(SESSION->vconfig_in, video_x, video_y,
992 video_zoom, default_asset->frame_rate);
993 // Get configuration parameters from device probe
994 color_model = vdevice->get_best_colormodel(default_asset);
995 master_channel->copy_usage(vdevice->channel);
996 picture->copy_usage(vdevice->picture);
997 vdevice->set_field_order(reverse_interlace);
998 vdevice->set_adevice(adevice);
999 if( adevice ) adevice->set_vdevice(vdevice);
1000 set_dev_channel(get_current_channel());
1002 vdevice_lock->unlock();
1005 void Record::start_audio_thread()
1008 if( !record_audio ) {
1009 total_samples = current_sample = 0; audio_time = -1.;
1010 record_audio = new RecordAudio(mwindow,this);
1011 record_audio->arm_recording();
1012 record_audio->start_recording();
1017 void Record::start_video_thread()
1020 if( !record_video ) {
1021 total_frames = current_frame = 0; video_time = -1.;
1022 record_video = new RecordVideo(mwindow,this);
1023 record_video->arm_recording();
1024 record_video->start_recording();
1029 void Record::start_input_threads()
1032 input_threads_pausing = 0;
1033 if( default_asset->audio_data )
1034 start_audio_thread();
1035 if( default_asset->video_data )
1036 start_video_thread();
1040 void Record::pause_input_threads()
1042 pause_lock->lock("Record::pause_input_threads");
1043 input_threads_pausing = 1;
1045 adevice_lock->lock();
1046 vdevice_lock->lock();
1048 record_audio->pause_recording();
1050 record_video->pause_recording();
1053 void Record::resume_input_threads()
1056 record_audio->resume_recording();
1058 record_video->resume_recording();
1059 vdevice_lock->unlock();
1060 adevice_lock->unlock();
1061 input_threads_pausing = 0;
1063 pause_lock->unlock();
1067 int Record::start_toc()
1069 if( !mwindow->edl->session->record_realtime_toc ) return 0;
1070 Batch *batch = get_current_batch();
1071 Asset *asset = batch->asset;
1072 char source_filename[BCTEXTLEN], toc_path[BCTEXTLEN];
1073 IndexFile::get_index_filename(source_filename,
1074 mwindow->preferences->index_directory,
1075 toc_path, asset->path,".toc");
1076 if( default_asset->video_data )
1077 return vdevice->start_toc(asset->path, toc_path);
1078 if( default_asset->audio_data )
1079 return adevice->start_toc(asset->path, toc_path);
1083 int Record::start_record(int fd)
1086 if( default_asset->video_data )
1087 return vdevice->start_record(fd);
1088 if( default_asset->audio_data )
1089 return adevice->start_record(fd);
1093 void Record::start_writing_file()
1095 if( !writing_file ) {
1097 written_samples = 0;
1098 do_video = File::supports_video(default_asset->format);
1099 do_audio = File::supports_audio(default_asset->format);
1100 if( single_frame ) do_audio = 0;
1101 if( !do_video && single_frame )
1103 else if( !open_output_file() )
1104 writing_file = default_asset->format == FILE_MPEG ? -1 : 1;
1105 if( do_audio && record_audio && writing_file > 0 ) {
1106 int buffer_samples = get_buffer_samples();
1107 record_audio->set_write_buffer_samples(buffer_samples);
1108 file->start_audio_thread(buffer_samples, FILE_RING_BUFFERS);
1110 if( do_video && record_video && writing_file > 0 ) {
1111 int disk_frames = SESSION->video_write_length;
1112 int cmodel = vdevice->get_best_colormodel(default_asset);
1113 int cpress = vdevice->is_compressed(1, 0);
1114 file->start_video_thread(disk_frames, cmodel, FILE_RING_BUFFERS, cpress);
1116 if( writing_file < 0 ) {
1117 int fd = file->record_fd();
1121 if( writing_file ) {
1122 record_gui->start_flash_batch();
1123 if( SESSION->record_sync_drives ) {
1124 drivesync = new DriveSync();
1132 int Record::stop_record()
1134 if( default_asset->video_data )
1135 return vdevice->stop_record();
1136 if( default_asset->audio_data )
1137 return adevice->stop_record();
1141 void Record::flush_buffer()
1144 record_audio->flush_buffer();
1146 record_video->flush_buffer();
1149 void Record::stop_writing_file()
1151 record_gui->stop_flash_batch();
1152 if( !writing_file ) return;
1153 if( writing_file > 0 )
1155 if( writing_file < 0 )
1157 close_output_file();
1159 Asset *asset = current_asset();
1160 asset->audio_length = written_samples;
1161 asset->video_length = written_frames;
1162 record_gui->flash_batch();
1164 drivesync->done = 1;
1170 void Record::stop_writing()
1172 if( writing_file ) {
1173 pause_input_threads();
1174 stop_writing_file();
1175 resume_input_threads();
1180 void Record::start_cron_thread()
1182 if( cron_active() < 0 ) {
1183 delete record_thread;
1186 if( !record_thread ) {
1187 record_thread = new RecordThread(mwindow,this);
1188 record_thread->start();
1189 record_gui->disable_batch_buttons();
1190 record_gui->update_cron_status(_("Running"));
1194 void Record::stop_cron_thread(const char *msg)
1196 if( record_thread ) {
1197 delete record_thread;
1199 record_gui->enable_batch_buttons();
1200 record_gui->update_cron_status(msg);
1204 void Record::set_power_off(int value)
1207 record_gui->power_off->update(value);
1210 int Record::set_video_picture()
1212 if( default_asset->video_data && vdevice )
1213 vdevice->set_picture(picture);
1217 void Record::set_translation(int x, int y)
1221 if(default_asset->video_data && vdevice)
1222 vdevice->set_translation(video_x, video_y);
1225 int Record::set_channel(Channel *channel)
1227 if( !channel ) return 1;
1228 printf("set_channel %s\n",channel->title);
1229 if( record_channel->set(channel) ) return 1;
1230 RecordMonitorGUI *window = record_monitor->window;
1231 window->lock_window("Record::set_channel");
1232 window->channel_picker->channel_text->update(channel->title);
1233 window->unlock_window();
1237 int Record::set_channel_no(int chan_no)
1239 if( chan_no < 0 || chan_no >= channeldb->size() ) return 1;
1240 Channel *channel = channeldb->get(chan_no);
1241 return set_channel(channel);
1244 int Record::channel_down()
1246 Channel *channel = get_current_channel();
1247 if( !channel || !channeldb->size() ) return 1;
1248 int n = channeldb->number_of(channel);
1249 if( n < 0 ) return 1;
1250 if( --n < 0 ) n = channeldb->size() - 1;
1251 return set_channel_no(n);
1254 int Record::channel_up()
1256 Channel *channel = get_current_channel();
1257 if( !channel || !channeldb->size() ) return 1;
1258 int n = channeldb->number_of(channel);
1259 if( n < 0 ) return 1;
1260 if( ++n >= channeldb->size() ) n = 0;
1261 return set_channel_no(n);
1264 int Record::set_channel_name(const char *name)
1266 Channel *channel = 0;
1267 int ch = 0, nch = channeldb->size();
1269 channel = channeldb->get(ch);
1270 if( channel && !channel->cstrcmp(name) ) break;
1273 if( ch >= nch || !channel ) return 1;
1274 return set_channel(channel);
1277 void Record::set_batch_channel_no(int chan_no)
1279 Channel *channel = channeldb->get(chan_no);
1281 Batch *batch = get_editing_batch();
1282 if( batch ) batch->channel = channel;
1283 record_gui->batch_source->update(channel->title);
1287 void Record::set_dev_channel(Channel *channel)
1289 // should be tuner device, not vdevice
1290 if( channel && vdevice &&
1291 (!this->channel || *channel != *this->channel) ) {
1292 current_channel = channel;
1293 if( this->channel ) delete this->channel;
1294 this->channel = new Channel(channel);
1295 vdevice->set_channel(channel);
1296 int strk = !SESSION->decode_subtitles ? -1 : SESSION->subtitle_number;
1297 vdevice->set_captioning(strk);
1298 set_video_picture();
1299 printf("new channel %s, has_signal=%d\n",channel->title,vdevice->has_signal());
1302 total_time.update();
1306 /* widget holds xlock and set_channel pauses rendering, deadlock */
1307 /* use a background thread to update channel after widget sets it */
1308 RecordChannel::RecordChannel(Record *record)
1311 this->record = record;
1312 change_channel = new Condition(0,"RecordSetChannel::change_channel");
1313 channel_lock = new Condition(1,"Record::channel_lock",1);
1318 RecordChannel::~RecordChannel()
1321 change_channel->unlock();
1323 delete change_channel;
1324 delete channel_lock;
1327 int RecordChannel::set(Channel *channel)
1329 if( !channel || new_channel ) return 1;
1330 new_channel = channel;
1331 channel_lock->lock(); // block has_signal
1332 change_channel->unlock(); // resume channel changer thread
1336 void RecordChannel::drain_audio()
1338 if( !audio_drain ) {
1340 change_channel->unlock();
1344 void RecordChannel::run()
1348 change_channel->lock();
1350 if( !new_channel && !audio_drain ) continue;
1351 record->pause_input_threads();
1353 record->set_dev_channel(new_channel);
1354 record->record_gui->reset_video();
1355 record->record_gui->reset_audio();
1360 record->adevice_drain();
1362 record->update_position();
1363 record->resume_input_threads();
1366 channel_lock->unlock();
1371 int Record::has_signal()
1373 record_channel->channel_lock->lock("Record::has_signal");
1374 record_channel->channel_lock->unlock();
1375 vdevice_lock->lock();
1376 int result = vdevice ? vdevice->has_signal() : 0;
1377 vdevice_lock->unlock();
1381 int Record::create_channeldb(ArrayList<Channel*> *channeldb)
1383 return vdevice ? vdevice->create_channeldb(channeldb) : 1;
1387 void Record::set_audio_monitoring(int mode)
1390 monitor_audio = mode;
1392 record_audio->set_monitoring(mode);
1393 record_gui->lock_window("Record::set_audio_monitoring");
1394 if( record_gui->monitor_audio )
1395 record_gui->monitor_audio->update(mode);
1396 record_gui->unlock_window();
1399 void Record::set_audio_metering(int mode)
1401 metering_audio = mode;
1402 record_gui->lock_window("Record::set_audio_metering");
1403 if( record_gui->meter_audio )
1404 record_gui->meter_audio->update(mode);
1405 record_gui->unlock_window();
1406 RecordMonitorGUI *window = record_monitor->window;
1407 window->lock_window("Record::set_audio_metering 1");
1408 window->resize_event(window->get_w(),window->get_h());
1409 window->unlock_window();
1413 void Record::set_video_monitoring(int mode)
1415 monitor_video = mode;
1416 record_gui->lock_window("Record::set_video_monitoring");
1417 if( record_gui->monitor_video )
1418 record_gui->monitor_video->update(mode);
1419 record_gui->flush();
1420 record_gui->unlock_window();
1423 int Record::get_time_format()
1425 return SESSION->time_format;
1428 int Record::set_record_mode(int value)
1430 Batch *batch = get_editing_batch();
1431 batch->record_mode = value;
1432 record_gui->update_batches();
1436 int Record::check_batch_complete()
1440 if( writing_file && cron_active() > 0 ) {
1441 Batch *batch = get_current_batch();
1442 if( batch && batch->recorded > 0 &&
1443 batch->record_mode == RECORD_TIMED &&
1444 current_display_position() >= batch->record_duration ) {
1445 batch->recorded = -1;
1447 record_gui->update_batches();
1448 record_thread->batch_timed_lock->unlock();
1452 batch_lock->unlock();
1457 int Record::skimming(void *vp, int track)
1459 return ((Record*)vp)->skimming(track);
1462 int Record::skimming(int track)
1464 int64_t framenum; uint8_t *tdat; int mw, mh;
1465 if( !vdevice ) return -1;
1466 if( vdevice->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
1467 int pid, width, height; double framerate;
1468 if( vdevice->get_video_info(track, pid, framerate, width, height, 0) ) return 1;
1469 if( !framerate ) return 1;
1470 return skim_thread->skim(pid,framenum,framerate, tdat,mw,mh,width,height);
1473 void Record::start_skimming()
1475 if( commercial_check && vdevice && !skimming_active ) {
1476 skimming_active = 1;
1477 skim_thread->start(mwindow->commercials);
1478 vdevice->set_skimming(0, 0, skimming, this);
1482 void Record::stop_skimming()
1484 if( skimming_active && vdevice ) {
1485 skimming_active = 0;
1486 vdevice->set_skimming(0, 0, 0, 0);
1487 skim_thread->stop();
1491 void Record::update_skimming(int v)
1493 if( (commercial_check=v) != 0 )
1499 RecordRemoteHandler::RecordRemoteHandler(RemoteControl *remote_control)
1500 : RemoteHandler(remote_control->gui, GREEN)
1504 RecordRemoteHandler::~RecordRemoteHandler()
1509 display_video_text(int x, int y, const char *text, int font,
1510 int bg_color, int color, int alpha, double secs, double scale)
1512 // gotta have a window for resources
1513 record_monitor->window->
1514 display_video_text(x, y, text, font,
1515 bg_color, color, alpha, secs, scale);
1519 display_cut_icon(int x, int y)
1521 VFrame *cut_icon = *mwindow->theme->get_image_set("commercial");
1523 x += cut_icon->get_w()*scale; y += cut_icon->get_h()*scale;
1524 display_vframe(cut_icon, x, y, 200, 1.0, scale);
1527 DeviceDVBInput *Record::
1530 DeviceDVBInput *dvb_dev = !vdevice ? 0 :
1531 (DeviceDVBInput *)vdevice->mpeg_device();
1532 if( !dvb_dev ) dvb_dev = !adevice ? 0 :
1533 (DeviceDVBInput *)adevice->mpeg_device();
1540 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1542 if( !channel ) return;
1543 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1544 DeviceDVBInput *dvb_input = dvb_device();
1545 if( !dvb_input ) return 1;
1546 zmpeg3_t *fd = dvb_input->get_src();
1548 scale *= fd->video_height(channel->video_stream) / 1080.;
1549 int ww = in->get_w() * scale, hh = in->get_h() * scale;
1550 VFrame out(ww, hh, BC_YUV444P);
1551 BC_WindowBase::get_cmodels()->transfer(out.get_rows(), in->get_rows(),
1552 out.get_y(), out.get_u(), out.get_v(),
1553 in->get_y(), in->get_u(), in->get_v(),
1554 0, 0, in->get_w(), in->get_h(),
1555 0, 0, out.get_w(), out.get_h(),
1556 in->get_color_model(), out.get_color_model(), 0,
1557 in->get_bytes_per_line(), ww);
1558 int sz = ww * hh; uint8_t *yuv = out.get_data(), aimg[sz];
1559 uint8_t *yp = yuv, *up = yuv+sz, *vp = yuv+2*sz, *ap = 0;
1560 if( alpha > 0 ) memset(ap=aimg, alpha, sz);
1561 else if( alpha < 0 ) ap = yp;
1562 fd->display_subtitle(channel->video_stream, 1, 1,
1563 yp,up,vp,ap, x,y,ww,hh, 0, secs*1000);
1564 dvb_input->put_src();
1570 if( !channel ) return;
1571 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1572 DeviceDVBInput *dvb_input = dvb_device();
1573 if( !dvb_input ) return 1;
1574 zmpeg3_t *fd = dvb_input->get_src();
1576 fd->delete_subtitle(channel->video_stream, 1, 1);
1577 dvb_input->put_src();
1583 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1585 record_monitor->display_vframe(in, x, y, alpha, secs, scale);
1591 record_monitor->undisplay_vframe();
1597 display_channel_info()
1599 if( !channel ) return 1;
1600 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1601 DeviceDVBInput *dvb_input = dvb_device();
1602 if( !dvb_input ) return 1;
1603 int elem = channel->element;
1604 time_t tt; time(&tt);
1605 struct tm ttm; localtime_r(&tt,&ttm);
1607 char text[BCTEXTLEN];
1608 zmpeg3_t *fd = dvb_input->get_src();
1610 for( int ord=0, i=0; ord<0x80; ) {
1612 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1613 if( len < 0 ) { ++ord; i = 0; continue; }
1614 struct tm stm = ttm, etm = ttm;
1615 char wday[4], *bp = cp; cp += len;
1616 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1617 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1618 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1619 while( bp<cp && *bp++!='\n' );
1620 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1621 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1622 stm.tm_year -= 1900; stm.tm_mon -= 1;
1623 etm.tm_year = stm.tm_year;
1624 etm.tm_mon = stm.tm_mon;
1625 etm.tm_mday = stm.tm_mday;
1626 time_t st = mktime(&stm), et = mktime(&etm);
1627 if( et < st ) et += 24*3600;
1628 if( tt < st || tt >= et ) continue;
1629 int major=0, minor=0;
1630 fd->dvb.get_channel(elem, major, minor);
1631 char chan[64]; sprintf(chan, "%3d.%1d", major, minor);
1632 for( i=0; i<5 && chan[i]!=0; ++i ) *bp++ = chan[i];
1633 while( bp<cp && *bp++!='\n' );
1635 for( char *lp=bp; bp<cp; ++bp ) {
1636 if( *bp == '\n' || ((bp-lp)>=60 && *bp==' ') ) {
1637 if( ++n >= 10 ) break;
1642 while( bp > text && *--bp == '\n' ) *bp = 0;
1646 dvb_input->put_src();
1648 display_video_text(20, 20, text,
1649 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1654 display_channel_schedule()
1656 if( !channel ) return 1;
1657 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1658 DeviceDVBInput *dvb_input = dvb_device();
1659 if( !dvb_input ) return 1;
1660 int elem = channel->element;
1661 time_t tt; time(&tt);
1662 struct tm ttm; localtime_r(&tt,&ttm);
1663 char text[BCTEXTLEN];
1664 zmpeg3_t *fd = dvb_input->get_src();
1666 RecordSchedule channel_schedule;
1667 for( int ord=0, i=0; ord<0x80; ) {
1669 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1670 if( len < 0 ) { ++ord; i = 0; continue; }
1671 struct tm stm = ttm, etm = ttm;
1672 char wday[4], *bp = cp; cp += len;
1673 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1674 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1675 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1676 while( bp<cp && *bp++!='\n' );
1677 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1678 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1679 stm.tm_year -= 1900; stm.tm_mon -= 1;
1680 etm.tm_year = stm.tm_year;
1681 etm.tm_mon = stm.tm_mon;
1682 etm.tm_mday = stm.tm_mday;
1683 time_t st = mktime(&stm), et = mktime(&etm);
1684 if( et < st ) et += 24*3600;
1685 if( tt >= et ) continue;
1686 if( bp > text )*--bp = 0;
1687 channel_schedule.append(new RecordScheduleItem(st, text));
1689 dvb_input->put_src();
1691 channel_schedule.sort_times();
1692 char *cp = text, *ep = cp+sizeof(text)-1;
1693 for( int i=0, n=0; i<channel_schedule.size(); ++i ) {
1694 RecordScheduleItem *item = channel_schedule.get(i);
1695 for( char *bp=item->title; cp<ep && *bp!=0; ++bp ) *cp++ = *bp;
1696 if( cp < ep ) *cp++ = '\n';
1697 if( ++n >= 12 ) break;
1700 while( cp > text && *--cp == '\n' ) *cp = 0;
1702 display_video_text(20, 20, text,
1703 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1707 void Record::clear_keybfr()
1713 void Record::add_key(int ch)
1716 while( n<(int)sizeof(keybfr)-2 && keybfr[n] ) ++n;
1717 keybfr[n++] = ch; keybfr[n] = 0;
1718 display_video_text(20, 20, keybfr,
1719 BIGFONT, WHITE, BLACK, 0, 3., 2.);
1722 int RecordRemoteHandler::remote_process_key(RemoteControl *remote_control, int key)
1724 Record *record = remote_control->mwindow_gui->record;
1725 return record->remote_process_key(remote_control, key);
1728 int Record::remote_process_key(RemoteControl *remote_control, int key)
1734 if( last_key == KPENTER ) {
1735 set_channel_name(keybfr);
1739 ch = '.'; // fall through
1740 case '0': if( last_key == '0' && ch == '0' ) {
1744 case '1': case '2': case '3': case '4':
1745 case '5': case '6': case '7': case '8': case '9':
1748 //case UP: case DOWN: case LEFT: case RIGHT:
1749 //case KPPLAY: case KPBACK: case KPFORW:
1750 case KPRECD: case 'c': // start capture, mark endpoint
1752 start_commercial_capture();
1754 set_play_gain(0.075);
1757 mark_commercial_capture(DEL_MARK);
1758 blink_status->update();
1760 display_cut_icon(10,20);
1762 case KPSTOP: case 'd': // end capture, start cutting
1763 remote_control->set_color(YELLOW);
1764 stop_commercial_capture(1);
1766 case KPAUSE: case 'x': // ignore current commercial
1767 mark_commercial_capture(DEL_SKIP);
1769 case KPBACK: case 'a': // toggle mute audio
1770 if( !monitor_audio ) { set_mute_gain(1); set_play_gain(1); }
1771 set_audio_monitoring(monitor_audio ? 0 : 1);
1773 case 'm': // toggle metering audio
1774 set_audio_metering(metering_audio ? 0 : 1);
1776 case KPPLAY: case 's': // ignore previous endpoint
1777 mark_commercial_capture(DEL_OOPS);
1779 case KPFWRD: case KPSLASH:
1780 display_channel_info();
1782 case KPMAXW: case KPSTAR:
1783 display_channel_schedule();
1785 case KPCHUP: case KPPLUS:
1788 case KPCHDN: case KPMINUS:
1792 Canvas *canvas = record_monitor->window->canvas;
1793 if( !canvas->get_fullscreen() )
1794 canvas->start_fullscreen();
1796 canvas->stop_fullscreen();
1807 int Record::start_commercial_capture()
1809 if( deletions != 0 ) return 1;
1810 Channel *channel = get_current_channel();
1811 if( !channel ) return 1;
1812 int track = channel->video_stream;
1813 int pid = vdevice->get_video_pid(track);
1814 if( pid < 0 ) return 1;
1815 time_t st; time(&st);
1816 struct tm stm; localtime_r(&st, &stm);
1817 char file_path[BCTEXTLEN];
1818 sprintf(file_path,"/tmp/del%04d%02d%02d-%02d%02d%02d.ts",
1819 stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
1820 stm.tm_hour, stm.tm_min, stm.tm_sec);
1821 commercial_fd = open(file_path,O_RDWR+O_CREAT,0666);
1822 if( commercial_fd < 0 ) return 1;
1823 if( vdevice->start_record(commercial_fd, 0x800000) ) {
1824 close(commercial_fd);
1828 commercial_start_time = st;
1829 printf("del to %s\n", file_path);
1830 deletions = new Deletions(pid, file_path);
1831 mark_commercial_capture(DEL_START);
1832 blink_status->start();
1836 int Record::mark_commercial_capture(int action)
1838 if( deletions == 0 ) return 1;
1839 double time = vdevice->get_timestamp();
1840 printf("dele %f\n", time);
1841 deletions->append(new Dele(time, action));
1845 void Record::remote_fill_color(int color)
1847 mwindow->gui->remote_control->fill_color(color);
1850 void Record::set_status_color(int color)
1852 status_color = color;
1853 remote_fill_color(status_color);
1856 void Record::set_mute_gain(double gain)
1858 gain = (mute_gain = gain) * play_gain;
1859 if( adevice ) adevice->set_play_gain(gain);
1862 void Record::set_play_gain(double gain)
1864 gain = mute_gain * (play_gain = gain);
1865 if( adevice ) adevice->set_play_gain(gain);
1868 int Record::stop_commercial_capture(int run_job)
1870 if( deletions == 0 ) return 1;
1871 if( run_job ) blink_status->stop();
1874 vdevice->stop_record();
1875 commercial_start_time = -1;
1876 if( commercial_fd >= 0 ) {
1877 close(commercial_fd);
1882 char del_filename[BCTEXTLEN];
1883 strcpy(del_filename, deletions->file_path());
1884 strcpy(strrchr(del_filename, '.'),".del");
1885 if( !deletions->write_dels(del_filename) ) {
1886 int pid = spawn("cutads %s",del_filename);
1888 cut_pids.append(pid);
1889 cutads_status->start_waiting();
1895 remove_file(deletions->filepath);
1897 delete deletions; deletions = 0;
1902 spawn(const char *fmt, ...)
1904 char exe_path[BCTEXTLEN], cmd[BCTEXTLEN];
1905 get_exe_path(exe_path);
1906 va_list ap; va_start(ap, fmt);
1907 int n = snprintf(cmd, sizeof(cmd), "exec %s/", exe_path);
1908 vsnprintf(cmd+n, sizeof(cmd)-n, fmt, ap); va_end(ap);
1909 pid_t pid = vfork();
1910 if( pid < 0 ) return -1;
1911 if( pid > 0 ) return pid;
1912 char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
1913 execvp(argv[0], &argv[0]);
1920 for( int i=0; i<cut_pids.size(); ) {
1921 int status, pid = cut_pids.get(i);
1922 if( waitpid(pid, &status, WNOHANG) ) {
1923 cut_pids.remove(pid);
1928 return cut_pids.size();
1932 RecordCutAdsStatus::
1933 RecordCutAdsStatus(Record *record)
1936 this->record = record;
1937 wait_lock = new Condition(0,"RecordCutAdsStatus::wait_lock",0);
1942 RecordCutAdsStatus::
1943 ~RecordCutAdsStatus()
1947 wait_lock->unlock();
1954 void RecordCutAdsStatus::
1957 wait_lock->unlock();
1960 void RecordCutAdsStatus::
1963 int status, pgrp = getpgrp();
1965 wait_lock->lock("RecordCutAdsStatus::run");
1967 if( !record->commercial_jobs() ) continue;
1968 record->set_status_color(YELLOW);
1971 waitpid(-pgrp, &status, 0);
1973 if( !record->commercial_jobs() ) break;
1975 record->set_status_color(GREEN);
1979 void RecordBlinkStatus::
1980 remote_color(int color)
1982 record->remote_fill_color(color);
1985 void RecordBlinkStatus::
1991 void RecordBlinkStatus::
1999 void RecordBlinkStatus::
2010 RecordBlinkStatus(Record *record)
2013 this->record = record;
2017 ~RecordBlinkStatus()
2022 void RecordBlinkStatus::
2027 remote_color(color);
2031 color ^= YELLOW ^ BLUE;
2032 if( timer.get_difference() > 10*60*1000 ) { // 10 minites
2033 record->stop_commercial_capture(0);
2037 remote_color(record->status_color);