/** Update tracks and settings from database. */ bool RecorderImpl::UpdateFromDatabase(unsigned int max_inputs, unsigned int max_tracks_per_input) { bool ok = true; // Load recorder object from database prodauto::Recorder * rec = 0; try { rec = prodauto::Database::getInstance()->loadRecorder(mName); } catch (const prodauto::DBException & dbe) { ACE_DEBUG((LM_ERROR, ACE_TEXT("Database Exception: %C\n"), dbe.getMessage().c_str())); ok = false; } if (!rec) { // If there was a problem, re-initialise database and hope // for better luck next time. ACE_DEBUG((LM_WARNING, ACE_TEXT("Re-initialising database.\n"))); DatabaseManager::Instance()->ReInitialise(); } else { // Store the Recorder object mRecorder.reset(rec); // Update RecorderSettings RecorderSettings * settings = RecorderSettings::Instance(); if (settings) { settings->Update(rec); } // Clear the set of SourceConfigs // and the various maps mSourceConfigs.clear(); mTrackMap.clear(); mTrackIndexMap.clear(); mRecordingLocationMap.clear(); // Set the source track names const unsigned int n_inputs = ACE_MIN((unsigned int)rec->recorderInputConfigs.size(), max_inputs); unsigned int track_i = 0; unsigned int n_video_tracks = 0; for (unsigned int i = 0; i < n_inputs; ++i) { prodauto::RecorderInputConfig * ric = rec->getInputConfig(i + 1); // We force number of tracks per input to be the hardware max because // this makes it easier to map to hardware parameters when filling out // tracks status with "signal present" etc. //const unsigned int n_tracks = ACE_MIN(ric->trackConfigs.size(), mMaxTracksPerInput); const unsigned int n_tracks = max_tracks_per_input; for (unsigned int j = 0; j < n_tracks; ++j) { prodauto::RecorderInputTrackConfig * ritc = 0; if (ric && j < ric->trackConfigs.size()) { ritc = ric->getTrackConfig(j + 1); } prodauto::SourceConfig * sc = 0; if (ritc) { sc = ritc->sourceConfig; } prodauto::SourceTrackConfig * stc = 0; if (sc) { stc = sc->getTrackConfig(ritc->sourceTrackID); } // Update our set of SourceConfig. Actually using // a map with database ID as the key, simply because // having a pointer as a key is not good practice. if (sc) { long id = sc->getDatabaseID(); mSourceConfigs[id] = sc; } // Update our map of RecordingLocation names if (sc) { long id = sc->recordingLocation; if (id) { try { mRecordingLocationMap[id] = prodauto::Database::getInstance()->loadLocationName(id); ACE_DEBUG((LM_DEBUG, ACE_TEXT("Location %d \"%C\"\n"), id, mRecordingLocationMap[id].c_str())); } catch (const prodauto::DBException & dbe) { ACE_DEBUG((LM_ERROR, ACE_TEXT("Database Exception: %C\n"), dbe.getMessage().c_str())); } } } // Update map from source to hardware tracks if (stc) { long id = stc->getDatabaseID(); HardwareTrack trk = {i, j}; mTrackMap[id] = trk; } // Note that here we assemble our list of tracks in harware order. // An alternative would be to present them in source order. The // GUI already re-orders them in source order and presents them to // the user in that form. // Update map from source to mTracks index long stc_db_id = 0; if (stc) { stc_db_id = stc->getDatabaseID(); // Check for duplicate input tracks if (mTrackIndexMap.find(stc_db_id) != mTrackIndexMap.end()) { ACE_DEBUG((LM_WARNING, ACE_TEXT("Warning: Duplicate input tracks connected! This is likely to cause problems.\n"))); } mTrackIndexMap[stc_db_id] = track_i; } mTracks->length(track_i + 1); ProdAuto::Track & track = mTracks->operator[](track_i); // Set track type if (stc && stc->dataDef == PICTURE_DATA_DEFINITION) { track.type = ProdAuto::VIDEO; ++n_video_tracks; } else if (stc && stc->dataDef == SOUND_DATA_DEFINITION) { track.type = ProdAuto::AUDIO; } // If no source track, assume hardware track 0 is video else if (j == 0) { track.type = ProdAuto::VIDEO; ++n_video_tracks; } else { track.type = ProdAuto::AUDIO; } #if 1 // Name track by hardware input std::ostringstream s; if (track.type == ProdAuto::VIDEO) { s << "V"; } else { track.type = ProdAuto::AUDIO; s << "A" << j; } s << " (input " << i << ")"; track.name = CORBA::string_dup(s.str().c_str()); #else // Name track by source track name if (stc) { track.name = CORBA::string_dup(stc->name.c_str()); } #endif // Set track id if (stc) { track.id = stc->getDatabaseID(); // Helps to have this as used as key for maps } else { // No source connected track.id = 0; } if (sc && stc) { track.has_source = 1; track.src.package_name = CORBA::string_dup(sc->name.c_str()); prodauto::SourcePackage * sp = sc->getSourcePackage(); if (sp) { track.src.tape_name = CORBA::string_dup(sp->name.c_str()); } else { track.src.tape_name = CORBA::string_dup(""); } track.src.track_name = CORBA::string_dup(stc->name.c_str()); } else { // No connection to this input track.has_source = 0; track.src.package_name = CORBA::string_dup("zz No Connection"); track.src.tape_name = CORBA::string_dup(""); track.src.track_name = CORBA::string_dup(""); } ACE_DEBUG((LM_DEBUG, ACE_TEXT("Input %d, track %d, databse id %3d, src.track_name \"%C\"\n"), i, j, stc_db_id, (const char *) track.src.track_name)); ++track_i; } // tracks } // inputs //mVideoTrackCount = n_video_tracks; // Re-initialise tracks status, if necessary. if (mTracksStatus->length() != mTracks->length()) { mTracksStatus->length(mTracks->length()); for (unsigned int i = 0; i < mTracksStatus->length(); ++i) { ProdAuto::TrackStatus & ts = mTracksStatus->operator[](i); ts.rec = 0; ts.rec_error = 0; ts.signal_present = 0; ts.timecode.undefined = true; //ts.timecode.edit_rate = mEditRate; } } ACE_DEBUG((LM_INFO, ACE_TEXT("Updated sources for recorder \"%C\"\n"), mRecorder->name.c_str())); } // Set source package names (using tape names if available) ok = ok && SetSourcePackages(); return ok; }
/** Final preparation for recording. */ void IngexRecorder::Setup( framecount_t start_timecode, const prodauto::ProjectName & project_name) { ACE_DEBUG((LM_DEBUG, ACE_TEXT("IngexRecorder::Setup()\n"))); // Get ProjectName associated with supplied name. //prodauto::ProjectName project_name; //GetProjectFromDb(project, project_name); // Store project name mProjectName = project_name; // Get current recorder settings RecorderSettings * settings = RecorderSettings::Instance(); settings->Update(mpImpl->Recorder()); /* switch (settings->timecode_mode) { case LTC_PARAMETER_VALUE: IngexShm::Instance()->TcMode(IngexShm::LTC); ACE_DEBUG((LM_DEBUG, ACE_TEXT("LTC mode\n"))); break; case VITC_PARAMETER_VALUE: IngexShm::Instance()->TcMode(IngexShm::VITC); ACE_DEBUG((LM_DEBUG, ACE_TEXT("VITC mode\n"))); break; default: ACE_DEBUG((LM_ERROR, ACE_TEXT("Unexpected timecode mode\n"))); break; } */ //unsigned int n_channels = IngexShm::Instance()->Channels(); // Tracks per channel // e.g. 5 (1 video, 4 audio) or 9 (1 video, 8 audio) // A bit dodgy as different inputs on a recorder can have // different numbers of tracks. //mTracksPerChannel = track_enables.size() / channel_enables.size(); int first_enabled_channel = -1; for (unsigned int i = 0; first_enabled_channel < 0 && i < mChannelEnable.size(); ++i) { if (mChannelEnable[i]) { first_enabled_channel = i; } } // Create any needed paths. // NB. Paths need to be same as those used in recorder_fucntions.cpp for (std::vector<EncodeParams>::iterator it = settings->encodings.begin(); it != settings->encodings.end(); ++it) { if (USE_PROJECT_SUBDIR) { std::string project_subdir = mProjectName.name; clean_filename(project_subdir); it->dir += PATH_SEPARATOR; it->dir += project_subdir; it->copy_dest += PATH_SEPARATOR; it->copy_dest += project_subdir; } FileUtils::CreatePath(it->dir); if (it->file_format == MXF_FILE_FORMAT_TYPE) { // Make Creating and Failures subdirs for MXF std::ostringstream creating_path; creating_path << it->dir << PATH_SEPARATOR << settings->mxf_subdir_creating; FileUtils::CreatePath(creating_path.str()); std::ostringstream failures_path; failures_path << it->dir << PATH_SEPARATOR << settings->mxf_subdir_failures; FileUtils::CreatePath(failures_path.str()); //std::ostringstream metadata_path; //metadata_path << it->dir << PATH_SEPARATOR << settings->mxf_subdir_metadata; //FileUtils::CreatePath(metadata_path.str()); } else { // Make Creating subdir for other formats std::ostringstream creating_path; creating_path << it->dir << PATH_SEPARATOR << CREATING_SUBDIR; FileUtils::CreatePath(creating_path.str()); } } // Set up encoding threads int encoding_i = 0; for (std::vector<EncodeParams>::const_iterator it = settings->encodings.begin(); it != settings->encodings.end(); ++it, ++encoding_i) { if (it->source == Input::NORMAL) { for (unsigned int i = 0; i < mChannelEnable.size(); i++) { if (mChannelEnable[i]) { ThreadParam tp; tp.p_rec = this; tp.p_opt = new RecordOptions; tp.p_opt->channel_num = i; tp.p_opt->index = encoding_i; tp.p_opt->resolution = it->resolution; tp.p_opt->file_format = it->file_format; tp.p_opt->bitc = it->bitc; tp.p_opt->dir = it->dir; mThreadParams.push_back(tp); } } } else if (it->source == Input::QUAD) { ThreadParam tp; tp.p_rec = this; tp.p_opt = new RecordOptions; tp.p_opt->channel_num = first_enabled_channel; tp.p_opt->index = encoding_i; tp.p_opt->quad = true; tp.p_opt->resolution = it->resolution; tp.p_opt->file_format = it->file_format; tp.p_opt->bitc = it->bitc; tp.p_opt->dir = it->dir; mThreadParams.push_back(tp); } } #if 0 // For test only, add a further encoding { ThreadParam tp; tp.p_rec = this; tp.p_opt = new RecordOptions; tp.p_opt->channel_num = 0; tp.p_opt->index = 2; tp.p_opt->resolution = 8; tp.p_opt->file_format = MXF_FILE_FORMAT_TYPE; tp.p_opt->bitc = true; tp.p_opt->dir = "/video/mxf_offline"; mThreadParams.push_back(tp); } #endif // Create and store filenames based on source, target timecode and date. ::Timecode tc(start_timecode, mFps, mDf); std::string date = DateTime::DateNoSeparators(); const char * tcode = tc.TextNoSeparators(); // We also include project name to help with copying to project-based // directories on a file-server. // Note that we make sure ident does not contain any unsuitable // characters such as '/' // Set filename stems in RecordOptions. for (std::vector<ThreadParam>::iterator it = mThreadParams.begin(); it != mThreadParams.end(); ++it) { const char * src_name = (it->p_opt->quad ? QUAD_NAME : SOURCE_NAME[it->p_opt->channel_num]); std::ostringstream ss; ss << date << "_" << tcode << "_" << mProjectName.name << "_" << mpImpl->Name() << "_" << src_name << "_" << it->p_opt->index; std::string ident = ss.str(); clean_filename(ident); it->p_opt->file_ident = ident; } // Set up some of the user comments mUserComments.clear(); mUserComments.push_back( prodauto::UserComment(AVID_UC_SHOOT_DATE_NAME, date.c_str(), STATIC_COMMENT_POSITION, 0)); }