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"
51 #include "libzmpeg3.h"
55 #include "mwindowgui.h"
58 #include "playbackengine.h"
59 #include "preferences.h"
61 #include "recordaudio.h"
62 #include "recordconfig.h"
63 #include "recordgui.h"
64 #include "recordlabel.h"
65 #include "recordmonitor.h"
66 #include "recordprefs.inc"
67 #include "recordthread.h"
68 #include "recordvideo.h"
69 #include "removefile.h"
70 #include "mainsession.h"
71 #include "sighandler.h"
72 #include "testobject.h"
76 #include "videoconfig.h"
77 #include "videodevice.h"
82 #include <sys/types.h>
86 RecordMenuItem::RecordMenuItem(MWindow *mwindow)
87 : BC_MenuItem(_("Record..."), "r", 'r')
89 this->mwindow = mwindow;
90 record = new Record(mwindow, this);
93 RecordMenuItem::~RecordMenuItem()
98 int RecordMenuItem::handle_event()
105 Record::Record(MWindow *mwindow, RecordMenuItem *menu_item)
107 record_batches(mwindow)
109 this->mwindow = mwindow;
110 this->menu_item = menu_item;
111 mwindow->gui->record = this;
115 picture = new PictureConfig();
116 channeldb = new ChannelDB;
117 master_channel = new Channel;
118 record_channel = new RecordChannel(this);
123 pause_lock = new Mutex("Record::pause_lock");
124 init_lock = new Condition(0,"Record::init_lock");
130 session_sample_offset = 0;
131 device_sample_offset = 0;
136 drop_overrun_frames = 0;
137 fill_underrun_frames = 0;
139 commercial_check = skimming_active = 0;
140 commercial_start_time = -1;
148 current_frame = written_frames = total_frames = 0;
149 current_sample = written_samples = total_samples = 0;
150 audio_time = video_time = -1.;
151 play_gain = mute_gain = 1.;
153 input_threads_pausing = 0;
154 window_lock = new Mutex("Record::window_lock");
155 timer_lock = new Mutex("Record::timer_lock");
156 file_lock = new Mutex("Record::file_lock");
157 adevice_lock = new Mutex("Record::adevice_lock");
158 vdevice_lock = new Mutex("Record::vdevice_lock");
159 batch_lock = new Mutex("Record::batch_lock");
160 #ifdef HAVE_COMMERCIAL
161 skim_thread = new SkimDbThread();
162 cutads_status = new RecordCutAdsStatus(this);
163 blink_status = new RecordBlinkStatus(this);
165 deinterlace = RECORD_LACE_ODD;
170 mwindow->gui->record = 0;
172 #ifdef HAVE_COMMERCIAL
174 delete cutads_status;
181 delete record_channel;
182 delete master_channel;
195 int Record::load_defaults()
198 char string[BCTEXTLEN];
199 BC_Hash *defaults = mwindow->defaults;
200 EDLSession *session = SESSION;
201 default_asset->copy_from(session->recording_format, 0);
202 default_asset->channels = session->aconfig_in->channels;
203 default_asset->sample_rate = session->aconfig_in->in_samplerate;
204 default_asset->frame_rate = session->vconfig_in->in_framerate;
205 default_asset->width = session->vconfig_in->w;
206 default_asset->height = session->vconfig_in->h;
207 default_asset->layers = 1;
208 // Fix encoding parameters depending on driver.
209 // These are locked by a specific driver.
210 const char *vcodec = 0;
211 switch( session->vconfig_in->driver ) {
213 case VIDEO4LINUX2MPEG:
215 case VIDEO4LINUX2JPEG:
216 vcodec = CODEC_TAG_MJPEG;
218 case CAPTURE_FIREWIRE:
219 case CAPTURE_IEC61883:
220 vcodec = CODEC_TAG_DVSD;
224 strcpy(default_asset->vcodec, vcodec);
226 record_batches.load_defaults(channeldb, this);
228 int cur_chan_no = defaults->get("RECORD_CURRENT_CHANNEL", 0);
229 current_channel = channeldb->get(cur_chan_no);
230 load_mode = defaults->get("RECORD_LOADMODE", LOADMODE_PASTE);
231 monitor_audio = defaults->get("RECORD_MONITOR_AUDIO", 1);
232 metering_audio = defaults->get("RECORD_METERING_AUDIO", 1);
233 monitor_video = defaults->get("RECORD_MONITOR_VIDEO", 1);
234 video_window_open = defaults->get("RECORD_MONITOR_OPEN", 1);
235 video_x = defaults->get("RECORD_VIDEO_X", 0);
236 video_y = defaults->get("RECORD_VIDEO_Y", 0);
237 video_zoom = defaults->get("RECORD_VIDEO_Z", (float)1);
238 picture->load_defaults();
239 reverse_interlace = defaults->get("REVERSE_INTERLACE", 0);
240 deinterlace = defaults->get("DEINTERLACE", RECORD_LACE_ODD);
241 do_cursor = defaults->get("RECORD_CURSOR", 0);
242 do_big_cursor = defaults->get("RECORD_BIG_CURSOR", 0);
243 for( int i=0; i<MAXCHANNELS; ++i ) {
244 sprintf(string, "RECORD_DCOFFSET_%d", i);
245 dc_offset[i] = defaults->get(string, 0);
247 drop_overrun_frames = defaults->get("DROP_OVERRUN_FRAMES", 0);
248 fill_underrun_frames = defaults->get("FILL_UNDERRUN_FRAMES", 0);
249 commercial_check = defaults->get("COMMERCIAL_CHECK", 0);
253 int Record::save_defaults()
255 char string[BCTEXTLEN];
256 BC_Hash *defaults = mwindow->defaults;
257 set_editing_batch(0);
258 // Save default asset path but not the format because that's
259 // overridden by the driver.
260 // The format is saved in preferences.
261 if( record_batches.total() )
262 strcpy(default_asset->path, record_batches[0]->asset->path);
263 default_asset->save_defaults(defaults, "RECORD_", 0, 0, 0, 0, 0);
265 record_batches.save_defaults(channeldb);
267 int cur_chan_no = channeldb->number_of(current_channel);
268 defaults->update("RECORD_CURRENT_CHANNEL", cur_chan_no);
269 defaults->update("RECORD_LOADMODE", load_mode);
270 defaults->update("RECORD_MONITOR_AUDIO", monitor_audio);
271 defaults->update("RECORD_METERING_AUDIO", metering_audio);
272 defaults->update("RECORD_MONITOR_VIDEO", monitor_video);
273 defaults->update("RECORD_MONITOR_OPEN", video_window_open);
274 defaults->update("RECORD_VIDEO_X", video_x);
275 defaults->update("RECORD_VIDEO_Y", video_y);
276 defaults->update("RECORD_VIDEO_Z", video_zoom);
277 picture->save_defaults();
278 defaults->update("REVERSE_INTERLACE", reverse_interlace);
279 defaults->update("DEINTERLACE", deinterlace);
280 defaults->update("RECORD_CURSOR", do_cursor);
281 defaults->update("RECORD_BIG_CURSOR", do_big_cursor);
282 for( int i=0; i<MAXCHANNELS; ++i ) {
283 sprintf(string, "RECORD_DCOFFSET_%d", i);
284 defaults->update(string, dc_offset[i]);
286 defaults->update("DROP_OVERRUN_FRAMES", drop_overrun_frames);
287 defaults->update("FILL_UNDERRUN_FRAMES", fill_underrun_frames);
288 defaults->update("COMMERCIAL_CHECK", commercial_check);
294 void Record::configure_batches()
296 // printf("Record::configure_batches %d\n",__LINE__);
297 // default_assset->dump();
298 strcpy(record_batches[0]->asset->path, default_asset->path);
299 int total_batches = record_batches.total();
300 for( int i=0; i<total_batches; ++i ) {
301 Batch *batch = record_batches[i];
302 batch->asset->copy_format(default_asset);
310 // Default asset forms the first path in the batch capture
311 // and the file format for all operations.
312 default_asset = new Asset;
314 // Determine information about the device.
315 AudioInConfig *aconfig_in = SESSION->aconfig_in;
316 VideoInConfig *vconfig_in = SESSION->vconfig_in;
317 int driver = vconfig_in->driver;
318 VideoDevice::load_channeldb(channeldb, vconfig_in);
319 fixed_compression = VideoDevice::is_compressed(driver, 0, 1);
321 // Apply a major kludge
322 if( fixed_compression ) {
324 device.fix_asset(default_asset, driver);
326 default_asset->channels = aconfig_in->channels;
327 VideoDevice::save_channeldb(channeldb, vconfig_in);
329 mwindow->save_defaults();
331 set_current_batch(0);
332 set_editing_batch(0);
336 edl->create_objects();
337 edl->session->output_w = default_asset->width;
338 edl->session->output_h = default_asset->height;
339 edl->session->aspect_w = SESSION->aspect_w;
340 edl->session->aspect_h = SESSION->aspect_h;
342 window_lock->lock("Record::run 3");
343 record_gui = new RecordGUI(mwindow, this);
344 record_gui->create_objects();
346 record_monitor = new RecordMonitor(mwindow, this);
347 record_monitor->create_objects();
348 record_gui->update_batch_sources();
350 record_gui->show_window();
353 if( mwindow->gui->remote_control->deactivate() &&
354 mwindow->gui->record_remote_handler )
355 mwindow->gui->record_remote_handler->activate();
357 if( video_window_open ) {
358 record_monitor->window->show_window();
359 record_monitor->window->raise_window();
360 record_monitor->window->flush();
363 window_lock->unlock();
365 start_input_threads();
369 result = record_gui->run_window();
370 // record gui operates here until window is closed
372 if( record_gui->get_window_lock() ) {
373 record_gui->lock_window();
374 record_gui->unlock_window();
377 // Need to stop everything this time
379 int video_stream = -1;
380 #ifdef HAVE_COMMERCIAL
381 stop_commercial_capture(0);
384 if( default_asset->format == FILE_MPEG ) {
385 Channel *channel = get_current_channel();
387 video_stream = channel->video_stream;
391 edl->Garbage::remove_user();
393 if( mwindow->gui->remote_control->deactivate() &&
394 mwindow->gui->cwindow_remote_handler )
395 mwindow->gui->cwindow_remote_handler->activate();
397 // Save everything again
401 if( !result && load_mode != LOADMODE_NOTHING ) {
402 mwindow->gui->lock_window("Record::run");
403 ArrayList<EDL*> new_edls;
405 int total_batches = record_batches.total();
406 for( int i=0; i<total_batches; ++i ) {
407 Batch *batch = record_batches[i];
408 Asset *asset = batch->asset;
409 if( batch->recorded ) {
410 EDL *new_edl = new EDL;
411 mwindow->remove_from_caches(asset);
412 new_edl->create_objects();
413 new_edl->copy_session(mwindow->edl);
414 mwindow->asset_to_edl(new_edl, asset, batch->labels);
415 new_edls.append(new_edl);
420 mwindow->undo->update_undo_before();
421 // For pasting, clear the active region
422 if(load_mode == LOADMODE_PASTE)
424 int loadmode = load_mode == LOADMODE_RESOURCESONLY ?
425 LOADMODE_ASSETSONLY : load_mode;
426 mwindow->paste_edls(&new_edls, loadmode, 0, -1,
427 SESSION->labels_follow_edits,
428 SESSION->plugins_follow_edits,
429 SESSION->autos_follow_edits,
431 for( int i=0; i<new_edls.total; ++i )
432 new_edls.get(i)->Garbage::remove_user();
433 new_edls.remove_all();
434 if( video_stream >= 0 ) {
435 mwindow->select_asset(video_stream, -1);
436 mwindow->fit_selection();
438 mwindow->save_backup();
439 mwindow->undo->update_undo_after(_("record"), LOAD_ALL);
440 mwindow->restart_brender();
441 mwindow->update_plugin_guis();
442 mwindow->gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
443 mwindow->sync_parameters(CHANGE_ALL);
445 mwindow->gui->unlock_window();
447 AWindowGUI *agui = mwindow->awindow->gui;
448 agui->async_update_assets();
452 record_batches.clear();
453 default_asset->Garbage::remove_user();
456 void Record::stop(int wait)
460 record_gui->set_done(1);
463 window_lock->lock("Record::stop");
464 delete record_thread; record_thread = 0;
465 delete record_monitor; record_monitor = 0;
466 delete record_gui; record_gui = 0;
467 window_lock->unlock();
470 void Record::activate_batch(int number)
472 if( number != current_batch() ) {
474 set_current_batch(number);
475 record_gui->update_batches();
476 record_gui->update_position(current_display_position());
477 record_gui->update_batch_tools();
482 void Record::delete_index_file(Asset *asset)
484 IndexFile::delete_index_files(mwindow->preferences, asset);
487 void Record::delete_batch()
489 // Abort if one batch left
490 int edit_batch = editing_batch();
491 int total_batches = record_batches.total();
492 if( total_batches > 1 && edit_batch < total_batches ) {
493 int cur_batch = current_batch();
494 Batch *batch = record_batches[edit_batch];
495 record_batches.remove(batch); delete batch;
496 if( cur_batch == edit_batch ) stop_writing();
497 record_gui->update_batches();
498 record_gui->update_batch_tools();
502 void Record::change_editing_batch(int number)
504 set_editing_batch(number);
505 record_gui->update_batch_tools();
508 Batch* Record::new_batch()
510 Batch *batch = new Batch(mwindow, this);
511 //printf("Record::new_batch 1\n");
512 batch->create_objects();
513 record_batches.append(batch);
514 batch->asset->copy_format(default_asset);
516 //printf("Record::new_batch 1\n");
517 batch->create_default_path();
518 Batch *edit_batch = get_editing_batch();
520 batch->copy_from(edit_batch);
521 int total_batches = record_batches.total();
522 set_editing_batch(total_batches - 1);
523 //printf("Record::new_batch 1\n");
524 // Update GUI if created yet
526 record_gui->update_batch_tools();
527 //printf("Record::new_batch 2\n");
531 int Record::current_batch()
533 return record_batches.current_item;
536 int Record::set_current_batch(int i)
538 return record_batches.current_item = i;
541 int Record::editing_batch()
543 return record_batches.editing_item;
546 int Record::set_editing_batch(int i)
548 return record_batches.editing_item = i;
551 int Record::delete_output_file()
553 Batch *batch = get_current_batch();
555 if( !file && batch && !access(batch->asset->path, F_OK) ) {
556 batch->set_notice(_("Deleting"));
557 record_gui->update_batches();
558 Asset *asset = batch->asset;
559 remove_file(asset->path);
560 mwindow->remove_from_caches(asset);
561 delete_index_file(asset);
562 batch->clear_notice();
563 record_gui->update_batches();
568 int Record::open_output_file()
572 Batch *batch = get_current_batch();
573 if( !file && batch ) {
574 delete_output_file();
575 Asset *asset = batch->asset;
576 asset->frame_rate = default_asset->frame_rate;
577 asset->sample_rate = default_asset->sample_rate;
578 asset->width = default_asset->width;
579 asset->height = default_asset->height;
581 if( default_asset->format == FILE_MPEG ) {
582 asset->layers = vdevice ? vdevice->total_video_streams() : 0;
583 asset->channels = adevice ? adevice->total_audio_channels() : 0;
587 result = file->open_file(mwindow->preferences, asset, 0, wr);
589 mwindow->sighandler->push_file(file);
591 file->set_processors(mwindow->preferences->real_processors);
592 record_gui->update_batches();
606 window_lock->lock("Record::start");
607 record_gui->lock_window("Record::start");
608 record_gui->raise_window();
609 record_gui->unlock_window();
610 window_lock->unlock();
618 void Record::start_over()
621 Batch *batch = get_current_batch();
622 if( batch ) batch->start_over();
623 record_gui->update_batches();
626 void Record::stop_operation()
629 stop_input_threads();
632 int Record::cron_active()
634 return !record_thread ? 0 : record_thread->cron_active;
637 void Record::close_output_file()
641 mwindow->sighandler->pull_file(file);
647 record_gui->update_batches();
650 void Record::toggle_label()
652 Batch *batch = get_current_batch();
653 if( batch ) batch->toggle_label(current_display_position());
654 record_gui->update_labels(current_display_position());
657 void Record::clear_labels()
659 Batch *batch = get_current_batch();
660 if( batch ) batch->clear_labels();
661 record_gui->update_labels(0);
664 int Record::get_fragment_samples()
666 const int min_samples = 1024, max_samples = 32768;
667 int samples, low_bit;
668 samples = default_asset->sample_rate / SESSION->record_speed;
669 if( samples < min_samples ) samples = min_samples;
670 else if( samples > max_samples ) samples = max_samples;
671 // loop until only one bit left standing
672 while( (low_bit=(samples & ~(samples-1))) != samples )
677 int Record::get_buffer_samples()
679 int fragment_samples = get_fragment_samples();
680 if( !fragment_samples ) return 0;
681 int fragments = (SESSION->record_write_length+fragment_samples-1) / fragment_samples;
682 if( fragments < 1 ) fragments = 1;
683 return fragments * fragment_samples;
686 Batch* Record::get_current_batch()
688 return record_batches.get_current_batch();
691 Batch* Record::get_editing_batch()
693 return record_batches.get_editing_batch();
696 int Record::get_next_batch(int incr)
698 int i = current_batch();
701 int total_batches = record_batches.total();
702 while( i < total_batches ) {
703 if( record_batches[i]->enabled ) return i;
710 const char* Record::current_mode()
712 Batch *batch = get_current_batch();
713 return batch ? Batch::mode_to_text(batch->record_mode) : "";
716 double Record::current_display_position()
718 //printf("Record::current_display_position "%jd %jd\n", total_samples, total_frames);
720 Asset *asset = default_asset;
722 if( asset->video_data && record_video )
723 result = (double) written_frames / asset->frame_rate;
724 else if( asset->audio_data && record_audio )
725 result = (double) written_samples / asset->sample_rate;
728 if( asset->video_data && record_video )
729 result = (double) total_frames / asset->frame_rate;
730 else if( asset->audio_data && record_audio )
731 result = (double) total_samples / asset->sample_rate;
733 result = (double) total_time.get_difference() / 1000.;
738 const char* Record::current_source()
740 Batch *batch = get_current_batch();
741 return batch ? batch->get_source_text() : _("Unknown");
744 Asset* Record::current_asset()
746 Batch *batch = get_current_batch();
747 return batch ? batch->asset : 0;
750 Channel *Record::get_current_channel()
752 return current_channel;
755 Channel *Record::get_editing_channel()
757 Batch *batch = get_editing_batch();
758 return batch ? batch->channel : 0;
761 ArrayList<Channel*>* Record::get_video_inputs()
763 return default_asset->video_data && vdevice ? vdevice->get_inputs() : 0;
767 int64_t Record::timer_position()
769 timer_lock->lock("RecordAudio::timer_positioin");
770 int samplerate = default_asset->sample_rate;
771 int64_t result = timer.get_scaled_difference(samplerate);
772 result += session_sample_offset;
773 timer_lock->unlock();
777 void Record::reset_position(int64_t position)
779 timer_lock->lock("RecordAudio::reset_position");
780 session_sample_offset = position;
781 device_sample_offset = adevice ? adevice->current_position() : 0;
783 timer_lock->unlock();
786 void Record::update_position()
788 int64_t position = sync_position();
789 reset_position(position);
790 current_frame = current_sample = 0;
791 audio_time = video_time = -1.;
794 int64_t Record::adevice_position()
796 timer_lock->lock("RecordAudio::adevice_position");
797 int64_t result = adevice->current_position();
798 result += session_sample_offset - device_sample_offset;
799 timer_lock->unlock();
803 int64_t Record::sync_position()
805 int64_t sync_position = -1;
806 double sync_time = -1.;
807 double next_audio_time = -1.;
808 double next_video_time = -1.;
810 if( current_frame == 0 && current_sample == 0 ) {
811 audio_time = video_time = -1.;
814 switch( SESSION->record_positioning ) {
815 case RECORD_POS_TIMESTAMPS:
816 if( default_asset->video_data && record_video )
817 next_video_time = vdevice->get_timestamp();
818 if( default_asset->audio_data && record_audio ) {
820 !adevice->is_monitoring() || writing_file > 0 ?
821 adevice->get_itimestamp() :
822 adevice->get_otimestamp();
824 if( next_audio_time >= 0. )
825 sync_time = next_audio_time;
826 else if( next_video_time > 0. )
827 sync_time = next_video_time;
828 if( sync_time >= 0. ) {
829 sync_position = sync_time * default_asset->sample_rate;
831 if( sync_position >= 0 ) break;
832 case RECORD_POS_DEVICE:
833 if( default_asset->audio_data && record_audio )
834 sync_position = adevice_position();
835 if( sync_position > 0 ) break;
836 case RECORD_POS_SOFTWARE:
837 sync_position = timer_position();
838 if( sync_position > 0 ) break;
839 case RECORD_POS_SAMPLE:
841 sync_position = current_sample;
845 if( next_video_time < 0. )
846 next_video_time = current_frame / default_asset->frame_rate;
847 if( next_video_time > video_time )
848 video_time = next_video_time;
849 if( next_audio_time < 0. )
850 next_audio_time = (double)sync_position / default_asset->sample_rate;
851 if( next_audio_time > audio_time )
852 audio_time = next_audio_time;
854 return sync_position;
858 void Record::adevice_drain()
860 if( adevice && record_audio ) {
861 adevice->stop_audio(0);
862 adevice->start_recording();
867 #define dbmsg if( debug ) printf
868 void Record::resync()
870 dropped = behind = 0;
871 int64_t audio_position = sync_position();
872 double audiotime = (double) audio_position / default_asset->sample_rate;
873 double diff = video_time - audiotime;
875 dbmsg("resync video %f audio %f/%f diff %f",
876 video_time, audiotime, audio_time, diff);
877 if( fabs(diff) > 5. ) {
878 dbmsg(" drain audio");
879 // jam job dvb file tesing, comment next line
880 record_channel->drain_audio();
882 else if( diff > 0. ) {
883 int64_t delay = (int64_t)(1000.0 * diff);
884 dbmsg(" delay %8jd", delay);
886 video_time = audio_time = -1.;
893 behind = (int)(-diff * default_asset->frame_rate);
894 dbmsg(" behind %d", behind);
895 if( behind > 1 && fill_underrun_frames ) {
896 dropped = behind > 3 ? 3 : behind-1;
897 dbmsg(" dropped %d", dropped);
901 int frames = dropped + 1;
902 current_frame += frames;
903 total_frames += frames;
904 record_gui->update_video(dropped, behind);
905 if( dropped > 0 && drop_overrun_frames )
906 if( vdevice ) vdevice->drop_frames(dropped);
910 void Record::close_audio_input()
912 adevice_lock->lock();
914 adevice->close_all();
918 adevice_lock->unlock();
921 void Record::close_video_input()
923 vdevice_lock->lock();
925 vdevice->close_all();
929 vdevice_lock->unlock();
932 void Record::close_input_devices()
938 void Record::stop_audio_thread()
941 record_audio->stop_recording();
949 void Record::stop_video_thread()
952 record_video->stop_recording();
961 void Record::stop_input_threads()
963 pause_lock->lock("Record::stop_input_threads");
968 pause_lock->unlock();
971 void Record::stop_playback()
974 record_monitor->stop_playback();
977 void Record::open_audio_input()
980 adevice_lock->lock();
982 if( default_asset->audio_data )
983 adevice = new AudioDevice(mwindow);
986 int sw_pos = SESSION->record_positioning == RECORD_POS_SOFTWARE;
987 adevice->set_software_positioning(sw_pos);
988 adevice->open_input(SESSION->aconfig_in, SESSION->vconfig_in,
989 default_asset->sample_rate, get_fragment_samples(),
990 default_asset->channels, SESSION->real_time_record);
991 adevice->start_recording();
992 adevice->open_monitor(SESSION->playback_config->aconfig,monitor_audio);
993 adevice->set_vdevice(vdevice);
994 if( vdevice ) vdevice->set_adevice(adevice);
996 adevice_lock->unlock();
999 void Record::open_video_input()
1001 close_video_input();
1002 vdevice_lock->lock();
1003 if( default_asset->video_data )
1004 vdevice = new VideoDevice(mwindow);
1007 vdevice->set_quality(default_asset->jpeg_quality);
1008 vdevice->open_input(SESSION->vconfig_in, video_x, video_y,
1009 video_zoom, default_asset->frame_rate);
1010 // Get configuration parameters from device probe
1011 color_model = vdevice->get_best_colormodel(default_asset);
1012 master_channel->copy_usage(vdevice->channel);
1013 picture->copy_usage(vdevice->picture);
1014 vdevice->set_field_order(reverse_interlace);
1015 vdevice->set_do_cursor(do_cursor, do_big_cursor);
1016 vdevice->set_adevice(adevice);
1017 if( adevice ) adevice->set_vdevice(vdevice);
1018 set_dev_channel(get_current_channel());
1020 vdevice_lock->unlock();
1023 void Record::start_audio_thread()
1026 if( !record_audio ) {
1027 total_samples = current_sample = 0; audio_time = -1.;
1028 record_audio = new RecordAudio(mwindow,this);
1029 record_audio->arm_recording();
1030 record_audio->start_recording();
1035 void Record::start_video_thread()
1038 if( !record_video ) {
1039 total_frames = current_frame = 0; video_time = -1.;
1040 record_video = new RecordVideo(mwindow,this);
1041 record_video->arm_recording();
1042 record_video->start_recording();
1047 void Record::start_input_threads()
1050 input_threads_pausing = 0;
1051 if( default_asset->audio_data )
1052 start_audio_thread();
1053 if( default_asset->video_data )
1054 start_video_thread();
1058 void Record::pause_input_threads()
1060 pause_lock->lock("Record::pause_input_threads");
1061 input_threads_pausing = 1;
1063 adevice_lock->lock();
1064 vdevice_lock->lock();
1066 record_audio->pause_recording();
1068 record_video->pause_recording();
1071 void Record::resume_input_threads()
1074 record_audio->resume_recording();
1076 record_video->resume_recording();
1077 vdevice_lock->unlock();
1078 adevice_lock->unlock();
1079 input_threads_pausing = 0;
1081 pause_lock->unlock();
1085 int Record::start_toc()
1087 if( !mwindow->edl->session->record_realtime_toc ) return 0;
1088 Batch *batch = get_current_batch();
1089 Asset *asset = batch->asset;
1090 char source_filename[BCTEXTLEN], toc_path[BCTEXTLEN];
1091 IndexFile::get_index_filename(source_filename,
1092 mwindow->preferences->index_directory,
1093 toc_path, asset->path,".toc");
1094 if( default_asset->video_data )
1095 return vdevice->start_toc(asset->path, toc_path);
1096 if( default_asset->audio_data )
1097 return adevice->start_toc(asset->path, toc_path);
1101 int Record::start_record(int fd)
1104 if( default_asset->video_data )
1105 return vdevice->start_record(fd);
1106 if( default_asset->audio_data )
1107 return adevice->start_record(fd);
1111 void Record::start_writing_file()
1113 if( !writing_file ) {
1115 written_samples = 0;
1116 do_video = File::renders_video(default_asset);
1117 do_audio = File::renders_audio(default_asset);
1118 if( single_frame ) do_audio = 0;
1119 if( !do_video && single_frame )
1121 else if( !open_output_file() )
1122 writing_file = default_asset->format == FILE_MPEG ? -1 : 1;
1123 if( do_audio && record_audio && writing_file > 0 ) {
1124 int buffer_samples = get_buffer_samples();
1125 record_audio->set_write_buffer_samples(buffer_samples);
1126 file->start_audio_thread(buffer_samples, FILE_RING_BUFFERS);
1128 if( do_video && record_video && writing_file > 0 ) {
1129 int disk_frames = SESSION->video_write_length;
1130 int cmodel = vdevice->get_best_colormodel(default_asset);
1131 int cpress = vdevice->is_compressed(1, 0);
1132 file->start_video_thread(disk_frames, cmodel, FILE_RING_BUFFERS, cpress);
1134 if( writing_file < 0 ) {
1135 int fd = file->record_fd();
1139 if( writing_file ) {
1140 record_gui->start_flash_batch();
1141 if( SESSION->record_sync_drives ) {
1142 drivesync = new DriveSync();
1150 int Record::stop_record()
1152 if( default_asset->video_data )
1153 return vdevice->stop_record();
1154 if( default_asset->audio_data )
1155 return adevice->stop_record();
1159 void Record::flush_buffer()
1162 record_audio->flush_buffer();
1164 record_video->flush_buffer();
1167 void Record::stop_writing_file()
1169 record_gui->stop_flash_batch();
1170 if( !writing_file ) return;
1171 if( writing_file > 0 )
1173 if( writing_file < 0 )
1175 close_output_file();
1177 Asset *asset = current_asset();
1178 asset->audio_length = written_samples;
1179 asset->video_length = written_frames;
1180 record_gui->flash_batch();
1182 drivesync->done = 1;
1188 void Record::stop_writing()
1190 if( writing_file ) {
1191 pause_input_threads();
1192 stop_writing_file();
1193 resume_input_threads();
1198 void Record::start_cron_thread()
1200 if( cron_active() < 0 ) {
1201 delete record_thread;
1204 if( !record_thread ) {
1205 record_thread = new RecordThread(mwindow,this);
1206 record_thread->start();
1207 record_gui->disable_batch_buttons();
1208 record_gui->update_cron_status(_("Running"));
1212 void Record::stop_cron_thread(const char *msg)
1214 if( record_thread ) {
1215 delete record_thread;
1217 record_gui->enable_batch_buttons();
1218 record_gui->update_cron_status(msg);
1222 void Record::set_power_off(int value)
1225 record_gui->power_off->update(value);
1228 void Record::set_video_picture()
1230 if( default_asset->video_data && vdevice )
1231 vdevice->set_picture(picture);
1234 void Record::set_do_cursor()
1236 vdevice->set_do_cursor(do_cursor, do_big_cursor);
1239 void Record::set_translation(int x, int y)
1243 if(default_asset->video_data && vdevice)
1244 vdevice->set_translation(video_x, video_y);
1247 int Record::set_channel(Channel *channel)
1249 if( !channel ) return 1;
1250 printf("set_channel %s\n",channel->title);
1251 if( record_channel->set(channel) ) return 1;
1252 RecordMonitorGUI *window = record_monitor->window;
1253 window->lock_window("Record::set_channel");
1254 window->channel_picker->channel_text->update(channel->title);
1255 window->unlock_window();
1259 int Record::set_channel_no(int chan_no)
1261 if( chan_no < 0 || chan_no >= channeldb->size() ) return 1;
1262 Channel *channel = channeldb->get(chan_no);
1263 return set_channel(channel);
1266 int Record::channel_down()
1268 Channel *channel = get_current_channel();
1269 if( !channel || !channeldb->size() ) return 1;
1270 int n = channeldb->number_of(channel);
1271 if( n < 0 ) return 1;
1272 if( --n < 0 ) n = channeldb->size() - 1;
1273 return set_channel_no(n);
1276 int Record::channel_up()
1278 Channel *channel = get_current_channel();
1279 if( !channel || !channeldb->size() ) return 1;
1280 int n = channeldb->number_of(channel);
1281 if( n < 0 ) return 1;
1282 if( ++n >= channeldb->size() ) n = 0;
1283 return set_channel_no(n);
1286 int Record::set_channel_name(const char *name)
1288 Channel *channel = 0;
1289 int ch = 0, nch = channeldb->size();
1291 channel = channeldb->get(ch);
1292 if( channel && !channel->cstrcmp(name) ) break;
1295 if( ch >= nch || !channel ) return 1;
1296 return set_channel(channel);
1299 void Record::set_batch_channel_no(int chan_no)
1301 Channel *channel = channeldb->get(chan_no);
1303 Batch *batch = get_editing_batch();
1304 if( batch ) batch->channel = channel;
1305 record_gui->batch_source->update(channel->title);
1309 void Record::set_dev_channel(Channel *channel)
1311 // should be tuner device, not vdevice
1312 if( channel && vdevice &&
1313 (!this->channel || *channel != *this->channel) ) {
1314 current_channel = channel;
1315 if( this->channel ) delete this->channel;
1316 this->channel = new Channel(channel);
1317 vdevice->set_channel(channel);
1318 int strk = !SESSION->decode_subtitles ? -1 : SESSION->subtitle_number;
1319 vdevice->set_captioning(strk);
1320 set_video_picture();
1321 printf("new channel %s, has_signal=%d\n",channel->title,vdevice->has_signal());
1324 total_time.update();
1328 /* widget holds xlock and set_channel pauses rendering, deadlock */
1329 /* use a background thread to update channel after widget sets it */
1330 RecordChannel::RecordChannel(Record *record)
1333 this->record = record;
1334 change_channel = new Condition(0,"RecordSetChannel::change_channel");
1335 channel_lock = new Condition(1,"Record::channel_lock",1);
1340 RecordChannel::~RecordChannel()
1343 change_channel->unlock();
1345 delete change_channel;
1346 delete channel_lock;
1349 int RecordChannel::set(Channel *channel)
1351 if( !channel || new_channel ) return 1;
1352 new_channel = channel;
1353 channel_lock->lock(); // block has_signal
1354 change_channel->unlock(); // resume channel changer thread
1358 void RecordChannel::drain_audio()
1360 if( !audio_drain ) {
1362 change_channel->unlock();
1366 void RecordChannel::run()
1370 change_channel->lock();
1372 if( !new_channel && !audio_drain ) continue;
1373 record->pause_input_threads();
1375 record->set_dev_channel(new_channel);
1376 record->record_gui->reset_video();
1377 record->record_gui->reset_audio();
1382 record->adevice_drain();
1384 record->update_position();
1385 record->resume_input_threads();
1388 channel_lock->unlock();
1393 int Record::has_signal()
1395 record_channel->channel_lock->lock("Record::has_signal");
1396 record_channel->channel_lock->unlock();
1397 vdevice_lock->lock();
1398 int result = vdevice ? vdevice->has_signal() : 0;
1399 vdevice_lock->unlock();
1403 int Record::create_channeldb(ArrayList<Channel*> *channeldb)
1405 return vdevice ? vdevice->create_channeldb(channeldb) : 1;
1409 void Record::set_audio_monitoring(int mode)
1412 monitor_audio = mode;
1414 record_audio->set_monitoring(mode);
1415 record_gui->lock_window("Record::set_audio_monitoring");
1416 if( record_gui->monitor_audio )
1417 record_gui->monitor_audio->update(mode);
1418 record_gui->unlock_window();
1421 void Record::set_audio_metering(int mode)
1423 metering_audio = mode;
1424 record_gui->lock_window("Record::set_audio_metering");
1425 if( record_gui->meter_audio )
1426 record_gui->meter_audio->update(mode);
1427 record_gui->unlock_window();
1428 RecordMonitorGUI *window = record_monitor->window;
1429 window->lock_window("Record::set_audio_metering 1");
1430 window->resize_event(window->get_w(),window->get_h());
1431 window->unlock_window();
1435 void Record::set_video_monitoring(int mode)
1437 monitor_video = mode;
1438 record_gui->lock_window("Record::set_video_monitoring");
1439 if( record_gui->monitor_video )
1440 record_gui->monitor_video->update(mode);
1441 record_gui->flush();
1442 record_gui->unlock_window();
1445 int Record::get_time_format()
1447 return SESSION->time_format;
1450 int Record::set_record_mode(int value)
1452 Batch *batch = get_editing_batch();
1453 batch->record_mode = value;
1454 record_gui->update_batches();
1458 int Record::check_batch_complete()
1462 if( writing_file && cron_active() > 0 ) {
1463 Batch *batch = get_current_batch();
1464 if( batch && batch->recorded > 0 &&
1465 batch->record_mode == RECORD_TIMED &&
1466 current_display_position() >= batch->record_duration ) {
1467 batch->recorded = -1;
1469 record_gui->update_batches();
1470 record_thread->batch_timed_lock->unlock();
1474 batch_lock->unlock();
1478 #ifdef HAVE_COMMERCIAL
1479 int Record::skimming(void *vp, int track)
1481 return ((Record*)vp)->skimming(track);
1484 int Record::skimming(int track)
1486 int64_t framenum; uint8_t *tdat; int mw, mh;
1487 if( !vdevice ) return -1;
1488 if( vdevice->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
1489 int pid, width, height; double framerate;
1490 if( vdevice->get_video_info(track, pid, framerate, width, height, 0) ) return 1;
1491 if( !framerate ) return 1;
1492 return skim_thread->skim(pid,framenum,framerate, tdat,mw,mh,width,height);
1495 void Record::start_skimming()
1497 if( commercial_check && vdevice && !skimming_active ) {
1498 skimming_active = 1;
1499 skim_thread->start(mwindow->commercials);
1500 vdevice->set_skimming(0, 0, skimming, this);
1504 void Record::stop_skimming()
1506 if( skimming_active && vdevice ) {
1507 skimming_active = 0;
1508 vdevice->set_skimming(0, 0, 0, 0);
1509 skim_thread->stop();
1513 void Record::update_skimming(int v)
1515 if( (commercial_check=v) != 0 )
1522 int Record::skimming(void *vp, int track) { return 1; }
1523 int Record::skimming(int track) { return 1; }
1524 void Record::start_skimming() {}
1525 void Record::stop_skimming() {}
1526 void Record::update_skimming(int v) {}
1529 RecordKeyEvHandler::RecordKeyEvHandler(RemoteControl *remote_control)
1530 : RemoteHandler(remote_control->gui, GREEN)
1532 this->remote_control = remote_control;
1535 RecordKeyEvHandler::~RecordKeyEvHandler()
1539 int RecordKeyEvHandler::remote_key(int key)
1541 Record *record = remote_control->mwindow_gui->record;
1542 return record->record_process_key(remote_control, key);
1546 display_video_text(int x, int y, const char *text, int font,
1547 int bg_color, int color, int alpha, double secs, double scale)
1549 // gotta have a window for resources
1550 record_monitor->window->
1551 display_video_text(x, y, text, font,
1552 bg_color, color, alpha, secs, scale);
1556 display_cut_icon(int x, int y)
1558 VFrame *cut_icon = *mwindow->theme->get_image_set("commercial");
1560 x += cut_icon->get_w()*scale; y += cut_icon->get_h()*scale;
1561 display_vframe(cut_icon, x, y, 200, 1.0, scale);
1565 DeviceDVBInput *Record::
1568 DeviceDVBInput *dvb_dev = !vdevice ? 0 :
1569 (DeviceDVBInput *)vdevice->mpeg_device();
1570 if( !dvb_dev ) dvb_dev = !adevice ? 0 :
1571 (DeviceDVBInput *)adevice->mpeg_device();
1579 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1581 if( !channel ) return;
1582 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1583 DeviceDVBInput *dvb_input = dvb_device();
1584 if( !dvb_input ) return 1;
1585 zmpeg3_t *fd = dvb_input->get_src();
1587 scale *= fd->video_height(channel->video_stream) / 1080.;
1588 int ww = in->get_w() * scale, hh = in->get_h() * scale;
1589 VFrame out(ww, hh, BC_YUV444P);
1590 BC_WindowBase::get_cmodels()->transfer(out.get_rows(), in->get_rows(),
1591 out.get_y(), out.get_u(), out.get_v(),
1592 in->get_y(), in->get_u(), in->get_v(),
1593 0, 0, in->get_w(), in->get_h(),
1594 0, 0, out.get_w(), out.get_h(),
1595 in->get_color_model(), out.get_color_model(), 0,
1596 in->get_bytes_per_line(), ww);
1597 int sz = ww * hh; uint8_t *yuv = out.get_data(), aimg[sz];
1598 uint8_t *yp = yuv, *up = yuv+sz, *vp = yuv+2*sz, *ap = 0;
1599 if( alpha > 0 ) memset(ap=aimg, alpha, sz);
1600 else if( alpha < 0 ) ap = yp;
1601 fd->display_subtitle(channel->video_stream, 1, 1,
1602 yp,up,vp,ap, x,y,ww,hh, 0, secs*1000);
1603 dvb_input->put_src();
1609 if( !channel ) return;
1610 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1611 DeviceDVBInput *dvb_input = dvb_device();
1612 if( !dvb_input ) return 1;
1613 zmpeg3_t *fd = dvb_input->get_src();
1615 fd->delete_subtitle(channel->video_stream, 1, 1);
1616 dvb_input->put_src();
1622 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1624 record_monitor->display_vframe(in, x, y, alpha, secs, scale);
1630 record_monitor->undisplay_vframe();
1636 display_channel_info()
1639 if( !channel ) return 1;
1640 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1641 DeviceDVBInput *dvb_input = dvb_device();
1642 if( !dvb_input ) return 1;
1643 int elem = channel->element;
1644 time_t tt; time(&tt);
1645 struct tm ttm; localtime_r(&tt,&ttm);
1647 char text[BCTEXTLEN];
1648 zmpeg3_t *fd = dvb_input->get_src();
1650 for( int ord=0, i=0; ord<0x80; ) {
1652 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1653 if( len < 0 ) { ++ord; i = 0; continue; }
1654 struct tm stm = ttm, etm = ttm;
1655 char wday[4], *bp = cp; cp += len;
1656 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1657 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1658 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1659 while( bp<cp && *bp++!='\n' );
1660 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1661 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1662 stm.tm_year -= 1900; stm.tm_mon -= 1;
1663 etm.tm_year = stm.tm_year;
1664 etm.tm_mon = stm.tm_mon;
1665 etm.tm_mday = stm.tm_mday;
1666 time_t st = mktime(&stm), et = mktime(&etm);
1667 if( et < st ) et += 24*3600;
1668 if( tt < st || tt >= et ) continue;
1669 int major=0, minor=0;
1670 fd->dvb.get_channel(elem, major, minor);
1671 char chan[64]; sprintf(chan, "%3d.%1d", major, minor);
1672 for( i=0; i<5 && chan[i]!=0; ++i ) *bp++ = chan[i];
1673 while( bp<cp && *bp++!='\n' );
1675 for( char *lp=bp; bp<cp; ++bp ) {
1676 if( *bp == '\n' || ((bp-lp)>=60 && *bp==' ') ) {
1677 if( ++n >= 10 ) break;
1682 while( bp > text && *--bp == '\n' ) *bp = 0;
1686 dvb_input->put_src();
1688 display_video_text(20, 20, text,
1689 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1697 display_channel_schedule()
1700 if( !channel ) return 1;
1701 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1702 DeviceDVBInput *dvb_input = dvb_device();
1703 if( !dvb_input ) return 1;
1704 int elem = channel->element;
1705 time_t tt; time(&tt);
1706 struct tm ttm; localtime_r(&tt,&ttm);
1707 char text[BCTEXTLEN];
1708 zmpeg3_t *fd = dvb_input->get_src();
1710 RecordSchedule channel_schedule;
1711 for( int ord=0, i=0; ord<0x80; ) {
1713 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1714 if( len < 0 ) { ++ord; i = 0; continue; }
1715 struct tm stm = ttm, etm = ttm;
1716 char wday[4], *bp = cp; cp += len;
1717 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1718 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1719 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1720 while( bp<cp && *bp++!='\n' );
1721 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1722 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1723 stm.tm_year -= 1900; stm.tm_mon -= 1;
1724 etm.tm_year = stm.tm_year;
1725 etm.tm_mon = stm.tm_mon;
1726 etm.tm_mday = stm.tm_mday;
1727 time_t st = mktime(&stm), et = mktime(&etm);
1728 if( et < st ) et += 24*3600;
1729 if( tt >= et ) continue;
1730 if( bp > text )*--bp = 0;
1731 channel_schedule.append(new RecordScheduleItem(st, text));
1733 dvb_input->put_src();
1735 channel_schedule.sort_times();
1736 char *cp = text, *ep = cp+sizeof(text)-1;
1737 for( int i=0, n=0; i<channel_schedule.size(); ++i ) {
1738 RecordScheduleItem *item = channel_schedule.get(i);
1739 for( char *bp=item->title; cp<ep && *bp!=0; ++bp ) *cp++ = *bp;
1740 if( cp < ep ) *cp++ = '\n';
1741 if( ++n >= 12 ) break;
1744 while( cp > text && *--cp == '\n' ) *cp = 0;
1746 display_video_text(20, 20, text,
1747 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1754 void Record::clear_keybfr()
1760 void Record::add_key(int ch)
1763 while( n<(int)sizeof(keybfr)-2 && keybfr[n] ) ++n;
1764 keybfr[n++] = ch; keybfr[n] = 0;
1765 display_video_text(20, 20, keybfr,
1766 BIGFONT, WHITE, BLACK, 0, 3., 2.);
1769 int Record::record_process_key(RemoteControl *remote_control, int key)
1775 if( last_key != KPENTER ) break;
1777 set_channel_name(keybfr);
1781 if( last_key == '0' && ch == '0' ) {
1785 case '1': case '2': case '3':
1786 case '4': case '5': case '6':
1787 case '7': case '8': case '9':
1791 //case UP: case DOWN:
1792 //case LEFT: case RIGHT:
1793 //case KPPLAY: case KPFWRD:
1795 case 'a': // toggle mute audio
1796 if( !monitor_audio ) { set_mute_gain(1); set_play_gain(1); }
1797 set_audio_monitoring(monitor_audio ? 0 : 1);
1799 case KPBACK: case 'm': // toggle metering audio
1800 set_audio_metering(metering_audio ? 0 : 1);
1802 case 'd': case KPSLASH:
1803 display_channel_info();
1805 case 'e': case KPSTAR:
1806 display_channel_schedule();
1808 case KPCHUP: case KPPLUS:
1811 case KPCHDN: case KPMINUS:
1815 set_play_gain(play_gain * 1.25);
1818 set_play_gain(play_gain * 0.75);
1822 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
1823 int on = canvas->get_fullscreen() ? 0 : 1;
1824 canvas->Canvas::set_fullscreen(on, 0);
1826 #ifdef HAVE_COMMERCIAL
1827 case KPRECD: case 'c': // start capture, mark endpoint
1829 start_commercial_capture();
1831 set_play_gain(0.075);
1834 mark_commercial_capture(DEL_MARK);
1835 blink_status->update();
1837 display_cut_icon(10,20);
1839 case KPSTOP: case 's': // end capture, start cutting
1840 remote_control->set_color(YELLOW);
1841 stop_commercial_capture(1);
1843 case KPAUSE: case 'x': // ignore current commercial
1844 mark_commercial_capture(DEL_SKIP);
1846 case KPPLAY: case 'z': // ignore previous endpoint
1847 mark_commercial_capture(DEL_OOPS);
1858 int Record::wintv_process_code(int code)
1868 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
1869 int on = canvas->get_fullscreen() ? 0 : 1;
1870 canvas->Canvas::set_fullscreen(on, 0);
1872 case WTV_BACK: // toggle metering audio
1873 set_audio_metering(metering_audio ? 0 : 1);
1876 set_play_gain(play_gain * 1.125);
1879 set_play_gain(play_gain * 0.875);
1888 WinTVRecordHandler *wintv_remote = (WinTVRecordHandler *)
1889 mwindow->gui->remote_control->handler;
1890 WinTV *wintv = !wintv_remote ? 0 : wintv_remote->wintv;
1891 if( !wintv || wintv->last_code == WTV_0 ) {
1895 case WTV_1: case WTV_2: case WTV_3: case WTV_4:
1896 case WTV_5: case WTV_6: case WTV_7: case WTV_8:
1898 int ch = code - WTV_0 + '0';
1901 case WTV_TEXT: // add decimal point
1904 case WTV_CC: // change channel
1905 set_channel_name(keybfr);
1909 display_channel_schedule();
1911 case WTV_START: break;
1912 case WTV_REV: break;
1913 case WTV_STOP: break;
1914 case WTV_PLAY: break;
1915 case WTV_FWD: break;
1916 case WTV_END: break;
1917 case WTV_MUTE: // toggle mute audio
1918 if( !monitor_audio ) {
1920 set_play_gain(play_gain);
1922 set_audio_monitoring(monitor_audio ? 0 : 1);
1925 display_channel_info();
1928 printf("wintv record: unknown code: %04x\n", code);
1935 int Record::x10tv_process_code(int code)
1939 case X10_A: // toggle metering audio
1940 set_audio_metering(metering_audio ? 0 : 1);
1943 case X10_POWER: break;
1945 case X10_DVD: break;
1946 case X10_WWW: break;
1947 case X10_BOOK: break;
1948 case X10_EDIT: break;
1950 set_play_gain(play_gain * 1.125);
1953 set_play_gain(play_gain * 0.875);
1955 case X10_MUTE: // toggle mute audio
1956 if( !monitor_audio ) {
1958 set_play_gain(play_gain);
1960 set_audio_monitoring(monitor_audio ? 0 : 1);
1969 X10TVRecordHandler *x10tv_remote = (X10TVRecordHandler *)
1970 mwindow->gui->remote_control->handler;
1971 X10TV *x10tv = !x10tv_remote ? 0 : x10tv_remote->x10tv;
1972 if( x10tv->last_code == X10_0 ) {
1976 case X10_1: case X10_2: case X10_3: case X10_4:
1977 case X10_5: case X10_6: case X10_7: case X10_8:
1979 int ch = code - X10_0 + '0';
1982 case X10_MENU: // add decimal point
1985 case X10_SETUP: // change channel
1986 set_channel_name(keybfr);
1990 display_channel_schedule();
1994 display_channel_info();
1996 case X10_PROPS: break;
2001 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
2002 int on = canvas->get_fullscreen() ? 0 : 1;
2003 canvas->Canvas::set_fullscreen(on, 0);
2008 case X10_REW: break;
2009 case X10_PLAY: break;
2010 case X10_FWD: break;
2011 case X10_REC: break;
2012 case X10_STOP: break;
2013 case X10_PAUSE: break;
2016 printf("x10tv record: unknown code: %04x\n", code);
2023 #ifdef HAVE_COMMERCIAL
2024 int Record::start_commercial_capture()
2026 if( deletions != 0 ) return 1;
2027 Channel *channel = get_current_channel();
2028 if( !channel ) return 1;
2029 int track = channel->video_stream;
2030 int pid = vdevice->get_video_pid(track);
2031 if( pid < 0 ) return 1;
2032 time_t st; time(&st);
2033 struct tm stm; localtime_r(&st, &stm);
2034 char file_path[BCTEXTLEN];
2035 sprintf(file_path,"/tmp/del%04d%02d%02d-%02d%02d%02d.ts",
2036 stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
2037 stm.tm_hour, stm.tm_min, stm.tm_sec);
2038 commercial_fd = open(file_path,O_RDWR+O_CREAT,0666);
2039 if( commercial_fd < 0 ) return 1;
2040 if( vdevice->start_record(commercial_fd, 0x800000) ) {
2041 close(commercial_fd);
2045 commercial_start_time = st;
2046 printf("del to %s\n", file_path);
2047 deletions = new Deletions(pid, file_path);
2048 mark_commercial_capture(DEL_START);
2049 blink_status->start();
2053 int Record::mark_commercial_capture(int action)
2055 if( deletions == 0 ) return 1;
2056 double time = vdevice->get_timestamp();
2057 printf("dele %f\n", time);
2058 deletions->append(new Dele(time, action));
2063 void Record::remote_fill_color(int color)
2065 mwindow->gui->remote_control->fill_color(color);
2068 void Record::set_status_color(int color)
2070 status_color = color;
2071 remote_fill_color(status_color);
2074 void Record::set_mute_gain(double gain)
2076 gain = (mute_gain = gain) * play_gain;
2077 if( adevice ) adevice->set_play_gain(gain);
2080 void Record::set_play_gain(double gain)
2082 gain = mute_gain * (play_gain = gain);
2083 if( adevice ) adevice->set_play_gain(gain);
2086 #ifdef HAVE_COMMERCIAL
2087 int Record::stop_commercial_capture(int run_job)
2089 if( deletions == 0 ) return 1;
2090 if( run_job ) blink_status->stop();
2093 vdevice->stop_record();
2094 commercial_start_time = -1;
2095 if( commercial_fd >= 0 ) {
2096 close(commercial_fd);
2101 char del_filename[BCTEXTLEN];
2102 strcpy(del_filename, deletions->file_path());
2103 strcpy(strrchr(del_filename, '.'),".del");
2104 if( !deletions->write_dels(del_filename) ) {
2105 int pid = spawn("cutads %s",del_filename);
2107 cut_pids.append(pid);
2108 cutads_status->start_waiting();
2114 remove_file(deletions->filepath);
2116 delete deletions; deletions = 0;
2121 spawn(const char *fmt, ...)
2123 const char *exec_path = File::get_cinlib_path();
2124 char cmd[BCTEXTLEN], *cp = cmd, *ep = cp+sizeof(cmd)-1;
2125 va_list ap; va_start(ap, fmt);
2126 cp += snprintf(cp, ep-cp, "exec %s/", exec_path);
2127 cp += vsnprintf(cp, ep-cp, fmt, ap); va_end(ap);
2129 pid_t pid = vfork();
2130 if( pid < 0 ) return -1;
2131 if( pid > 0 ) return pid;
2132 char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
2133 execvp(argv[0], &argv[0]);
2140 for( int i=0; i<cut_pids.size(); ) {
2141 int status, pid = cut_pids.get(i);
2142 if( waitpid(pid, &status, WNOHANG) ) {
2143 cut_pids.remove(pid);
2148 return cut_pids.size();
2152 RecordCutAdsStatus::
2153 RecordCutAdsStatus(Record *record)
2156 this->record = record;
2157 wait_lock = new Condition(0,"RecordCutAdsStatus::wait_lock",0);
2162 RecordCutAdsStatus::
2163 ~RecordCutAdsStatus()
2167 wait_lock->unlock();
2174 void RecordCutAdsStatus::
2177 wait_lock->unlock();
2180 void RecordCutAdsStatus::
2183 int status, pgrp = getpgrp();
2185 wait_lock->lock("RecordCutAdsStatus::run");
2187 if( !record->commercial_jobs() ) continue;
2188 record->set_status_color(YELLOW);
2191 waitpid(-pgrp, &status, 0);
2193 if( !record->commercial_jobs() ) break;
2195 record->set_status_color(GREEN);
2199 void RecordBlinkStatus::
2200 remote_color(int color)
2202 record->remote_fill_color(color);
2205 void RecordBlinkStatus::
2211 void RecordBlinkStatus::
2219 void RecordBlinkStatus::
2230 RecordBlinkStatus(Record *record)
2233 this->record = record;
2237 ~RecordBlinkStatus()
2242 void RecordBlinkStatus::
2247 remote_color(color);
2251 color ^= YELLOW ^ BLUE;
2252 if( timer.get_difference() > 10*60*1000 ) { // 10 minutes
2253 record->stop_commercial_capture(0);
2257 remote_color(record->status_color);