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"
53 #include "libzmpeg3.h"
57 #include "mwindowgui.h"
60 #include "playbackengine.h"
61 #include "preferences.h"
63 #include "recordaudio.h"
64 #include "recordconfig.h"
65 #include "recordgui.h"
66 #include "recordlabel.h"
67 #include "recordmonitor.h"
68 #include "recordprefs.inc"
69 #include "recordthread.h"
70 #include "recordvideo.h"
71 #include "removefile.h"
72 #include "mainsession.h"
73 #include "sighandler.h"
74 #include "testobject.h"
78 #include "videoconfig.h"
79 #include "videodevice.h"
84 #include <sys/types.h>
88 RecordMenuItem::RecordMenuItem(MWindow *mwindow)
89 : BC_MenuItem(_("Record..."), "r", 'r')
91 this->mwindow = mwindow;
92 record = new Record(mwindow, this);
95 RecordMenuItem::~RecordMenuItem()
100 int RecordMenuItem::handle_event()
107 Record::Record(MWindow *mwindow, RecordMenuItem *menu_item)
109 record_batches(mwindow)
111 this->mwindow = mwindow;
112 this->menu_item = menu_item;
113 mwindow->gui->record = this;
117 picture = new PictureConfig();
118 channeldb = new ChannelDB;
119 master_channel = new Channel;
120 record_channel = new RecordChannel(this);
125 pause_lock = new Mutex("Record::pause_lock");
126 init_lock = new Condition(0,"Record::init_lock");
132 session_sample_offset = 0;
133 device_sample_offset = 0;
138 drop_overrun_frames = 0;
139 fill_underrun_frames = 0;
141 commercial_check = skimming_active = 0;
142 commercial_start_time = -1;
150 current_frame = written_frames = total_frames = 0;
151 current_sample = written_samples = total_samples = 0;
152 audio_time = video_time = -1.;
153 play_gain = mute_gain = 1.;
155 input_threads_pausing = 0;
156 window_lock = new Mutex("Record::window_lock");
157 timer_lock = new Mutex("Record::timer_lock");
158 file_lock = new Mutex("Record::file_lock");
159 adevice_lock = new Mutex("Record::adevice_lock");
160 vdevice_lock = new Mutex("Record::vdevice_lock");
161 batch_lock = new Mutex("Record::batch_lock");
162 #ifdef HAVE_COMMERCIAL
163 skim_thread = new SkimDbThread();
164 cutads_status = new RecordCutAdsStatus(this);
165 blink_status = new RecordBlinkStatus(this);
167 deinterlace = RECORD_LACE_ODD;
172 mwindow->gui->record = 0;
174 #ifdef HAVE_COMMERCIAL
176 delete cutads_status;
183 delete record_channel;
184 delete master_channel;
197 int Record::load_defaults()
200 char string[BCTEXTLEN];
201 BC_Hash *defaults = mwindow->defaults;
202 EDLSession *session = SESSION;
203 default_asset->copy_from(session->recording_format, 0);
204 default_asset->channels = session->aconfig_in->channels;
205 default_asset->sample_rate = session->aconfig_in->in_samplerate;
206 default_asset->frame_rate = session->vconfig_in->in_framerate;
207 default_asset->width = session->vconfig_in->w;
208 default_asset->height = session->vconfig_in->h;
209 default_asset->layers = 1;
210 // Fix encoding parameters depending on driver.
211 // These are locked by a specific driver.
212 const char *vcodec = 0;
213 switch( session->vconfig_in->driver ) {
215 case VIDEO4LINUX2MPEG:
217 case VIDEO4LINUX2JPEG:
218 vcodec = CODEC_TAG_MJPEG;
221 case CAPTURE_FIREWIRE:
222 case CAPTURE_IEC61883:
223 vcodec = CODEC_TAG_DVSD;
228 strcpy(default_asset->vcodec, vcodec);
230 record_batches.load_defaults(channeldb, this);
232 int cur_chan_no = defaults->get("RECORD_CURRENT_CHANNEL", 0);
233 current_channel = channeldb->get(cur_chan_no);
234 load_mode = defaults->get("RECORD_LOADMODE", LOADMODE_PASTE);
235 monitor_audio = defaults->get("RECORD_MONITOR_AUDIO", 1);
236 metering_audio = defaults->get("RECORD_METERING_AUDIO", 1);
237 monitor_video = defaults->get("RECORD_MONITOR_VIDEO", 1);
238 video_window_open = defaults->get("RECORD_MONITOR_OPEN", 1);
239 video_x = defaults->get("RECORD_VIDEO_X", 0);
240 video_y = defaults->get("RECORD_VIDEO_Y", 0);
241 video_zoom = defaults->get("RECORD_VIDEO_Z", (float)1);
242 picture->load_defaults();
243 reverse_interlace = defaults->get("REVERSE_INTERLACE", 0);
244 deinterlace = defaults->get("DEINTERLACE", RECORD_LACE_ODD);
245 do_cursor = defaults->get("RECORD_CURSOR", 0);
246 do_big_cursor = defaults->get("RECORD_BIG_CURSOR", 0);
247 for( int i=0; i<MAXCHANNELS; ++i ) {
248 sprintf(string, "RECORD_DCOFFSET_%d", i);
249 dc_offset[i] = defaults->get(string, 0);
251 drop_overrun_frames = defaults->get("DROP_OVERRUN_FRAMES", 0);
252 fill_underrun_frames = defaults->get("FILL_UNDERRUN_FRAMES", 0);
253 commercial_check = defaults->get("COMMERCIAL_CHECK", 0);
257 int Record::save_defaults()
259 char string[BCTEXTLEN];
260 BC_Hash *defaults = mwindow->defaults;
261 set_editing_batch(0);
262 // Save default asset path but not the format because that's
263 // overridden by the driver.
264 // The format is saved in preferences.
265 if( record_batches.total() )
266 strcpy(default_asset->path, record_batches[0]->asset->path);
267 default_asset->save_defaults(defaults, "RECORD_", 0, 0, 0, 0, 0);
269 record_batches.save_defaults(channeldb);
271 int cur_chan_no = channeldb->number_of(current_channel);
272 defaults->update("RECORD_CURRENT_CHANNEL", cur_chan_no);
273 defaults->update("RECORD_LOADMODE", load_mode);
274 defaults->update("RECORD_MONITOR_AUDIO", monitor_audio);
275 defaults->update("RECORD_METERING_AUDIO", metering_audio);
276 defaults->update("RECORD_MONITOR_VIDEO", monitor_video);
277 defaults->update("RECORD_MONITOR_OPEN", video_window_open);
278 defaults->update("RECORD_VIDEO_X", video_x);
279 defaults->update("RECORD_VIDEO_Y", video_y);
280 defaults->update("RECORD_VIDEO_Z", video_zoom);
281 picture->save_defaults();
282 defaults->update("REVERSE_INTERLACE", reverse_interlace);
283 defaults->update("DEINTERLACE", deinterlace);
284 defaults->update("RECORD_CURSOR", do_cursor);
285 defaults->update("RECORD_BIG_CURSOR", do_big_cursor);
286 for( int i=0; i<MAXCHANNELS; ++i ) {
287 sprintf(string, "RECORD_DCOFFSET_%d", i);
288 defaults->update(string, dc_offset[i]);
290 defaults->update("DROP_OVERRUN_FRAMES", drop_overrun_frames);
291 defaults->update("FILL_UNDERRUN_FRAMES", fill_underrun_frames);
292 defaults->update("COMMERCIAL_CHECK", commercial_check);
298 void Record::configure_batches()
300 // printf("Record::configure_batches %d\n",__LINE__);
301 // default_assset->dump();
302 strcpy(record_batches[0]->asset->path, default_asset->path);
303 int total_batches = record_batches.total();
304 for( int i=0; i<total_batches; ++i ) {
305 Batch *batch = record_batches[i];
306 batch->asset->copy_format(default_asset);
314 // Default asset forms the first path in the batch capture
315 // and the file format for all operations.
316 default_asset = new Asset;
318 // Determine information about the device.
319 AudioInConfig *aconfig_in = SESSION->aconfig_in;
320 VideoInConfig *vconfig_in = SESSION->vconfig_in;
321 int driver = vconfig_in->driver;
322 VideoDevice::load_channeldb(channeldb, vconfig_in);
323 fixed_compression = VideoDevice::is_compressed(driver, 0, 1);
325 // Apply a major kludge
326 if( fixed_compression ) {
328 device.fix_asset(default_asset, driver);
330 default_asset->channels = aconfig_in->channels;
331 VideoDevice::save_channeldb(channeldb, vconfig_in);
333 mwindow->save_defaults();
335 set_current_batch(0);
336 set_editing_batch(0);
340 edl->create_objects();
341 edl->session->output_w = default_asset->width;
342 edl->session->output_h = default_asset->height;
343 edl->session->aspect_w = SESSION->aspect_w;
344 edl->session->aspect_h = SESSION->aspect_h;
346 window_lock->lock("Record::run 3");
347 record_gui = new RecordGUI(mwindow, this);
348 record_gui->create_objects();
350 record_monitor = new RecordMonitor(mwindow, this);
351 record_monitor->create_objects();
352 record_gui->update_batch_sources();
354 record_gui->show_window();
357 if( mwindow->gui->remote_control->deactivate() &&
358 mwindow->gui->record_remote_handler )
359 mwindow->gui->record_remote_handler->activate();
361 if( video_window_open ) {
362 record_monitor->window->show_window();
363 record_monitor->window->raise_window();
364 record_monitor->window->flush();
367 window_lock->unlock();
369 start_input_threads();
373 result = record_gui->run_window();
374 // record gui operates here until window is closed
376 if( record_gui->get_window_lock() ) {
377 record_gui->lock_window();
378 record_gui->unlock_window();
381 // Need to stop everything this time
383 int video_stream = -1;
384 #ifdef HAVE_COMMERCIAL
385 stop_commercial_capture(0);
388 if( default_asset->format == FILE_MPEG ) {
389 Channel *channel = get_current_channel();
391 video_stream = channel->video_stream;
395 edl->Garbage::remove_user();
397 if( mwindow->gui->remote_control->deactivate() &&
398 mwindow->gui->cwindow_remote_handler )
399 mwindow->gui->cwindow_remote_handler->activate();
401 // Save everything again
405 if( !result && load_mode != LOADMODE_NOTHING ) {
406 mwindow->gui->lock_window("Record::run");
407 ArrayList<EDL*> new_edls;
409 int total_batches = record_batches.total();
410 for( int i=0; i<total_batches; ++i ) {
411 Batch *batch = record_batches[i];
412 Asset *asset = batch->asset;
413 if( batch->recorded ) {
414 EDL *new_edl = new EDL;
415 mwindow->remove_from_caches(asset);
416 new_edl->create_objects();
417 new_edl->copy_session(mwindow->edl);
418 mwindow->asset_to_edl(new_edl, asset, batch->labels);
419 new_edls.append(new_edl);
424 mwindow->undo->update_undo_before();
425 // For pasting, clear the active region
426 if(load_mode == LOADMODE_PASTE)
428 int loadmode = load_mode == LOADMODE_RESOURCESONLY ?
429 LOADMODE_ASSETSONLY : load_mode;
430 mwindow->paste_edls(&new_edls, loadmode, 0, -1,
431 SESSION->labels_follow_edits,
432 SESSION->plugins_follow_edits,
433 SESSION->autos_follow_edits,
435 for( int i=0; i<new_edls.total; ++i )
436 new_edls.get(i)->Garbage::remove_user();
437 new_edls.remove_all();
438 if( video_stream >= 0 ) {
439 mwindow->select_asset(video_stream, -1);
440 mwindow->fit_selection();
442 mwindow->save_backup();
443 mwindow->undo->update_undo_after(_("record"), LOAD_ALL);
444 mwindow->restart_brender();
445 mwindow->update_plugin_guis();
446 mwindow->gui->update(1, FORCE_REDRAW, 1, 1, 1, 1, 0);
447 mwindow->sync_parameters(CHANGE_ALL);
449 mwindow->gui->unlock_window();
451 AWindowGUI *agui = mwindow->awindow->gui;
452 agui->async_update_assets();
456 record_batches.clear();
457 default_asset->Garbage::remove_user();
460 void Record::stop(int wait)
464 record_gui->set_done(1);
467 window_lock->lock("Record::stop");
468 delete record_thread; record_thread = 0;
469 delete record_monitor; record_monitor = 0;
470 delete record_gui; record_gui = 0;
471 window_lock->unlock();
474 void Record::activate_batch(int number)
476 if( number != current_batch() ) {
478 set_current_batch(number);
479 record_gui->update_batches();
480 record_gui->update_position(current_display_position());
481 record_gui->update_batch_tools();
486 void Record::delete_index_file(Asset *asset)
488 IndexFile::delete_index_files(mwindow->preferences, asset);
491 void Record::delete_batch()
493 // Abort if one batch left
494 int edit_batch = editing_batch();
495 int total_batches = record_batches.total();
496 if( total_batches > 1 && edit_batch < total_batches ) {
497 int cur_batch = current_batch();
498 Batch *batch = record_batches[edit_batch];
499 record_batches.remove(batch); delete batch;
500 if( cur_batch == edit_batch ) stop_writing();
501 record_gui->update_batches();
502 record_gui->update_batch_tools();
506 void Record::change_editing_batch(int number)
508 set_editing_batch(number);
509 record_gui->update_batch_tools();
512 Batch* Record::new_batch()
514 Batch *batch = new Batch(mwindow, this);
515 //printf("Record::new_batch 1\n");
516 batch->create_objects();
517 record_batches.append(batch);
518 batch->asset->copy_format(default_asset);
520 //printf("Record::new_batch 1\n");
521 batch->create_default_path();
522 Batch *edit_batch = get_editing_batch();
524 batch->copy_from(edit_batch);
525 int total_batches = record_batches.total();
526 set_editing_batch(total_batches - 1);
527 //printf("Record::new_batch 1\n");
528 // Update GUI if created yet
530 record_gui->update_batch_tools();
531 //printf("Record::new_batch 2\n");
535 int Record::current_batch()
537 return record_batches.current_item;
540 int Record::set_current_batch(int i)
542 return record_batches.current_item = i;
545 int Record::editing_batch()
547 return record_batches.editing_item;
550 int Record::set_editing_batch(int i)
552 return record_batches.editing_item = i;
555 int Record::delete_output_file()
557 Batch *batch = get_current_batch();
559 if( !file && batch && !access(batch->asset->path, F_OK) ) {
560 batch->set_notice(_("Deleting"));
561 record_gui->update_batches();
562 Asset *asset = batch->asset;
563 remove_file(asset->path);
564 mwindow->remove_from_caches(asset);
565 delete_index_file(asset);
566 batch->clear_notice();
567 record_gui->update_batches();
572 int Record::open_output_file()
576 Batch *batch = get_current_batch();
577 if( !file && batch ) {
578 delete_output_file();
579 Asset *asset = batch->asset;
580 asset->frame_rate = default_asset->frame_rate;
581 asset->sample_rate = default_asset->sample_rate;
582 asset->width = default_asset->width;
583 asset->height = default_asset->height;
585 if( default_asset->format == FILE_MPEG ) {
586 asset->layers = vdevice ? vdevice->total_video_streams() : 0;
587 asset->channels = adevice ? adevice->total_audio_channels() : 0;
591 result = file->open_file(mwindow->preferences, asset, 0, wr);
593 mwindow->sighandler->push_file(file);
595 file->set_processors(mwindow->preferences->real_processors);
596 record_gui->update_batches();
610 window_lock->lock("Record::start");
611 record_gui->lock_window("Record::start");
612 record_gui->raise_window();
613 record_gui->unlock_window();
614 window_lock->unlock();
622 void Record::start_over()
625 Batch *batch = get_current_batch();
626 if( batch ) batch->start_over();
627 record_gui->update_batches();
630 void Record::stop_operation()
633 stop_input_threads();
636 int Record::cron_active()
638 return !record_thread ? 0 : record_thread->cron_active;
641 void Record::close_output_file()
645 mwindow->sighandler->pull_file(file);
651 record_gui->update_batches();
654 void Record::toggle_label()
656 Batch *batch = get_current_batch();
657 if( batch ) batch->toggle_label(current_display_position());
658 record_gui->update_labels(current_display_position());
661 void Record::clear_labels()
663 Batch *batch = get_current_batch();
664 if( batch ) batch->clear_labels();
665 record_gui->update_labels(0);
668 int Record::get_fragment_samples()
670 const int min_samples = 1024, max_samples = 32768;
671 int samples, low_bit;
672 samples = default_asset->sample_rate / SESSION->record_speed;
673 if( samples < min_samples ) samples = min_samples;
674 else if( samples > max_samples ) samples = max_samples;
675 // loop until only one bit left standing
676 while( (low_bit=(samples & ~(samples-1))) != samples )
681 int Record::get_buffer_samples()
683 int fragment_samples = get_fragment_samples();
684 if( !fragment_samples ) return 0;
685 int fragments = (SESSION->record_write_length+fragment_samples-1) / fragment_samples;
686 if( fragments < 1 ) fragments = 1;
687 return fragments * fragment_samples;
690 Batch* Record::get_current_batch()
692 return record_batches.get_current_batch();
695 Batch* Record::get_editing_batch()
697 return record_batches.get_editing_batch();
700 int Record::get_next_batch(int incr)
702 int i = current_batch();
705 int total_batches = record_batches.total();
706 while( i < total_batches ) {
707 if( record_batches[i]->enabled ) return i;
714 const char* Record::current_mode()
716 Batch *batch = get_current_batch();
717 return batch ? Batch::mode_to_text(batch->record_mode) : "";
720 double Record::current_display_position()
722 //printf("Record::current_display_position "%jd %jd\n", total_samples, total_frames);
724 Asset *asset = default_asset;
726 if( asset->video_data && record_video )
727 result = (double) written_frames / asset->frame_rate;
728 else if( asset->audio_data && record_audio )
729 result = (double) written_samples / asset->sample_rate;
732 if( asset->video_data && record_video )
733 result = (double) total_frames / asset->frame_rate;
734 else if( asset->audio_data && record_audio )
735 result = (double) total_samples / asset->sample_rate;
737 result = (double) total_time.get_difference() / 1000.;
742 const char* Record::current_source()
744 Batch *batch = get_current_batch();
745 return batch ? batch->get_source_text() : _("Unknown");
748 Asset* Record::current_asset()
750 Batch *batch = get_current_batch();
751 return batch ? batch->asset : 0;
754 Channel *Record::get_current_channel()
756 return current_channel;
759 Channel *Record::get_editing_channel()
761 Batch *batch = get_editing_batch();
762 return batch ? batch->channel : 0;
765 ArrayList<Channel*>* Record::get_video_inputs()
767 return default_asset->video_data && vdevice ? vdevice->get_inputs() : 0;
771 int64_t Record::timer_position()
773 timer_lock->lock("RecordAudio::timer_positioin");
774 int samplerate = default_asset->sample_rate;
775 int64_t result = timer.get_scaled_difference(samplerate);
776 result += session_sample_offset;
777 timer_lock->unlock();
781 void Record::reset_position(int64_t position)
783 timer_lock->lock("RecordAudio::reset_position");
784 session_sample_offset = position;
785 device_sample_offset = adevice ? adevice->current_position() : 0;
787 timer_lock->unlock();
790 void Record::update_position()
792 int64_t position = sync_position();
793 reset_position(position);
794 current_frame = current_sample = 0;
795 audio_time = video_time = -1.;
798 int64_t Record::adevice_position()
800 timer_lock->lock("RecordAudio::adevice_position");
801 int64_t result = adevice->current_position();
802 result += session_sample_offset - device_sample_offset;
803 timer_lock->unlock();
807 int64_t Record::sync_position()
809 int64_t sync_position = -1;
810 double sync_time = -1.;
811 double next_audio_time = -1.;
812 double next_video_time = -1.;
814 if( current_frame == 0 && current_sample == 0 ) {
815 audio_time = video_time = -1.;
818 switch( SESSION->record_positioning ) {
819 case RECORD_POS_TIMESTAMPS:
820 if( default_asset->video_data && record_video )
821 next_video_time = vdevice->get_timestamp();
822 if( default_asset->audio_data && record_audio ) {
824 !adevice->is_monitoring() || writing_file > 0 ?
825 adevice->get_itimestamp() :
826 adevice->get_otimestamp();
828 if( next_audio_time >= 0. )
829 sync_time = next_audio_time;
830 else if( next_video_time > 0. )
831 sync_time = next_video_time;
832 if( sync_time >= 0. ) {
833 sync_position = sync_time * default_asset->sample_rate;
835 if( sync_position >= 0 ) break;
836 case RECORD_POS_DEVICE:
837 if( default_asset->audio_data && record_audio )
838 sync_position = adevice_position();
839 if( sync_position > 0 ) break;
840 case RECORD_POS_SOFTWARE:
841 sync_position = timer_position();
842 if( sync_position > 0 ) break;
843 case RECORD_POS_SAMPLE:
845 sync_position = current_sample;
849 if( next_video_time < 0. )
850 next_video_time = current_frame / default_asset->frame_rate;
851 if( next_video_time > video_time )
852 video_time = next_video_time;
853 if( next_audio_time < 0. )
854 next_audio_time = (double)sync_position / default_asset->sample_rate;
855 if( next_audio_time > audio_time )
856 audio_time = next_audio_time;
858 return sync_position;
862 void Record::adevice_drain()
864 if( adevice && record_audio ) {
865 adevice->stop_audio(0);
866 adevice->start_recording();
871 #define dbmsg if( debug ) printf
872 void Record::resync()
874 dropped = behind = 0;
875 int64_t audio_position = sync_position();
876 double audiotime = (double) audio_position / default_asset->sample_rate;
877 double diff = video_time - audiotime;
879 dbmsg("resync video %f audio %f/%f diff %f",
880 video_time, audiotime, audio_time, diff);
881 if( fabs(diff) > 5. ) {
882 dbmsg(" drain audio");
883 // jam job dvb file tesing, comment next line
884 record_channel->drain_audio();
886 else if( diff > 0. ) {
887 int64_t delay = (int64_t)(1000.0 * diff);
888 dbmsg(" delay %8jd", delay);
890 video_time = audio_time = -1.;
897 behind = (int)(-diff * default_asset->frame_rate);
898 dbmsg(" behind %d", behind);
899 if( behind > 1 && fill_underrun_frames ) {
900 dropped = behind > 3 ? 3 : behind-1;
901 dbmsg(" dropped %d", dropped);
905 int frames = dropped + 1;
906 current_frame += frames;
907 total_frames += frames;
908 record_gui->update_video(dropped, behind);
909 if( dropped > 0 && drop_overrun_frames )
910 if( vdevice ) vdevice->drop_frames(dropped);
914 void Record::close_audio_input()
916 adevice_lock->lock();
918 adevice->close_all();
922 adevice_lock->unlock();
925 void Record::close_video_input()
927 vdevice_lock->lock();
929 vdevice->close_all();
933 vdevice_lock->unlock();
936 void Record::close_input_devices()
942 void Record::stop_audio_thread()
945 record_audio->stop_recording();
953 void Record::stop_video_thread()
956 record_video->stop_recording();
965 void Record::stop_input_threads()
967 pause_lock->lock("Record::stop_input_threads");
972 pause_lock->unlock();
975 void Record::stop_playback()
978 record_monitor->stop_playback();
981 void Record::open_audio_input()
984 adevice_lock->lock();
986 if( default_asset->audio_data )
987 adevice = new AudioDevice(mwindow);
990 int sw_pos = SESSION->record_positioning == RECORD_POS_SOFTWARE;
991 adevice->set_software_positioning(sw_pos);
992 adevice->open_input(SESSION->aconfig_in, SESSION->vconfig_in,
993 default_asset->sample_rate, get_fragment_samples(),
994 default_asset->channels, SESSION->real_time_record);
995 adevice->start_recording();
996 adevice->open_monitor(SESSION->playback_config->aconfig,monitor_audio);
997 adevice->set_vdevice(vdevice);
998 if( vdevice ) vdevice->set_adevice(adevice);
1000 adevice_lock->unlock();
1003 void Record::open_video_input()
1005 close_video_input();
1006 vdevice_lock->lock();
1007 if( default_asset->video_data )
1008 vdevice = new VideoDevice(mwindow);
1011 vdevice->set_quality(default_asset->jpeg_quality);
1012 vdevice->open_input(SESSION->vconfig_in, video_x, video_y,
1013 video_zoom, default_asset->frame_rate);
1014 // Get configuration parameters from device probe
1015 color_model = vdevice->get_best_colormodel(default_asset);
1016 master_channel->copy_usage(vdevice->channel);
1017 picture->copy_usage(vdevice->picture);
1018 vdevice->set_field_order(reverse_interlace);
1019 vdevice->set_do_cursor(do_cursor, do_big_cursor);
1020 vdevice->set_adevice(adevice);
1021 if( adevice ) adevice->set_vdevice(vdevice);
1022 set_dev_channel(get_current_channel());
1024 vdevice_lock->unlock();
1027 void Record::start_audio_thread()
1030 if( !record_audio ) {
1031 total_samples = current_sample = 0; audio_time = -1.;
1032 record_audio = new RecordAudio(mwindow,this);
1033 record_audio->arm_recording();
1034 record_audio->start_recording();
1039 void Record::start_video_thread()
1042 if( !record_video ) {
1043 total_frames = current_frame = 0; video_time = -1.;
1044 record_video = new RecordVideo(mwindow,this);
1045 record_video->arm_recording();
1046 record_video->start_recording();
1051 void Record::start_input_threads()
1054 input_threads_pausing = 0;
1055 if( default_asset->audio_data )
1056 start_audio_thread();
1057 if( default_asset->video_data )
1058 start_video_thread();
1062 void Record::pause_input_threads()
1064 pause_lock->lock("Record::pause_input_threads");
1065 input_threads_pausing = 1;
1067 adevice_lock->lock();
1068 vdevice_lock->lock();
1070 record_audio->pause_recording();
1072 record_video->pause_recording();
1075 void Record::resume_input_threads()
1078 record_audio->resume_recording();
1080 record_video->resume_recording();
1081 vdevice_lock->unlock();
1082 adevice_lock->unlock();
1083 input_threads_pausing = 0;
1085 pause_lock->unlock();
1089 int Record::start_toc()
1091 if( !mwindow->edl->session->record_realtime_toc ) return 0;
1092 Batch *batch = get_current_batch();
1093 Asset *asset = batch->asset;
1094 char source_filename[BCTEXTLEN], toc_path[BCTEXTLEN];
1095 IndexFile::get_index_filename(source_filename,
1096 mwindow->preferences->index_directory,
1097 toc_path, asset->path,".toc");
1098 if( default_asset->video_data )
1099 return vdevice->start_toc(asset->path, toc_path);
1100 if( default_asset->audio_data )
1101 return adevice->start_toc(asset->path, toc_path);
1105 int Record::start_record(int fd)
1108 if( default_asset->video_data )
1109 return vdevice->start_record(fd);
1110 if( default_asset->audio_data )
1111 return adevice->start_record(fd);
1115 void Record::start_writing_file()
1117 if( !writing_file ) {
1119 written_samples = 0;
1120 do_video = File::renders_video(default_asset);
1121 do_audio = File::renders_audio(default_asset);
1122 if( single_frame ) do_audio = 0;
1123 if( !do_video && single_frame )
1125 else if( !open_output_file() )
1126 writing_file = default_asset->format == FILE_MPEG ? -1 : 1;
1127 if( do_audio && record_audio && writing_file > 0 ) {
1128 int buffer_samples = get_buffer_samples();
1129 record_audio->set_write_buffer_samples(buffer_samples);
1130 file->start_audio_thread(buffer_samples, FILE_RING_BUFFERS);
1132 if( do_video && record_video && writing_file > 0 ) {
1133 int disk_frames = SESSION->video_write_length;
1134 int cmodel = vdevice->get_best_colormodel(default_asset);
1135 int cpress = vdevice->is_compressed(1, 0);
1136 file->start_video_thread(disk_frames, cmodel, FILE_RING_BUFFERS, cpress);
1138 if( writing_file < 0 ) {
1139 int fd = file->record_fd();
1143 if( writing_file ) {
1144 record_gui->start_flash_batch();
1145 if( SESSION->record_sync_drives ) {
1146 drivesync = new DriveSync();
1154 int Record::stop_record()
1156 if( default_asset->video_data )
1157 return vdevice->stop_record();
1158 if( default_asset->audio_data )
1159 return adevice->stop_record();
1163 void Record::flush_buffer()
1166 record_audio->flush_buffer();
1168 record_video->flush_buffer();
1171 void Record::stop_writing_file()
1173 record_gui->stop_flash_batch();
1174 if( !writing_file ) return;
1175 if( writing_file > 0 )
1177 if( writing_file < 0 )
1179 close_output_file();
1181 Asset *asset = current_asset();
1182 asset->audio_length = written_samples;
1183 asset->video_length = written_frames;
1184 record_gui->flash_batch();
1186 drivesync->done = 1;
1192 void Record::stop_writing()
1194 if( writing_file ) {
1195 pause_input_threads();
1196 stop_writing_file();
1197 resume_input_threads();
1202 void Record::start_cron_thread()
1204 if( cron_active() < 0 ) {
1205 delete record_thread;
1208 if( !record_thread ) {
1209 record_thread = new RecordThread(mwindow,this);
1210 record_thread->start();
1211 record_gui->disable_batch_buttons();
1212 record_gui->update_cron_status(_("Running"));
1216 void Record::stop_cron_thread(const char *msg)
1218 if( record_thread ) {
1219 delete record_thread;
1221 record_gui->enable_batch_buttons();
1222 record_gui->update_cron_status(msg);
1226 void Record::set_power_off(int value)
1229 record_gui->power_off->update(value);
1232 void Record::set_video_picture()
1234 if( default_asset->video_data && vdevice )
1235 vdevice->set_picture(picture);
1238 void Record::set_do_cursor()
1240 vdevice->set_do_cursor(do_cursor, do_big_cursor);
1243 void Record::set_translation(int x, int y)
1247 if(default_asset->video_data && vdevice)
1248 vdevice->set_translation(video_x, video_y);
1251 int Record::set_channel(Channel *channel)
1253 if( !channel ) return 1;
1254 printf("set_channel %s\n",channel->title);
1255 if( record_channel->set(channel) ) return 1;
1256 RecordMonitorGUI *window = record_monitor->window;
1257 window->lock_window("Record::set_channel");
1258 window->channel_picker->channel_text->update(channel->title);
1259 window->unlock_window();
1263 int Record::set_channel_no(int chan_no)
1265 if( chan_no < 0 || chan_no >= channeldb->size() ) return 1;
1266 Channel *channel = channeldb->get(chan_no);
1267 return set_channel(channel);
1270 int Record::channel_down()
1272 Channel *channel = get_current_channel();
1273 if( !channel || !channeldb->size() ) return 1;
1274 int n = channeldb->number_of(channel);
1275 if( n < 0 ) return 1;
1276 if( --n < 0 ) n = channeldb->size() - 1;
1277 return set_channel_no(n);
1280 int Record::channel_up()
1282 Channel *channel = get_current_channel();
1283 if( !channel || !channeldb->size() ) return 1;
1284 int n = channeldb->number_of(channel);
1285 if( n < 0 ) return 1;
1286 if( ++n >= channeldb->size() ) n = 0;
1287 return set_channel_no(n);
1290 int Record::set_channel_name(const char *name)
1292 Channel *channel = 0;
1293 int ch = 0, nch = channeldb->size();
1295 channel = channeldb->get(ch);
1296 if( channel && !channel->cstrcmp(name) ) break;
1299 if( ch >= nch || !channel ) return 1;
1300 return set_channel(channel);
1303 void Record::set_batch_channel_no(int chan_no)
1305 Channel *channel = channeldb->get(chan_no);
1307 Batch *batch = get_editing_batch();
1308 if( batch ) batch->channel = channel;
1309 record_gui->batch_source->update(channel->title);
1313 void Record::set_dev_channel(Channel *channel)
1315 // should be tuner device, not vdevice
1316 if( channel && vdevice &&
1317 (!this->channel || *channel != *this->channel) ) {
1318 current_channel = channel;
1319 if( this->channel ) delete this->channel;
1320 this->channel = new Channel(channel);
1321 vdevice->set_channel(channel);
1322 int strk = !SESSION->decode_subtitles ? -1 : SESSION->subtitle_number;
1323 vdevice->set_captioning(strk);
1324 set_video_picture();
1325 printf("new channel %s, has_signal=%d\n",channel->title,vdevice->has_signal());
1328 total_time.update();
1332 /* widget holds xlock and set_channel pauses rendering, deadlock */
1333 /* use a background thread to update channel after widget sets it */
1334 RecordChannel::RecordChannel(Record *record)
1337 this->record = record;
1338 change_channel = new Condition(0,"RecordSetChannel::change_channel");
1339 channel_lock = new Condition(1,"Record::channel_lock",1);
1344 RecordChannel::~RecordChannel()
1347 change_channel->unlock();
1349 delete change_channel;
1350 delete channel_lock;
1353 int RecordChannel::set(Channel *channel)
1355 if( !channel || new_channel ) return 1;
1356 new_channel = channel;
1357 channel_lock->lock(); // block has_signal
1358 change_channel->unlock(); // resume channel changer thread
1362 void RecordChannel::drain_audio()
1364 if( !audio_drain ) {
1366 change_channel->unlock();
1370 void RecordChannel::run()
1374 change_channel->lock();
1376 if( !new_channel && !audio_drain ) continue;
1377 record->pause_input_threads();
1379 record->set_dev_channel(new_channel);
1380 record->record_gui->reset_video();
1381 record->record_gui->reset_audio();
1386 record->adevice_drain();
1388 record->update_position();
1389 record->resume_input_threads();
1392 channel_lock->unlock();
1397 int Record::has_signal()
1399 record_channel->channel_lock->lock("Record::has_signal");
1400 record_channel->channel_lock->unlock();
1401 vdevice_lock->lock();
1402 int result = vdevice ? vdevice->has_signal() : 0;
1403 vdevice_lock->unlock();
1407 int Record::create_channeldb(ArrayList<Channel*> *channeldb)
1409 return vdevice ? vdevice->create_channeldb(channeldb) : 1;
1413 void Record::set_audio_monitoring(int mode)
1416 monitor_audio = mode;
1418 record_audio->set_monitoring(mode);
1419 record_gui->lock_window("Record::set_audio_monitoring");
1420 if( record_gui->monitor_audio )
1421 record_gui->monitor_audio->update(mode);
1422 record_gui->unlock_window();
1425 void Record::set_audio_metering(int mode)
1427 metering_audio = mode;
1428 record_gui->lock_window("Record::set_audio_metering");
1429 if( record_gui->meter_audio )
1430 record_gui->meter_audio->update(mode);
1431 record_gui->unlock_window();
1432 RecordMonitorGUI *window = record_monitor->window;
1433 window->lock_window("Record::set_audio_metering 1");
1434 window->resize_event(window->get_w(),window->get_h());
1435 window->unlock_window();
1439 void Record::set_video_monitoring(int mode)
1441 monitor_video = mode;
1442 record_gui->lock_window("Record::set_video_monitoring");
1443 if( record_gui->monitor_video )
1444 record_gui->monitor_video->update(mode);
1445 record_gui->flush();
1446 record_gui->unlock_window();
1449 int Record::get_time_format()
1451 return SESSION->time_format;
1454 int Record::set_record_mode(int value)
1456 Batch *batch = get_editing_batch();
1457 batch->record_mode = value;
1458 record_gui->update_batches();
1462 int Record::check_batch_complete()
1466 if( writing_file && cron_active() > 0 ) {
1467 Batch *batch = get_current_batch();
1468 if( batch && batch->recorded > 0 &&
1469 batch->record_mode == RECORD_TIMED &&
1470 current_display_position() >= batch->record_duration ) {
1471 batch->recorded = -1;
1473 record_gui->update_batches();
1474 record_thread->batch_timed_lock->unlock();
1478 batch_lock->unlock();
1482 #ifdef HAVE_COMMERCIAL
1483 int Record::skimming(void *vp, int track)
1485 return ((Record*)vp)->skimming(track);
1488 int Record::skimming(int track)
1490 int64_t framenum; uint8_t *tdat; int mw, mh;
1491 if( !vdevice ) return -1;
1492 if( vdevice->get_thumbnail(track, framenum, tdat, mw, mh) ) return 1;
1493 int pid, width, height; double framerate;
1494 if( vdevice->get_video_info(track, pid, framerate, width, height, 0) ) return 1;
1495 if( !framerate ) return 1;
1496 return skim_thread->skim(pid,framenum,framerate, tdat,mw,mh,width,height);
1499 void Record::start_skimming()
1501 if( commercial_check && vdevice && !skimming_active ) {
1502 skimming_active = 1;
1503 skim_thread->start(mwindow->commercials);
1504 vdevice->set_skimming(0, 0, skimming, this);
1508 void Record::stop_skimming()
1510 if( skimming_active && vdevice ) {
1511 skimming_active = 0;
1512 vdevice->set_skimming(0, 0, 0, 0);
1513 skim_thread->stop();
1517 void Record::update_skimming(int v)
1519 if( (commercial_check=v) != 0 )
1526 int Record::skimming(void *vp, int track) { return 1; }
1527 int Record::skimming(int track) { return 1; }
1528 void Record::start_skimming() {}
1529 void Record::stop_skimming() {}
1530 void Record::update_skimming(int v) {}
1533 RecordKeyEvHandler::RecordKeyEvHandler(RemoteControl *remote_control)
1534 : RemoteHandler(remote_control->gui, GREEN)
1536 this->remote_control = remote_control;
1539 RecordKeyEvHandler::~RecordKeyEvHandler()
1543 int RecordKeyEvHandler::remote_key(int key)
1545 Record *record = remote_control->mwindow_gui->record;
1546 return record->record_process_key(remote_control, key);
1550 display_video_text(int x, int y, const char *text, int font,
1551 int bg_color, int color, int alpha, double secs, double scale)
1553 // gotta have a window for resources
1554 record_monitor->window->
1555 display_video_text(x, y, text, font,
1556 bg_color, color, alpha, secs, scale);
1560 display_cut_icon(int x, int y)
1562 VFrame *cut_icon = *mwindow->theme->get_image_set("commercial");
1564 x += cut_icon->get_w()*scale; y += cut_icon->get_h()*scale;
1565 display_vframe(cut_icon, x, y, 200, 1.0, scale);
1569 DeviceDVBInput *Record::
1572 DeviceDVBInput *dvb_dev = !vdevice ? 0 :
1573 (DeviceDVBInput *)vdevice->mpeg_device();
1574 if( !dvb_dev ) dvb_dev = !adevice ? 0 :
1575 (DeviceDVBInput *)adevice->mpeg_device();
1583 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1585 if( !channel ) return;
1586 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1587 DeviceDVBInput *dvb_input = dvb_device();
1588 if( !dvb_input ) return 1;
1589 zmpeg3_t *fd = dvb_input->get_src();
1591 scale *= fd->video_height(channel->video_stream) / 1080.;
1592 int ww = in->get_w() * scale, hh = in->get_h() * scale;
1593 VFrame out(ww, hh, BC_YUV444P);
1594 BC_WindowBase::get_cmodels()->transfer(out.get_rows(), in->get_rows(),
1595 out.get_y(), out.get_u(), out.get_v(),
1596 in->get_y(), in->get_u(), in->get_v(),
1597 0, 0, in->get_w(), in->get_h(),
1598 0, 0, out.get_w(), out.get_h(),
1599 in->get_color_model(), out.get_color_model(), 0,
1600 in->get_bytes_per_line(), ww);
1601 int sz = ww * hh; uint8_t *yuv = out.get_data(), aimg[sz];
1602 uint8_t *yp = yuv, *up = yuv+sz, *vp = yuv+2*sz, *ap = 0;
1603 if( alpha > 0 ) memset(ap=aimg, alpha, sz);
1604 else if( alpha < 0 ) ap = yp;
1605 fd->display_subtitle(channel->video_stream, 1, 1,
1606 yp,up,vp,ap, x,y,ww,hh, 0, secs*1000);
1607 dvb_input->put_src();
1613 if( !channel ) return;
1614 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return;
1615 DeviceDVBInput *dvb_input = dvb_device();
1616 if( !dvb_input ) return 1;
1617 zmpeg3_t *fd = dvb_input->get_src();
1619 fd->delete_subtitle(channel->video_stream, 1, 1);
1620 dvb_input->put_src();
1626 display_vframe(VFrame *in, int x, int y, int alpha, double secs, double scale)
1628 record_monitor->display_vframe(in, x, y, alpha, secs, scale);
1634 record_monitor->undisplay_vframe();
1640 display_channel_info()
1643 if( !channel ) return 1;
1644 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1645 DeviceDVBInput *dvb_input = dvb_device();
1646 if( !dvb_input ) return 1;
1647 int elem = channel->element;
1648 time_t tt; time(&tt);
1649 struct tm ttm; localtime_r(&tt,&ttm);
1651 char text[BCTEXTLEN];
1652 zmpeg3_t *fd = dvb_input->get_src();
1654 for( int ord=0, i=0; ord<0x80; ) {
1656 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1657 if( len < 0 ) { ++ord; i = 0; continue; }
1658 struct tm stm = ttm, etm = ttm;
1659 char wday[4], *bp = cp; cp += len;
1660 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1661 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1662 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1663 while( bp<cp && *bp++!='\n' );
1664 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1665 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1666 stm.tm_year -= 1900; stm.tm_mon -= 1;
1667 etm.tm_year = stm.tm_year;
1668 etm.tm_mon = stm.tm_mon;
1669 etm.tm_mday = stm.tm_mday;
1670 time_t st = mktime(&stm), et = mktime(&etm);
1671 if( et < st ) et += 24*3600;
1672 if( tt < st || tt >= et ) continue;
1673 int major=0, minor=0;
1674 fd->dvb.get_channel(elem, major, minor);
1675 char chan[64]; sprintf(chan, "%3d.%1d", major, minor);
1676 for( i=0; i<5 && chan[i]!=0; ++i ) *bp++ = chan[i];
1677 while( bp<cp && *bp++!='\n' );
1679 for( char *lp=bp; bp<cp; ++bp ) {
1680 if( *bp == '\n' || ((bp-lp)>=60 && *bp==' ') ) {
1681 if( ++n >= 10 ) break;
1686 while( bp > text && *--bp == '\n' ) *bp = 0;
1690 dvb_input->put_src();
1692 display_video_text(20, 20, text,
1693 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1701 display_channel_schedule()
1704 if( !channel ) return 1;
1705 if( !vdevice || vdevice->in_config->driver != CAPTURE_DVB ) return 1;
1706 DeviceDVBInput *dvb_input = dvb_device();
1707 if( !dvb_input ) return 1;
1708 int elem = channel->element;
1709 time_t tt; time(&tt);
1710 struct tm ttm; localtime_r(&tt,&ttm);
1711 char text[BCTEXTLEN];
1712 zmpeg3_t *fd = dvb_input->get_src();
1714 RecordSchedule channel_schedule;
1715 for( int ord=0, i=0; ord<0x80; ) {
1717 int len = fd->dvb.get_chan_info(elem,ord,i++,cp,BCTEXTLEN-2);
1718 if( len < 0 ) { ++ord; i = 0; continue; }
1719 struct tm stm = ttm, etm = ttm;
1720 char wday[4], *bp = cp; cp += len;
1721 if( sscanf(bp, "%02d:%02d:%02d-%02d:%02d:%02d",
1722 &stm.tm_hour, &stm.tm_min, &stm.tm_sec,
1723 &etm.tm_hour, &etm.tm_min, &etm.tm_sec) != 6 ) continue;
1724 while( bp<cp && *bp++!='\n' );
1725 if( sscanf(bp, "(%3s) %04d/%02d/%02d", &wday[0],
1726 &stm.tm_year, &stm.tm_mon, &stm.tm_mday) != 4 ) continue;
1727 stm.tm_year -= 1900; stm.tm_mon -= 1;
1728 etm.tm_year = stm.tm_year;
1729 etm.tm_mon = stm.tm_mon;
1730 etm.tm_mday = stm.tm_mday;
1731 time_t st = mktime(&stm), et = mktime(&etm);
1732 if( et < st ) et += 24*3600;
1733 if( tt >= et ) continue;
1734 if( bp > text )*--bp = 0;
1735 channel_schedule.append(new RecordScheduleItem(st, text));
1737 dvb_input->put_src();
1739 channel_schedule.sort_times();
1740 char *cp = text, *ep = cp+sizeof(text)-1;
1741 for( int i=0, n=0; i<channel_schedule.size(); ++i ) {
1742 RecordScheduleItem *item = channel_schedule.get(i);
1743 for( char *bp=item->title; cp<ep && *bp!=0; ++bp ) *cp++ = *bp;
1744 if( cp < ep ) *cp++ = '\n';
1745 if( ++n >= 12 ) break;
1748 while( cp > text && *--cp == '\n' ) *cp = 0;
1750 display_video_text(20, 20, text,
1751 BIGFONT, WHITE, BLACK, 0, 3., 1.);
1758 void Record::clear_keybfr()
1764 void Record::add_key(int ch)
1767 while( n<(int)sizeof(keybfr)-2 && keybfr[n] ) ++n;
1768 keybfr[n++] = ch; keybfr[n] = 0;
1769 display_video_text(20, 20, keybfr,
1770 BIGFONT, WHITE, BLACK, 0, 3., 2.);
1773 int Record::record_process_key(RemoteControl *remote_control, int key)
1779 if( last_key != KPENTER ) break;
1781 set_channel_name(keybfr);
1785 if( last_key == '0' && ch == '0' ) {
1789 case '1': case '2': case '3':
1790 case '4': case '5': case '6':
1791 case '7': case '8': case '9':
1795 //case UP: case DOWN:
1796 //case LEFT: case RIGHT:
1797 //case KPPLAY: case KPFWRD:
1799 case 'a': // toggle mute audio
1800 if( !monitor_audio ) { set_mute_gain(1); set_play_gain(1); }
1801 set_audio_monitoring(monitor_audio ? 0 : 1);
1803 case KPBACK: case 'm': // toggle metering audio
1804 set_audio_metering(metering_audio ? 0 : 1);
1806 case 'd': case KPSLASH:
1807 display_channel_info();
1809 case 'e': case KPSTAR:
1810 display_channel_schedule();
1812 case KPCHUP: case KPPLUS:
1815 case KPCHDN: case KPMINUS:
1819 set_play_gain(play_gain * 1.25);
1822 set_play_gain(play_gain * 0.75);
1826 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
1827 int on = canvas->get_fullscreen() ? 0 : 1;
1828 canvas->Canvas::set_fullscreen(on, 0);
1830 #ifdef HAVE_COMMERCIAL
1831 case KPRECD: case 'c': // start capture, mark endpoint
1833 start_commercial_capture();
1835 set_play_gain(0.075);
1838 mark_commercial_capture(DEL_MARK);
1839 blink_status->update();
1841 display_cut_icon(10,20);
1843 case KPSTOP: case 's': // end capture, start cutting
1844 remote_control->set_color(YELLOW);
1845 stop_commercial_capture(1);
1847 case KPAUSE: case 'x': // ignore current commercial
1848 mark_commercial_capture(DEL_SKIP);
1850 case KPPLAY: case 'z': // ignore previous endpoint
1851 mark_commercial_capture(DEL_OOPS);
1862 int Record::wintv_process_code(int code)
1872 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
1873 int on = canvas->get_fullscreen() ? 0 : 1;
1874 canvas->Canvas::set_fullscreen(on, 0);
1876 case WTV_BACK: // toggle metering audio
1877 set_audio_metering(metering_audio ? 0 : 1);
1880 set_play_gain(play_gain * 1.125);
1883 set_play_gain(play_gain * 0.875);
1892 WinTVRecordHandler *wintv_remote = (WinTVRecordHandler *)
1893 mwindow->gui->remote_control->handler;
1894 WinTV *wintv = !wintv_remote ? 0 : wintv_remote->wintv;
1895 if( !wintv || wintv->last_code == WTV_0 ) {
1899 case WTV_1: case WTV_2: case WTV_3: case WTV_4:
1900 case WTV_5: case WTV_6: case WTV_7: case WTV_8:
1902 int ch = code - WTV_0 + '0';
1905 case WTV_TEXT: // add decimal point
1908 case WTV_CC: // change channel
1909 set_channel_name(keybfr);
1913 display_channel_schedule();
1915 case WTV_START: break;
1916 case WTV_REV: break;
1917 case WTV_STOP: break;
1918 case WTV_PLAY: break;
1919 case WTV_FWD: break;
1920 case WTV_END: break;
1921 case WTV_MUTE: // toggle mute audio
1922 if( !monitor_audio ) {
1924 set_play_gain(play_gain);
1926 set_audio_monitoring(monitor_audio ? 0 : 1);
1929 display_channel_info();
1932 printf("wintv record: unknown code: %04x\n", code);
1939 int Record::x10tv_process_code(int code)
1943 case X10_A: // toggle metering audio
1944 set_audio_metering(metering_audio ? 0 : 1);
1947 case X10_POWER: break;
1949 case X10_DVD: break;
1950 case X10_WWW: break;
1951 case X10_BOOK: break;
1952 case X10_EDIT: break;
1954 set_play_gain(play_gain * 1.125);
1957 set_play_gain(play_gain * 0.875);
1959 case X10_MUTE: // toggle mute audio
1960 if( !monitor_audio ) {
1962 set_play_gain(play_gain);
1964 set_audio_monitoring(monitor_audio ? 0 : 1);
1973 X10TVRecordHandler *x10tv_remote = (X10TVRecordHandler *)
1974 mwindow->gui->remote_control->handler;
1975 X10TV *x10tv = !x10tv_remote ? 0 : x10tv_remote->x10tv;
1976 if( x10tv->last_code == X10_0 ) {
1980 case X10_1: case X10_2: case X10_3: case X10_4:
1981 case X10_5: case X10_6: case X10_7: case X10_8:
1983 int ch = code - X10_0 + '0';
1986 case X10_MENU: // add decimal point
1989 case X10_SETUP: // change channel
1990 set_channel_name(keybfr);
1994 display_channel_schedule();
1998 display_channel_info();
2000 case X10_PROPS: break;
2005 RecordMonitorCanvas *canvas = record_monitor->window->canvas;
2006 int on = canvas->get_fullscreen() ? 0 : 1;
2007 canvas->Canvas::set_fullscreen(on, 0);
2012 case X10_REW: break;
2013 case X10_PLAY: break;
2014 case X10_FWD: break;
2015 case X10_REC: break;
2016 case X10_STOP: break;
2017 case X10_PAUSE: break;
2020 printf("x10tv record: unknown code: %04x\n", code);
2027 #ifdef HAVE_COMMERCIAL
2028 int Record::start_commercial_capture()
2030 if( deletions != 0 ) return 1;
2031 Channel *channel = get_current_channel();
2032 if( !channel ) return 1;
2033 int track = channel->video_stream;
2034 int pid = vdevice->get_video_pid(track);
2035 if( pid < 0 ) return 1;
2036 time_t st; time(&st);
2037 struct tm stm; localtime_r(&st, &stm);
2038 char file_path[BCTEXTLEN];
2039 sprintf(file_path,"/tmp/del%04d%02d%02d-%02d%02d%02d.ts",
2040 stm.tm_year+1900, stm.tm_mon+1, stm.tm_mday,
2041 stm.tm_hour, stm.tm_min, stm.tm_sec);
2042 commercial_fd = open(file_path,O_RDWR+O_CREAT,0666);
2043 if( commercial_fd < 0 ) return 1;
2044 if( vdevice->start_record(commercial_fd, 0x800000) ) {
2045 close(commercial_fd);
2049 commercial_start_time = st;
2050 printf("del to %s\n", file_path);
2051 deletions = new Deletions(pid, file_path);
2052 mark_commercial_capture(DEL_START);
2053 blink_status->start();
2057 int Record::mark_commercial_capture(int action)
2059 if( deletions == 0 ) return 1;
2060 double time = vdevice->get_timestamp();
2061 printf("dele %f\n", time);
2062 deletions->append(new Dele(time, action));
2067 void Record::remote_fill_color(int color)
2069 mwindow->gui->remote_control->fill_color(color);
2072 void Record::set_status_color(int color)
2074 status_color = color;
2075 remote_fill_color(status_color);
2078 void Record::set_mute_gain(double gain)
2080 gain = (mute_gain = gain) * play_gain;
2081 if( adevice ) adevice->set_play_gain(gain);
2084 void Record::set_play_gain(double gain)
2086 gain = mute_gain * (play_gain = gain);
2087 if( adevice ) adevice->set_play_gain(gain);
2090 #ifdef HAVE_COMMERCIAL
2091 int Record::stop_commercial_capture(int run_job)
2093 if( deletions == 0 ) return 1;
2094 if( run_job ) blink_status->stop();
2097 vdevice->stop_record();
2098 commercial_start_time = -1;
2099 if( commercial_fd >= 0 ) {
2100 close(commercial_fd);
2105 char del_filename[BCTEXTLEN];
2106 strcpy(del_filename, deletions->file_path());
2107 strcpy(strrchr(del_filename, '.'),".del");
2108 if( !deletions->write_dels(del_filename) ) {
2109 int pid = spawn("cutads %s",del_filename);
2111 cut_pids.append(pid);
2112 cutads_status->start_waiting();
2118 remove_file(deletions->filepath);
2120 delete deletions; deletions = 0;
2125 spawn(const char *fmt, ...)
2127 const char *exec_path = File::get_cinlib_path();
2128 char cmd[BCTEXTLEN], *cp = cmd, *ep = cp+sizeof(cmd)-1;
2129 va_list ap; va_start(ap, fmt);
2130 cp += snprintf(cp, ep-cp, "exec %s/", exec_path);
2131 cp += vsnprintf(cp, ep-cp, fmt, ap); va_end(ap);
2133 pid_t pid = vfork();
2134 if( pid < 0 ) return -1;
2135 if( pid > 0 ) return pid;
2136 char *const argv[4] = { (char*) "/bin/sh", (char*) "-c", cmd, 0 };
2137 execvp(argv[0], &argv[0]);
2144 for( int i=0; i<cut_pids.size(); ) {
2145 int status, pid = cut_pids.get(i);
2146 if( waitpid(pid, &status, WNOHANG) ) {
2147 cut_pids.remove(pid);
2152 return cut_pids.size();
2156 RecordCutAdsStatus::
2157 RecordCutAdsStatus(Record *record)
2160 this->record = record;
2161 wait_lock = new Condition(0,"RecordCutAdsStatus::wait_lock",0);
2166 RecordCutAdsStatus::
2167 ~RecordCutAdsStatus()
2171 wait_lock->unlock();
2178 void RecordCutAdsStatus::
2181 wait_lock->unlock();
2184 void RecordCutAdsStatus::
2187 int status, pgrp = getpgrp();
2189 wait_lock->lock("RecordCutAdsStatus::run");
2191 if( !record->commercial_jobs() ) continue;
2192 record->set_status_color(YELLOW);
2195 waitpid(-pgrp, &status, 0);
2197 if( !record->commercial_jobs() ) break;
2199 record->set_status_color(GREEN);
2203 void RecordBlinkStatus::
2204 remote_color(int color)
2206 record->remote_fill_color(color);
2209 void RecordBlinkStatus::
2215 void RecordBlinkStatus::
2223 void RecordBlinkStatus::
2234 RecordBlinkStatus(Record *record)
2237 this->record = record;
2241 ~RecordBlinkStatus()
2246 void RecordBlinkStatus::
2251 remote_color(color);
2255 color ^= YELLOW ^ BLUE;
2256 if( timer.get_difference() > 10*60*1000 ) { // 10 minutes
2257 record->stop_commercial_capture(0);
2261 remote_color(record->status_color);