bool Dvr::DeleteRecording(int RecordedId, int chanid, const QDateTime &recstarttsRaw, bool forceDelete, bool allowRerecord) { if ((RecordedId <= 0) && (chanid <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); // TODO Should use RecordingInfo ProgramInfo pi; if (RecordedId > 0) pi = ProgramInfo(RecordedId); else pi = ProgramInfo(chanid, recstarttsRaw.toUTC()); if (pi.GetChanID() && pi.HasPathname()) { QString cmd = QString("DELETE_RECORDING %1 %2 %3 %4") .arg(pi.GetChanID()) .arg(pi.GetRecordingStartTime(MythDate::ISODate)) .arg(forceDelete ? "FORCE" : "NO_FORCE") .arg(allowRerecord ? "FORGET" : "NO_FORGET"); MythEvent me(cmd); gCoreContext->dispatch(me); return true; } return false; }
/** \brief Adds a ProgramInfo to the cache. * \note This must only be called from the UI thread. */ void ProgramInfoCache::Add(const ProgramInfo &pginfo) { if (!pginfo.GetChanID() || Update(pginfo)) return; PICKey key(pginfo.GetChanID(),pginfo.GetRecordingStartTime()); m_cache[key] = new ProgramInfo(pginfo); }
static int QueueJob(const MythUtilCommandLineParser &cmdline) { ProgramInfo pginfo; if (!GetProgramInfo(cmdline, pginfo)) return GENERIC_EXIT_NO_RECORDING_DATA; bool rebuildSeektable = false; int jobType = JOB_NONE; if (cmdline.toString("queuejob") == "transcode") jobType = JOB_TRANSCODE; else if (cmdline.toString("queuejob") == "commflag") jobType = JOB_COMMFLAG; else if (cmdline.toString("queuejob") == "rebuild") { jobType = JOB_COMMFLAG; rebuildSeektable = true; } else if (cmdline.toString("queuejob") == "metadata") jobType = JOB_METADATA; else if (cmdline.toString("queuejob") == "userjob1") jobType = JOB_USERJOB1; else if (cmdline.toString("queuejob") == "userjob2") jobType = JOB_USERJOB1; else if (cmdline.toString("queuejob") == "userjob4") jobType = JOB_USERJOB1; else if (cmdline.toString("queuejob") == "userjob4") jobType = JOB_USERJOB1; else if (cmdline.toInt("queuejob") > 0) jobType = cmdline.toInt("queuejob"); if (jobType == JOB_NONE) { LOG(VB_GENERAL, LOG_ERR, "Error, invalid job type given with queuejob option"); return GENERIC_EXIT_INVALID_CMDLINE; } bool result = JobQueue::QueueJob(jobType, pginfo.GetChanID(), pginfo.GetRecordingStartTime(), "", "", "", rebuildSeektable, JOB_QUEUED, QDateTime()); if (result) { QString tmp = QString("%1 Job Queued for chanid %2 @ %3") .arg(cmdline.toString("queuejob")) .arg(pginfo.GetChanID()) .arg(pginfo.GetRecordingStartTime().toString()); cerr << tmp.toLocal8Bit().constData() << endl; return GENERIC_EXIT_OK; } QString tmp = QString("Error queueing job for chanid %1 @ %2") .arg(pginfo.GetChanID()) .arg(pginfo.GetRecordingStartTime().toString()); cerr << tmp.toLocal8Bit().constData() << endl; return GENERIC_EXIT_DB_ERROR; }
ProgramInfo *getProgramInfoForFile(const QString &inFile) { ProgramInfo *pinfo = NULL; QString chanID, startTime; bool bIsMythRecording = false; bIsMythRecording = extractDetailsFromFilename(inFile, chanID, startTime); if (bIsMythRecording) { uint chanid = chanID.toUInt(); QDateTime recstartts = MythDate::fromString(startTime); pinfo = new ProgramInfo(chanid, recstartts); if (pinfo->GetChanID()) { pinfo->SetPathname(pinfo->GetPlaybackURL(false, true)); } else { delete pinfo; pinfo = NULL; } } if (!pinfo) { // file is not a myth recording or is no longer in the db pinfo = new ProgramInfo(inFile); LOG(VB_JOBQUEUE, LOG_NOTICE, "File is not a MythTV recording."); } else LOG(VB_JOBQUEUE, LOG_NOTICE, "File is a MythTV recording."); return pinfo; }
/// \brief Copies important fields from ProgramInfo void RecordingInfo::clone(const ProgramInfo &other, bool ignore_non_serialized_data) { bool is_same = (chanid && recstartts.isValid() && startts.isValid() && chanid == other.GetChanID() && recstartts == other.GetRecordingStartTime() && startts == other.GetScheduledStartTime()); ProgramInfo::clone(other, ignore_non_serialized_data); if (!is_same) { delete record; record = NULL; } oldrecstatus = rsUnknown; savedrecstatus = rsUnknown; future = false; schedorder = 0; mplexid = 0; desiredrecstartts = QDateTime(); desiredrecendts = QDateTime(); }
void LiveTVChain::SetProgram(const ProgramInfo &pginfo) { QMutexLocker lock(&m_lock); m_cur_chanid = pginfo.GetChanID(); m_cur_startts = pginfo.GetRecordingStartTime(); m_curpos = ProgramIsAt(pginfo); m_switchid = -1; }
/** * \brief Show the program guide */ void ScheduleCommon::ShowGuide(void) const { ProgramInfo *pginfo = GetCurrentProgram(); if (!pginfo) return; QString startchannel = pginfo->GetChanNum(); uint startchanid = pginfo->GetChanID(); QDateTime starttime = pginfo->GetScheduledStartTime(); GuideGrid::RunProgramGuide(startchanid, startchannel, starttime); }
/** * \brief Show the upcoming recordings for this title */ void ScheduleCommon::ShowUpcoming(void) const { ProgramInfo *pginfo = GetCurrentProgram(); if (!pginfo) return; if (pginfo->GetChanID() == 0 && pginfo->GetRecordingRuleID() > 0) return ShowUpcomingScheduled(); ShowUpcoming(pginfo->GetTitle(), pginfo->GetSeriesID()); }
/** \brief Updates a ProgramInfo in the cache. * \note This must only be called from the UI thread. * \return True iff the ProgramInfo was in the cache and was updated. */ bool ProgramInfoCache::Update(const ProgramInfo &pginfo) { QMutexLocker locker(&m_lock); Cache::iterator it = m_cache.find( PICKey(pginfo.GetChanID(),pginfo.GetRecordingStartTime())); if (it != m_cache.end()) it->second->clone(pginfo, true); return it != m_cache.end(); }
QFileInfo Content::GetRecording( int nRecordedId, int nChanId, const QDateTime &recstarttsRaw ) { if ((nRecordedId <= 0) && (nChanId <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); // ------------------------------------------------------------------ // Read Recording From Database // ------------------------------------------------------------------ // TODO Should use RecordingInfo ProgramInfo pginfo; if (nRecordedId > 0) pginfo = ProgramInfo(nRecordedId); else pginfo = ProgramInfo(nChanId, recstarttsRaw.toUTC()); if (!pginfo.GetChanID()) { LOG(VB_UPNP, LOG_ERR, QString("GetRecording - for '%1' failed") .arg(nRecordedId)); return QFileInfo(); } if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower()) { // We only handle requests for local resources QString sMsg = QString("GetRecording: Wrong Host '%1' request from '%2'.") .arg( gCoreContext->GetHostName()) .arg( pginfo.GetHostname() ); LOG(VB_UPNP, LOG_ERR, sMsg); throw HttpRedirectException( pginfo.GetHostname() ); } QString sFileName( GetPlaybackURL(&pginfo) ); // ---------------------------------------------------------------------- // check to see if the file exists // ---------------------------------------------------------------------- if (QFile::exists( sFileName )) return QFileInfo( sFileName ); return QFileInfo(); }
ProgramInfo *RemoteEncoder::GetRecording(void) { QStringList strlist( QString("QUERY_RECORDER %1").arg(recordernum) ); strlist << "GET_RECORDING"; if (SendReceiveStringList(strlist)) { ProgramInfo *proginfo = new ProgramInfo(strlist); if (proginfo->GetChanID()) return proginfo; delete proginfo; } return NULL; }
/** * \brief Show the channel search */ void ScheduleCommon::ShowChannelSearch() const { ProgramInfo *pginfo = GetCurrentProgram(); if (!pginfo) return; MythScreenStack *mainStack = GetMythMainWindow()->GetMainStack(); ProgLister *pl = new ProgLister(mainStack, plChannel, QString::number(pginfo->GetChanID()), "", pginfo->GetScheduledStartTime()); if (pl->Create()) mainStack->AddScreen(pl); else delete pl; }
ProgramInfo *LiveTVChain::EntryToProgram(const LiveTVChainEntry &entry) { ProgramInfo *pginfo = new ProgramInfo(entry.chanid, entry.starttime); if (pginfo->GetChanID()) { pginfo->SetPathname(entry.hostprefix + pginfo->GetBasename()); return pginfo; } LOG(VB_GENERAL, LOG_ERR, QString("EntryToProgram(%1@%2) failed to get pginfo") .arg(entry.chanid).arg(entry.starttime.toString())); delete pginfo; return NULL; }
/** \brief Returns the ProgramInfo being used by any current recording. * * Caller is responsible for deleting the ProgramInfo when done with it. */ ProgramInfo *PlaybackSock::GetRecording(uint cardid) { QStringList strlist(QString("QUERY_REMOTEENCODER %1").arg(cardid)); strlist << "GET_CURRENT_RECORDING"; if (!SendReceiveStringList(strlist)) return NULL; ProgramInfo *pginfo = new ProgramInfo(strlist); if (!pginfo->HasPathname() && !pginfo->GetChanID()) { delete pginfo; pginfo = NULL; } return pginfo; }
void ProgLister::DeleteOldEpisode(bool ok) { ProgramInfo *pi = GetCurrent(); if (!ok || !pi) return; MSqlQuery query(MSqlQuery::InitCon()); query.prepare( "DELETE FROM oldrecorded " "WHERE chanid = :CHANID AND " " starttime = :STARTTIME"); query.bindValue(":CHANID", pi->GetChanID()); query.bindValue(":STARTTIME", pi->GetScheduledStartTime()); if (!query.exec()) MythDB::DBError("ProgLister::DeleteOldEpisode", query); ScheduledRecording::signalChange(0); FillItemList(true); }
bool Dvr::UpdateRecordedWatchedStatus ( int RecordedId, int chanid, const QDateTime &recstarttsRaw, bool watched) { if ((RecordedId <= 0) && (chanid <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); // TODO Should use RecordingInfo ProgramInfo pi; if (RecordedId > 0) pi = ProgramInfo(RecordedId); else pi = ProgramInfo(chanid, recstarttsRaw.toUTC()); if (pi.GetChanID() && pi.HasPathname()) { pi.SaveWatched(watched); return true; } return false; }
DTC::ProgramGuide *Guide::GetProgramGuide( const QDateTime &dtStartTime , const QDateTime &dtEndTime , int nStartChanId, int nNumChannels, bool bDetails ) { if (!dtStartTime.isValid()) throw( "StartTime is invalid" ); if (!dtEndTime.isValid()) throw( "EndTime is invalid" ); if (dtEndTime < dtStartTime) throw( "EndTime is before StartTime"); if (nNumChannels == 0) nNumChannels = 1; if (nNumChannels == -1) nNumChannels = SHRT_MAX; // ---------------------------------------------------------------------- // Find the ending channel Id // ---------------------------------------------------------------------- int nEndChanId = nStartChanId; MSqlQuery query(MSqlQuery::InitCon()); query.prepare( "SELECT chanid FROM channel WHERE (chanid >= :STARTCHANID )" " ORDER BY chanid LIMIT :NUMCHAN" ); query.bindValue(":STARTCHANID", nStartChanId ); query.bindValue(":NUMCHAN" , nNumChannels ); if (!query.exec()) MythDB::DBError("Select ChanId", query); query.first(); nStartChanId = query.value(0).toInt(); query.last(); nEndChanId = query.value(0).toInt(); // ---------------------------------------------------------------------- // Build SQL statement for Program Listing // ---------------------------------------------------------------------- ProgramList progList; ProgramList schedList; MSqlBindings bindings; QString sSQL = "WHERE program.chanid >= :StartChanId " "AND program.chanid <= :EndChanId " "AND program.endtime >= :StartDate " "AND program.starttime <= :EndDate " "GROUP BY program.starttime, channel.channum, " "channel.callsign, program.title " "ORDER BY program.chanid "; bindings[":StartChanId"] = nStartChanId; bindings[":EndChanId" ] = nEndChanId; bindings[":StartDate" ] = dtStartTime; bindings[":EndDate" ] = dtEndTime; // ---------------------------------------------------------------------- // Get all Pending Scheduled Programs // ---------------------------------------------------------------------- bool hasConflicts; LoadFromScheduler(schedList, hasConflicts); // ---------------------------------------------------------------------- LoadFromProgram( progList, sSQL, bindings, schedList, false ); // ---------------------------------------------------------------------- // Build Response // ---------------------------------------------------------------------- DTC::ProgramGuide *pGuide = new DTC::ProgramGuide(); int nChanCount = 0; uint nCurChanId = 0; DTC::ChannelInfo *pChannel = NULL; for( uint n = 0; n < progList.size(); n++) { ProgramInfo *pInfo = progList[ n ]; if ( nCurChanId != pInfo->GetChanID() ) { nChanCount++; nCurChanId = pInfo->GetChanID(); pChannel = pGuide->AddNewChannel(); FillChannelInfo( pChannel, pInfo, bDetails ); } DTC::Program *pProgram = pChannel->AddNewProgram(); FillProgramInfo( pProgram, pInfo, false, bDetails ); } // ---------------------------------------------------------------------- pGuide->setStartTime ( dtStartTime ); pGuide->setEndTime ( dtEndTime ); pGuide->setStartChanId ( nStartChanId ); pGuide->setEndChanId ( nEndChanId ); pGuide->setNumOfChannels( nChanCount ); pGuide->setDetails ( bDetails ); pGuide->setCount ( progList.size()); pGuide->setAsOf ( QDateTime::currentDateTime() ); pGuide->setVersion ( MYTH_BINARY_VERSION ); pGuide->setProtoVer ( MYTH_PROTO_VERSION ); return pGuide; }
int main(int argc, char *argv[]) { uint chanid; QDateTime starttime; QString infile, outfile; QString profilename = QString("autodetect"); QString fifodir = NULL; int jobID = -1; int jobType = JOB_NONE; int otype = REPLEX_MPEG2; bool useCutlist = false, keyframesonly = false; bool build_index = false, fifosync = false; bool mpeg2 = false; bool fifo_info = false; bool cleanCut = false; QMap<QString, QString> settingsOverride; frm_dir_map_t deleteMap; frm_pos_map_t posMap; int AudioTrackNo = -1; int found_starttime = 0; int found_chanid = 0; int found_infile = 0; int update_index = 1; int isVideo = 0; bool passthru = false; MythTranscodeCommandLineParser cmdline; if (!cmdline.Parse(argc, argv)) { cmdline.PrintHelp(); return GENERIC_EXIT_INVALID_CMDLINE; } if (cmdline.toBool("showhelp")) { cmdline.PrintHelp(); return GENERIC_EXIT_OK; } if (cmdline.toBool("showversion")) { cmdline.PrintVersion(); return GENERIC_EXIT_OK; } QCoreApplication a(argc, argv); QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHTRANSCODE); if (cmdline.toBool("outputfile")) { outfile = cmdline.toString("outputfile"); update_index = 0; } bool showprogress = cmdline.toBool("showprogress"); int retval; QString mask("general"); bool quiet = (outfile == "-") || showprogress; if ((retval = cmdline.ConfigureLogging(mask, quiet)) != GENERIC_EXIT_OK) return retval; if (cmdline.toBool("starttime")) { starttime = cmdline.toDateTime("starttime"); found_starttime = 1; } if (cmdline.toBool("chanid")) { chanid = cmdline.toUInt("chanid"); found_chanid = 1; } if (cmdline.toBool("jobid")) jobID = cmdline.toInt("jobid"); if (cmdline.toBool("inputfile")) { infile = cmdline.toString("inputfile"); found_infile = 1; } if (cmdline.toBool("video")) isVideo = true; if (cmdline.toBool("profile")) profilename = cmdline.toString("profile"); if (cmdline.toBool("usecutlist")) { useCutlist = true; if (!cmdline.toString("usecutlist").isEmpty()) { if (!cmdline.toBool("inputfile") && !cmdline.toBool("hls")) { LOG(VB_GENERAL, LOG_CRIT, "External cutlists are only allowed " "when using the --infile option."); return GENERIC_EXIT_INVALID_CMDLINE; } uint64_t last = 0, start, end; QStringList cutlist = cmdline.toStringList("usecutlist", " "); QStringList::iterator it; for (it = cutlist.begin(); it != cutlist.end(); ++it) { QStringList startend = (*it).split("-", QString::SkipEmptyParts); if (startend.size() == 2) { start = startend.first().toULongLong(); end = startend.last().toULongLong(); if (cmdline.toBool("inversecut")) { LOG(VB_GENERAL, LOG_DEBUG, QString("Cutting section %1-%2.") .arg(last).arg(start)); deleteMap[start] = MARK_CUT_END; deleteMap[end] = MARK_CUT_START; last = end; } else { LOG(VB_GENERAL, LOG_DEBUG, QString("Cutting section %1-%2.") .arg(start).arg(end)); deleteMap[start] = MARK_CUT_START; deleteMap[end] = MARK_CUT_END; } } } if (cmdline.toBool("inversecut")) { if (deleteMap.contains(0) && (deleteMap[0] == MARK_CUT_END)) deleteMap.remove(0); else deleteMap[0] = MARK_CUT_START; deleteMap[999999999] = MARK_CUT_END; LOG(VB_GENERAL, LOG_DEBUG, QString("Cutting section %1-999999999.") .arg(last)); } // sanitize cutlist if (deleteMap.count() >= 2) { frm_dir_map_t::iterator cur = deleteMap.begin(), prev; prev = cur++; while (cur != deleteMap.end()) { if (prev.value() == cur.value()) { // two of the same type next to each other QString err("Cut %1points found at %3 and %4, with no " "%2 point in between."); if (prev.value() == MARK_CUT_END) err = err.arg("end").arg("start"); else err = err.arg("start").arg("end"); LOG(VB_GENERAL, LOG_CRIT, "Invalid cutlist defined!"); LOG(VB_GENERAL, LOG_CRIT, err.arg(prev.key()) .arg(cur.key())); return GENERIC_EXIT_INVALID_CMDLINE; } else if ( (prev.value() == MARK_CUT_START) && ((cur.key() - prev.key()) < 2) ) { LOG(VB_GENERAL, LOG_WARNING, QString("Discarding " "insufficiently long cut: %1-%2") .arg(prev.key()).arg(cur.key())); prev = deleteMap.erase(prev); cur = deleteMap.erase(cur); if (cur == deleteMap.end()) continue; } prev = cur++; } } } else if (cmdline.toBool("inversecut")) { cerr << "Cutlist inversion requires an external cutlist be" << endl << "provided using the --honorcutlist option." << endl; return GENERIC_EXIT_INVALID_CMDLINE; } } if (cmdline.toBool("cleancut")) cleanCut = true; if (cmdline.toBool("allkeys")) keyframesonly = true; if (cmdline.toBool("reindex")) build_index = true; if (cmdline.toBool("fifodir")) fifodir = cmdline.toString("fifodir"); if (cmdline.toBool("fifoinfo")) fifo_info = true; if (cmdline.toBool("fifosync")) fifosync = true; if (cmdline.toBool("recopt")) recorderOptions = cmdline.toString("recopt"); if (cmdline.toBool("mpeg2")) mpeg2 = true; if (cmdline.toBool("ostream")) { if (cmdline.toString("ostream") == "dvd") otype = REPLEX_DVD; else if (cmdline.toString("ostream") == "ts") otype = REPLEX_TS_SD; else { cerr << "Invalid 'ostream' type: " << cmdline.toString("ostream").toLocal8Bit().constData() << endl; return GENERIC_EXIT_INVALID_CMDLINE; } } if (cmdline.toBool("audiotrack")) AudioTrackNo = cmdline.toInt("audiotrack"); if (cmdline.toBool("passthru")) passthru = true; CleanupGuard callCleanup(cleanup); #ifndef _WIN32 QList<int> signallist; signallist << SIGINT << SIGTERM << SIGSEGV << SIGABRT << SIGBUS << SIGFPE << SIGILL; SignalHandler handler(signallist); signal(SIGHUP, SIG_IGN); #endif // Load the context gContext = new MythContext(MYTH_BINARY_VERSION); if (!gContext->Init(false)) { LOG(VB_GENERAL, LOG_ERR, "Failed to init MythContext, exiting."); return GENERIC_EXIT_NO_MYTHCONTEXT; } MythTranslation::load("mythfrontend"); cmdline.ApplySettingsOverride(); if (jobID != -1) { if (JobQueue::GetJobInfoFromID(jobID, jobType, chanid, starttime)) { found_starttime = 1; found_chanid = 1; } else { cerr << "mythtranscode: ERROR: Unable to find DB info for " << "JobQueue ID# " << jobID << endl; return GENERIC_EXIT_NO_RECORDING_DATA; } } if (((!found_infile && !(found_chanid && found_starttime)) || (found_infile && (found_chanid || found_starttime))) && (!cmdline.toBool("hls"))) { cerr << "Must specify -i OR -c AND -s options!" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (isVideo && !found_infile && !cmdline.toBool("hls")) { cerr << "Must specify --infile to use --video" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (jobID >= 0 && (found_infile || build_index)) { cerr << "Can't specify -j with --buildindex, --video or --infile" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if ((jobID >= 0) && build_index) { cerr << "Can't specify both -j and --buildindex" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (keyframesonly && !fifodir.isEmpty()) { cerr << "Cannot specify both --fifodir and --allkeys" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (fifosync && fifodir.isEmpty()) { cerr << "Must specify --fifodir to use --fifosync" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (fifo_info && !fifodir.isEmpty()) { cerr << "Cannot specify both --fifodir and --fifoinfo" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (cleanCut && fifodir.isEmpty() && !fifo_info) { cerr << "Clean cutting works only in fifodir mode" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (cleanCut && !useCutlist) { cerr << "--cleancut is pointless without --honorcutlist" << endl; return GENERIC_EXIT_INVALID_CMDLINE; } if (fifo_info) { // Setup a dummy fifodir path, so that the "fifodir" code path // is taken. The path wont actually be used. fifodir = "DummyFifoPath"; } if (!MSqlQuery::testDBConnection()) { LOG(VB_GENERAL, LOG_ERR, "couldn't open db"); return GENERIC_EXIT_DB_ERROR; } ProgramInfo *pginfo = NULL; if (cmdline.toBool("hls")) { pginfo = new ProgramInfo(); } else if (isVideo) { // We want the absolute file path for the filemarkup table QFileInfo inf(infile); infile = inf.absoluteFilePath(); pginfo = new ProgramInfo(infile); } else if (!found_infile) { pginfo = new ProgramInfo(chanid, starttime); if (!pginfo->GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find recording for chanid %1 @ %2") .arg(chanid).arg(starttime.toString(Qt::ISODate))); delete pginfo; return GENERIC_EXIT_NO_RECORDING_DATA; } infile = pginfo->GetPlaybackURL(false, true); } else { pginfo = new ProgramInfo(infile); if (!pginfo->GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("Couldn't find a recording for filename '%1'") .arg(infile)); delete pginfo; return GENERIC_EXIT_NO_RECORDING_DATA; } } if (!pginfo) { LOG(VB_GENERAL, LOG_ERR, "No program info found!"); return GENERIC_EXIT_NO_RECORDING_DATA; } if (cmdline.toBool("queue")) { QString hostname = cmdline.toString("queue"); return QueueTranscodeJob(pginfo, profilename, hostname, useCutlist); } if (infile.left(7) == "myth://" && (outfile.isEmpty() || outfile != "-") && fifodir.isEmpty() && !cmdline.toBool("hls") && !cmdline.toBool("avf")) { LOG(VB_GENERAL, LOG_ERR, QString("Attempted to transcode %1. Mythtranscode is currently " "unable to transcode remote files.") .arg(infile)); return GENERIC_EXIT_REMOTE_FILE; } if (outfile.isEmpty() && !build_index && fifodir.isEmpty()) outfile = infile + ".tmp"; if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_RUNNING); Transcode *transcode = new Transcode(pginfo); if (!build_index) { if (cmdline.toBool("hlsstreamid")) LOG(VB_GENERAL, LOG_NOTICE, QString("Transcoding HTTP Live Stream ID %1") .arg(cmdline.toInt("hlsstreamid"))); else if (fifodir.isEmpty()) LOG(VB_GENERAL, LOG_NOTICE, QString("Transcoding from %1 to %2") .arg(infile).arg(outfile)); else LOG(VB_GENERAL, LOG_NOTICE, QString("Transcoding from %1 to FIFO") .arg(infile)); } if (cmdline.toBool("avf")) { transcode->SetAVFMode(); if (cmdline.toBool("container")) transcode->SetCMDContainer(cmdline.toString("container")); if (cmdline.toBool("acodec")) transcode->SetCMDAudioCodec(cmdline.toString("acodec")); if (cmdline.toBool("vcodec")) transcode->SetCMDVideoCodec(cmdline.toString("vcodec")); } else if (cmdline.toBool("hls")) { transcode->SetHLSMode(); if (cmdline.toBool("hlsstreamid")) transcode->SetHLSStreamID(cmdline.toInt("hlsstreamid")); if (cmdline.toBool("maxsegments")) transcode->SetHLSMaxSegments(cmdline.toInt("maxsegments")); if (cmdline.toBool("noaudioonly")) transcode->DisableAudioOnlyHLS(); } if (cmdline.toBool("avf") || cmdline.toBool("hls")) { if (cmdline.toBool("width")) transcode->SetCMDWidth(cmdline.toInt("width")); if (cmdline.toBool("height")) transcode->SetCMDHeight(cmdline.toInt("height")); if (cmdline.toBool("bitrate")) transcode->SetCMDBitrate(cmdline.toInt("bitrate") * 1000); if (cmdline.toBool("audiobitrate")) transcode->SetCMDAudioBitrate(cmdline.toInt("audiobitrate") * 1000); } if (showprogress) transcode->ShowProgress(true); if (!recorderOptions.isEmpty()) transcode->SetRecorderOptions(recorderOptions); int result = 0; if ((!mpeg2 && !build_index) || cmdline.toBool("hls")) { result = transcode->TranscodeFile(infile, outfile, profilename, useCutlist, (fifosync || keyframesonly), jobID, fifodir, fifo_info, cleanCut, deleteMap, AudioTrackNo, passthru); if ((result == REENCODE_OK) && (jobID >= 0)) JobQueue::ChangeJobArgs(jobID, "RENAME_TO_NUV"); } if (fifo_info) { delete transcode; return GENERIC_EXIT_OK; } int exitcode = GENERIC_EXIT_OK; if ((result == REENCODE_MPEG2TRANS) || mpeg2 || build_index) { void (*update_func)(float) = NULL; int (*check_func)() = NULL; if (useCutlist && !found_infile) pginfo->QueryCutList(deleteMap); if (jobID >= 0) { glbl_jobID = jobID; update_func = &UpdateJobQueue; check_func = &CheckJobQueue; } MPEG2fixup *m2f = new MPEG2fixup(infile, outfile, &deleteMap, NULL, false, false, 20, showprogress, otype, update_func, check_func); if (build_index) { int err = BuildKeyframeIndex(m2f, infile, posMap, jobID); if (err) return err; if (update_index) UpdatePositionMap(posMap, NULL, pginfo); else UpdatePositionMap(posMap, outfile + QString(".map"), pginfo); } else { result = m2f->Start(); if (result == REENCODE_OK) { result = BuildKeyframeIndex(m2f, outfile, posMap, jobID); if (result == REENCODE_OK) { if (update_index) UpdatePositionMap(posMap, NULL, pginfo); else UpdatePositionMap(posMap, outfile + QString(".map"), pginfo); } } } delete m2f; } if (result == REENCODE_OK) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_STOPPING); LOG(VB_GENERAL, LOG_NOTICE, QString("%1 %2 done") .arg(build_index ? "Building Index for" : "Transcoding") .arg(infile)); } else if (result == REENCODE_CUTLIST_CHANGE) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_RETRY); LOG(VB_GENERAL, LOG_NOTICE, QString("Transcoding %1 aborted because of cutlist update") .arg(infile)); exitcode = GENERIC_EXIT_RESTART; } else if (result == REENCODE_STOPPED) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_ABORTING); LOG(VB_GENERAL, LOG_NOTICE, QString("Transcoding %1 stopped because of stop command") .arg(infile)); exitcode = GENERIC_EXIT_KILLED; } else { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_ERRORING); LOG(VB_GENERAL, LOG_ERR, QString("Transcoding %1 failed").arg(infile)); exitcode = result; } if (jobID >= 0) CompleteJob(jobID, pginfo, useCutlist, &deleteMap, exitcode); transcode->deleteLater(); return exitcode; }
int preview_helper(uint chanid, QDateTime starttime, long long previewFrameNumber, long long previewSeconds, const QSize &previewSize, const QString &infile, const QString &outfile) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) LOG(VB_GENERAL, LOG_ERR, "Setting priority failed." + ENO); if (!chanid || !starttime.isValid()) ProgramInfo::QueryKeyFromPathname(infile, chanid, starttime); ProgramInfo *pginfo = NULL; if (chanid && starttime.isValid()) { pginfo = new ProgramInfo(chanid, starttime); if (!pginfo->GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("Cannot locate recording made on '%1' at '%2'") .arg(chanid).arg(starttime.toString(Qt::ISODate))); delete pginfo; return GENERIC_EXIT_NOT_OK; } pginfo->SetPathname(pginfo->GetPlaybackURL(false, true)); } else if (!infile.isEmpty()) { if (!QFileInfo(infile).isReadable()) { LOG(VB_GENERAL, LOG_ERR, QString("Cannot read this file '%1'").arg(infile)); return GENERIC_EXIT_NOT_OK; } pginfo = new ProgramInfo( infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/, 0/*season*/, 0/*episode*/, ""/*inetref*/, 120/*length_in_minutes*/, 1895/*year*/, ""/*id*/); } else { LOG(VB_GENERAL, LOG_ERR, "Cannot locate recording to preview"); return GENERIC_EXIT_NOT_OK; } PreviewGenerator *previewgen = new PreviewGenerator( pginfo, QString(), PreviewGenerator::kLocal); if (previewFrameNumber >= 0) previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); if (previewSeconds >= 0) previewgen->SetPreviewTimeAsSeconds(previewSeconds); previewgen->SetOutputSize(previewSize); previewgen->SetOutputFilename(outfile); bool ok = previewgen->RunReal(); previewgen->deleteLater(); delete pginfo; return (ok) ? GENERIC_EXIT_OK : GENERIC_EXIT_NOT_OK; }
DTC::ProgramGuide *Guide::GetProgramGuide( const QDateTime &rawStartTime , const QDateTime &rawEndTime , int nStartChanId, int nNumChannels, bool bDetails, int nChannelGroupId ) { if (!rawStartTime.isValid()) throw( "StartTime is invalid" ); if (!rawEndTime.isValid()) throw( "EndTime is invalid" ); QDateTime dtStartTime = rawStartTime.toUTC(); QDateTime dtEndTime = rawEndTime.toUTC(); if (dtEndTime < dtStartTime) throw( "EndTime is before StartTime"); if (nNumChannels == 0) nNumChannels = SHRT_MAX; // ---------------------------------------------------------------------- // Find the ending channel Id // ---------------------------------------------------------------------- int nEndChanId = nStartChanId; MSqlQuery query(MSqlQuery::InitCon()); query.prepare( "SELECT chanid FROM channel WHERE (chanid >= :STARTCHANID )" " ORDER BY chanid LIMIT :NUMCHAN" ); query.bindValue(":STARTCHANID", nStartChanId ); query.bindValue(":NUMCHAN" , nNumChannels ); if (!query.exec()) MythDB::DBError("Select ChanId", query); query.first(); nStartChanId = query.value(0).toInt(); query.last(); nEndChanId = query.value(0).toInt(); // ---------------------------------------------------------------------- // Build SQL statement for Program Listing // ---------------------------------------------------------------------- ProgramList progList; ProgramList schedList; MSqlBindings bindings; // lpad is to allow natural sorting of numbers QString sSQL; if (nChannelGroupId > 0) { sSQL = "LEFT JOIN channelgroup ON program.chanid = channelgroup.chanid " "WHERE channelgroup.grpid = :CHANGRPID AND "; bindings[":CHANGRPID" ] = nChannelGroupId; } else sSQL = "WHERE "; sSQL += "visible != 0 " "AND program.chanid >= :StartChanId " "AND program.chanid <= :EndChanId " "AND program.endtime >= :StartDate " "AND program.starttime <= :EndDate " "AND program.manualid = 0 " // Exclude programmes created purely for 'manual' recording schedules "ORDER BY LPAD(CAST(channum AS UNSIGNED), 10, 0), " " LPAD(channum, 10, 0), " " callsign, " " LPAD(program.chanid, 10, 0), " " program.starttime "; bindings[":StartChanId"] = nStartChanId; bindings[":EndChanId" ] = nEndChanId; bindings[":StartDate" ] = dtStartTime; bindings[":EndDate" ] = dtEndTime; // ---------------------------------------------------------------------- // Get all Pending Scheduled Programs // ---------------------------------------------------------------------- bool hasConflicts; LoadFromScheduler(schedList, hasConflicts); // ---------------------------------------------------------------------- LoadFromProgram( progList, sSQL, bindings, schedList ); // ---------------------------------------------------------------------- // Build Response // ---------------------------------------------------------------------- DTC::ProgramGuide *pGuide = new DTC::ProgramGuide(); int nChanCount = 0; uint nCurChanId = 0; DTC::ChannelInfo *pChannel = NULL; QString sCurCallsign; uint nSkipChanId = 0; for( uint n = 0; n < progList.size(); n++) { ProgramInfo *pInfo = progList[ n ]; if ( nSkipChanId == pInfo->GetChanID()) continue; if ( nCurChanId != pInfo->GetChanID() ) { nChanCount++; nCurChanId = pInfo->GetChanID(); // Filter out channels with the same callsign, keeping just the // first seen if (sCurCallsign == pInfo->GetChannelSchedulingID()) { nSkipChanId = pInfo->GetChanID(); continue; } pChannel = pGuide->AddNewChannel(); FillChannelInfo( pChannel, pInfo->GetChanID(), bDetails ); sCurCallsign = pChannel->CallSign(); } DTC::Program *pProgram = pChannel->AddNewProgram(); FillProgramInfo( pProgram, pInfo, false, bDetails, false ); // No cast info } // ---------------------------------------------------------------------- pGuide->setStartTime ( dtStartTime ); pGuide->setEndTime ( dtEndTime ); pGuide->setStartChanId ( nStartChanId ); pGuide->setEndChanId ( nEndChanId ); pGuide->setNumOfChannels( nChanCount ); pGuide->setDetails ( bDetails ); pGuide->setCount ( progList.size()); pGuide->setAsOf ( MythDate::current() ); pGuide->setVersion ( MYTH_BINARY_VERSION ); pGuide->setProtoVer ( MYTH_PROTO_VERSION ); return pGuide; }
DTC::LiveStreamInfo *Content::AddRecordingLiveStream( int nRecordedId, int nChanId, const QDateTime &recstarttsRaw, int nMaxSegments, int nWidth, int nHeight, int nBitrate, int nAudioBitrate, int nSampleRate ) { if ((nRecordedId <= 0) && (nChanId <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); // ------------------------------------------------------------------ // Read Recording From Database // ------------------------------------------------------------------ // TODO Should use RecordingInfo ProgramInfo pginfo; if (nRecordedId > 0) pginfo = ProgramInfo(nRecordedId); else pginfo = ProgramInfo(nChanId, recstarttsRaw.toUTC()); if (!pginfo.GetChanID()) { LOG(VB_UPNP, LOG_ERR, QString("AddRecordingLiveStream - for %1, %2 failed") .arg(QString::number(nRecordedId))); return NULL; } if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower()) { // We only handle requests for local resources QString sMsg = QString("GetRecording: Wrong Host '%1' request from '%2'.") .arg( gCoreContext->GetHostName()) .arg( pginfo.GetHostname() ); LOG(VB_UPNP, LOG_ERR, sMsg); throw HttpRedirectException( pginfo.GetHostname() ); } QString sFileName( GetPlaybackURL(&pginfo) ); // ---------------------------------------------------------------------- // check to see if the file exists // ---------------------------------------------------------------------- if (!QFile::exists( sFileName )) { LOG( VB_UPNP, LOG_ERR, QString("AddRecordingLiveStream - for %1, %2 failed") .arg( nChanId ) .arg( recstarttsRaw.toUTC().toString() )); return NULL; } QFileInfo fInfo( sFileName ); return AddLiveStream( pginfo.GetStorageGroup(), fInfo.fileName(), pginfo.GetHostname(), nMaxSegments, nWidth, nHeight, nBitrate, nAudioBitrate, nSampleRate ); }
QFileInfo Content::GetPreviewImage( int nRecordedId, int nChanId, const QDateTime &recstarttsRaw, int nWidth, int nHeight, int nSecsIn, const QString &sFormat ) { if ((nRecordedId <= 0) && (nChanId <= 0 || !recstarttsRaw.isValid())) throw QString("Recorded ID or Channel ID and StartTime appears invalid."); if (!sFormat.isEmpty() && !QImageWriter::supportedImageFormats().contains(sFormat.toLower().toLocal8Bit())) { throw "GetPreviewImage: Specified 'Format' is not supported."; } // ---------------------------------------------------------------------- // Read Recording From Database // ---------------------------------------------------------------------- // TODO Should use RecordingInfo ProgramInfo pginfo; if (nRecordedId > 0) pginfo = ProgramInfo(nRecordedId); else pginfo = ProgramInfo(nChanId, recstarttsRaw.toUTC()); if (!pginfo.GetChanID()) { LOG(VB_GENERAL, LOG_ERR, QString("GetPreviewImage: No recording for '%1'") .arg(nRecordedId)); return QFileInfo(); } if (pginfo.GetHostname().toLower() != gCoreContext->GetHostName().toLower()) { QString sMsg = QString("GetPreviewImage: Wrong Host '%1' request from '%2'") .arg( gCoreContext->GetHostName()) .arg( pginfo.GetHostname() ); LOG(VB_UPNP, LOG_ERR, sMsg); throw HttpRedirectException( pginfo.GetHostname() ); } QString sImageFormat = sFormat; if (sImageFormat.isEmpty()) sImageFormat = "PNG"; QString sFileName = GetPlaybackURL(&pginfo); // ---------------------------------------------------------------------- // check to see if default preview image is already created. // ---------------------------------------------------------------------- QString sPreviewFileName; if (nSecsIn <= 0) { nSecsIn = -1; sPreviewFileName = QString("%1.png").arg(sFileName); } else { sPreviewFileName = QString("%1.%2.png").arg(sFileName).arg(nSecsIn); } if (!QFile::exists( sPreviewFileName )) { // ------------------------------------------------------------------ // Must generate Preview Image, Generate Image and save. // ------------------------------------------------------------------ if (!pginfo.IsLocal() && sFileName.startsWith("/")) pginfo.SetPathname(sFileName); if (!pginfo.IsLocal()) return QFileInfo(); PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sPreviewFileName ); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); } bool bDefaultPixmap = (nWidth == 0) && (nHeight == 0); QString sNewFileName; if (bDefaultPixmap) sNewFileName = sPreviewFileName; else { sNewFileName = QString( "%1.%2.%3x%4.%5" ) .arg( sFileName ) .arg( nSecsIn ) .arg( nWidth == 0 ? -1 : nWidth ) .arg( nHeight == 0 ? -1 : nHeight ) .arg( sImageFormat.toLower() ); // ---------------------------------------------------------------------- // check to see if scaled preview image is already created and isn't // out of date // ---------------------------------------------------------------------- if (QFile::exists( sNewFileName )) { if (QFileInfo(sPreviewFileName).lastModified() <= QFileInfo(sNewFileName).lastModified()) return QFileInfo( sNewFileName ); } QImage image = QImage(sPreviewFileName); if (image.isNull()) return QFileInfo(); // We can just re-scale the default (full-size version) to avoid // a preview generator run if ( nWidth <= 0 ) image = image.scaledToHeight(nHeight, Qt::SmoothTransformation); else if ( nHeight <= 0 ) image = image.scaledToWidth(nWidth, Qt::SmoothTransformation); else image = image.scaled(nWidth, nHeight, Qt::IgnoreAspectRatio, Qt::SmoothTransformation); image.save(sNewFileName, sImageFormat.toUpper().toLocal8Bit()); // Let anybody update it bool ret = makeFileAccessible(sNewFileName.toLocal8Bit().constData()); if (!ret) { LOG(VB_GENERAL, LOG_ERR, "Unable to change permissions on " "preview image. Backends and frontends " "running under different users will be " "unable to access it"); } } if (QFile::exists( sNewFileName )) return QFileInfo( sNewFileName ); PreviewGenerator *previewgen = new PreviewGenerator( &pginfo, QString(), PreviewGenerator::kLocal); previewgen->SetPreviewTimeAsSeconds( nSecsIn ); previewgen->SetOutputFilename ( sNewFileName ); previewgen->SetOutputSize (QSize(nWidth,nHeight)); bool ok = previewgen->Run(); previewgen->deleteLater(); if (!ok) return QFileInfo(); return QFileInfo( sNewFileName ); }
void StatusBox::customEvent(QEvent *event) { if (event->type() == DialogCompletionEvent::kEventType) { DialogCompletionEvent *dce = (DialogCompletionEvent*)(event); QString resultid = dce->GetId(); int buttonnum = dce->GetResult(); if (resultid == "LogAck") { if (buttonnum == 1) { QString sql = dce->GetData().toString(); MSqlQuery query(MSqlQuery::InitCon()); query.prepare("UPDATE mythlog SET acknowledged = 1 " "WHERE logid = :LOGID ;"); query.bindValue(":LOGID", sql); if (!query.exec()) MythDB::DBError("StatusBox::customEvent -- LogAck", query); m_logList->RemoveItem(m_logList->GetItemCurrent()); } } else if (resultid == "LogAckAll") { if (buttonnum == 1) { MSqlQuery query(MSqlQuery::InitCon()); query.prepare("UPDATE mythlog SET acknowledged = 1 " "WHERE priority <= :PRIORITY ;"); query.bindValue(":PRIORITY", m_minLevel); if (!query.exec()) MythDB::DBError("StatusBox::customEvent -- LogAckAll", query); doLogEntries(); } } else if (resultid == "JobDelete") { if (buttonnum == 1) { int jobID = dce->GetData().toInt(); JobQueue::DeleteJob(jobID); m_logList->RemoveItem(m_logList->GetItemCurrent()); } } else if (resultid == "JobRequeue") { if (buttonnum == 1) { int jobID = dce->GetData().toInt(); JobQueue::ChangeJobStatus(jobID, JOB_QUEUED); doJobQueueStatus(); } } else if (resultid == "JobModify") { int jobID = dce->GetData().toInt(); if (buttonnum == 0) { if (JobQueue::GetJobStatus(jobID) == JOB_PAUSED) JobQueue::ResumeJob(jobID); else JobQueue::PauseJob(jobID); } else if (buttonnum == 1) { JobQueue::StopJob(jobID); } doJobQueueStatus(); } else if (resultid == "AutoExpireManage") { ProgramInfo* rec = qVariantValue<ProgramInfo*>(dce->GetData()); // button 2 is "No Change" if (!rec || buttonnum == 2) return; // button 1 is "Delete Now" if ((buttonnum == 0) && rec->QueryIsDeleteCandidate()) { if (!RemoteDeleteRecording( rec->GetChanID(), rec->GetRecordingStartTime(), false, false)) { LOG(VB_GENERAL, LOG_ERR, QString("Failed to delete recording: %1").arg(rec->GetTitle())); return; } } // button 1 is "Move To Default Group" or "UnDelete" or "Disable AutoExpire" else if (buttonnum == 1) { if ((rec)->GetRecordingGroup() == "Deleted") { RemoteUndeleteRecording( rec->GetChanID(), rec->GetRecordingStartTime()); } else { rec->SaveAutoExpire(kDisableAutoExpire); if ((rec)->GetRecordingGroup() == "LiveTV") { RecordingInfo ri(*rec); ri.ApplyRecordRecGroupChange("Default"); *rec = ri; } } } // remove the changed recording from the expire list delete m_expList[m_logList->GetCurrentPos()]; m_expList.erase(m_expList.begin() + m_logList->GetCurrentPos()); int pos = m_logList->GetCurrentPos(); int topPos = m_logList->GetTopItemPos(); doAutoExpireList(false); m_logList->SetItemCurrent(pos, topPos); } } }
/** \fn LiveTVChain::ProgramIsAt(const ProgramInfo&) const * \returns program location or -1 for not found. */ int LiveTVChain::ProgramIsAt(const ProgramInfo &pginfo) const { return ProgramIsAt(pginfo.GetChanID(), pginfo.GetRecordingStartTime()); }
int main(int argc, char *argv[]) { uint chanid; QString starttime, infile, outfile; QString profilename = QString("autodetect"); QString fifodir = NULL; int jobID = -1; QDateTime startts; int jobType = JOB_NONE; int otype = REPLEX_MPEG2; bool useCutlist = false, keyframesonly = false; bool build_index = false, fifosync = false, showprogress = false, mpeg2 = false; QMap<QString, QString> settingsOverride; frm_dir_map_t deleteMap; frm_pos_map_t posMap; srand(time(NULL)); int AudioTrackNo = -1; QCoreApplication a(argc, argv); QCoreApplication::setApplicationName(MYTH_APPNAME_MYTHTRANSCODE); print_verbose_messages = VB_IMPORTANT; verboseString = "important"; int found_starttime = 0; int found_chanid = 0; int found_infile = 0; int update_index = 1; int isVideo = 0; bool passthru = false; for (int argpos = 1; argpos < a.argc(); ++argpos) { if (!strcmp(a.argv()[argpos],"-s") || !strcmp(a.argv()[argpos],"--starttime")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { starttime = a.argv()[argpos + 1]; found_starttime = 1; ++argpos; } else { cerr << "Missing argument to -s/--starttime option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-c") || !strcmp(a.argv()[argpos],"--chanid")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { chanid = QString(a.argv()[argpos + 1]).toUInt(); found_chanid = 1; ++argpos; } else { cerr << "Missing argument to -c/--chanid option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos], "-j")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { jobID = QString(a.argv()[++argpos]).toInt(); } else { cerr << "Missing argument to -j option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-i") || !strcmp(a.argv()[argpos],"--infile")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { infile = a.argv()[argpos + 1]; found_infile = 1; ++argpos; } else { cerr << "Missing argument to -i/--infile option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"--video")) { isVideo = 1; //mpeg2 = true; } else if (!strcmp(a.argv()[argpos],"-o") || !strcmp(a.argv()[argpos],"--outfile")) { if ((a.argc()-1 > argpos) && (a.argv()[argpos+1][0] != '-' || a.argv()[argpos+1][1] == 0x0)) { outfile = a.argv()[argpos + 1]; update_index = 0; ++argpos; } else { cerr << "Missing argument to -o/--outfile option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-V")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { QString temp = a.argv()[++argpos]; print_verbose_messages = temp.toUInt(); } else { cerr << "Missing argument to -V option\n"; return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-v") || !strcmp(a.argv()[argpos],"--verbose")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { if (parse_verbose_arg(a.argv()[argpos+1]) == GENERIC_EXIT_INVALID_CMDLINE) return GENERIC_EXIT_INVALID_CMDLINE; ++argpos; } else { cerr << "Missing argument to -v/--verbose option\n"; return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-p") || !strcmp(a.argv()[argpos],"--profile")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { profilename = a.argv()[argpos + 1]; ++argpos; } else { cerr << "Missing argument to -p/--profile option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-l") || !strcmp(a.argv()[argpos],"--honorcutlist")) { useCutlist = true; if (!found_infile) continue; if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { QStringList cutlist = QString(a.argv()[argpos + 1]) .split(" ", QString::SkipEmptyParts); ++argpos; for (QStringList::Iterator it = cutlist.begin(); it != cutlist.end(); ++it ) { QStringList startend = (*it) .split("-", QString::SkipEmptyParts); if (startend.count() == 2) { cerr << "Cutting from: " << startend.first().toULongLong() << " to: " << startend.last().toULongLong() <<"\n"; deleteMap[startend.first().toULongLong()] = MARK_CUT_START; deleteMap[startend.last().toULongLong()] = MARK_CUT_END; } } } else { cerr << "Missing argument to -l/--honorcutlist option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"--inversecut")) { useCutlist = true; if (!found_infile) { cerr << "--inversecut option can only be used with --infile\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { uint64_t last = 0; QStringList cutlist = QString(a.argv()[argpos + 1]) .split(" ", QString::SkipEmptyParts); ++argpos; deleteMap[0] = MARK_CUT_START; for (QStringList::Iterator it = cutlist.begin(); it != cutlist.end(); ++it ) { QStringList startend = (*it).split( "-", QString::SkipEmptyParts); if (startend.count() == 2) { cerr << "Cutting from: " << last << " to: " << startend.first().toULongLong() <<"\n"; deleteMap[startend.first().toULongLong()] = MARK_CUT_END; deleteMap[startend.last().toULongLong()] = MARK_CUT_START; last = startend.last().toInt(); } } cerr << "Cutting from: " << last << " to the end\n"; deleteMap[999999999] = MARK_CUT_END; } else { cerr << "Missing argument to --inversecut option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-k") || !strcmp(a.argv()[argpos],"--allkeys")) { keyframesonly = true; } else if (!strcmp(a.argv()[argpos],"-b") || !strcmp(a.argv()[argpos],"--buildindex")) { build_index = true; } else if (!strcmp(a.argv()[argpos],"-f") || !strcmp(a.argv()[argpos],"--fifodir")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { fifodir = a.argv()[argpos + 1]; ++argpos; } else { cerr << "Missing argument to -f/--fifodir option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-ro") || !strcmp(a.argv()[argpos],"--recorderOptions")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { recorderOptions = a.argv()[argpos + 1]; ++argpos; } else { cerr << "Missing argument to -ro/--recorderOptions option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"--fifosync")) { fifosync = true; } else if (!strcmp(a.argv()[argpos],"--showprogress")) { showprogress = true; } else if (!strcmp(a.argv()[argpos],"-m") || !strcmp(a.argv()[argpos],"--mpeg2")) { mpeg2 = true; } else if (!strcmp(a.argv()[argpos],"-e") || !strcmp(a.argv()[argpos],"--ostream")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { if(!strcmp(a.argv()[argpos + 1], "dvd")) otype = REPLEX_DVD; if(!strcmp(a.argv()[argpos + 1], "ts")) otype = REPLEX_TS_SD; ++argpos; } else { cerr << "Missing argument to -e/--ostream option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } else if (!strcmp(a.argv()[argpos],"-O") || !strcmp(a.argv()[argpos],"--override-setting")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { QStringList pairs = QString(a.argv()[argpos+1]).split( ",", QString::SkipEmptyParts); for (int index = 0; index < pairs.size(); ++index) { QStringList tokens = pairs[index].split( "=", QString::SkipEmptyParts); tokens[0].replace(QRegExp("^[\"']"), ""); tokens[0].replace(QRegExp("[\"']$"), ""); tokens[1].replace(QRegExp("^[\"']"), ""); tokens[1].replace(QRegExp("[\"']$"), ""); settingsOverride[tokens[0]] = tokens[1]; } } else { cerr << "Invalid or missing argument to -O/--override-setting " "option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } ++argpos; } else if (!strcmp(a.argv()[argpos],"--audiotrack")) { if (a.argc()-1 > argpos && a.argv()[argpos+1][0] != '-') { AudioTrackNo = QString(a.argv()[argpos + 1]).toInt(); } else { cerr << "Invalid or missing argument to --audiotrack " "option\n"; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } ++argpos; } else if (!strcmp(a.argv()[argpos],"-h") || !strcmp(a.argv()[argpos],"--help")) { usage(a.argv()[0]); return GENERIC_EXIT_OK; } else if (!strcmp(a.argv()[argpos],"--passthrough")) { passthru = true; } else { cerr << "Unknown option: " << a.argv()[argpos] << endl; usage(a.argv()[0]); return GENERIC_EXIT_INVALID_CMDLINE; } } if (outfile == "-") print_verbose_messages = VB_NONE; // Load the context gContext = new MythContext(MYTH_BINARY_VERSION); if (!gContext->Init(false)) { VERBOSE(VB_IMPORTANT, "Failed to init MythContext, exiting."); return GENERIC_EXIT_NO_MYTHCONTEXT; } MythTranslation::load("mythfrontend"); if (settingsOverride.size()) { QMap<QString, QString>::iterator it; for (it = settingsOverride.begin(); it != settingsOverride.end(); ++it) { VERBOSE(VB_IMPORTANT, QString("Setting '%1' being forced to '%2'") .arg(it.key()).arg(*it)); gCoreContext->OverrideSettingForSession(it.key(), *it); } } if (jobID != -1) { if (JobQueue::GetJobInfoFromID( jobID, jobType, chanid, startts)) { starttime = startts.toString(Qt::ISODate); found_starttime = 1; found_chanid = 1; } else { cerr << "mythtranscode: ERROR: Unable to find DB info for " << "JobQueue ID# " << jobID << endl; return GENERIC_EXIT_NO_RECORDING_DATA; } } if ((! found_infile && !(found_chanid && found_starttime)) || (found_infile && (found_chanid || found_starttime)) ) { cerr << "Must specify -i OR -c AND -s options!\n"; return GENERIC_EXIT_INVALID_CMDLINE; } if (isVideo && !found_infile) { cerr << "Must specify --infile to use --video\n"; return GENERIC_EXIT_INVALID_CMDLINE; } if (jobID >= 0 && (found_infile || build_index)) { cerr << "Can't specify -j with --buildindex, --video or --infile\n"; return GENERIC_EXIT_INVALID_CMDLINE; } if ((jobID >= 0) && build_index) { cerr << "Can't specify both -j and --buildindex\n"; return GENERIC_EXIT_INVALID_CMDLINE; } if (keyframesonly && !fifodir.isEmpty()) { cerr << "Cannot specify both --fifodir and --allkeys\n"; return GENERIC_EXIT_INVALID_CMDLINE; } if (fifosync && fifodir.isEmpty()) { cerr << "Must specify --fifodir to use --fifosync\n"; return GENERIC_EXIT_INVALID_CMDLINE; } VERBOSE(VB_IMPORTANT, QString("Enabled verbose msgs: %1").arg(verboseString)); if (!MSqlQuery::testDBConnection()) { printf("couldn't open db\n"); return GENERIC_EXIT_DB_ERROR; } ProgramInfo *pginfo = NULL; if (isVideo) { // We want the absolute file path for the filemarkup table QFileInfo inf(infile); infile = inf.absoluteFilePath(); pginfo = new ProgramInfo(infile); } else if (!found_infile) { QDateTime recstartts = myth_dt_from_string(starttime); pginfo = new ProgramInfo(chanid, recstartts); if (!pginfo->GetChanID()) { QString msg = QString("Couldn't find recording for chanid %1 @ %2") .arg(chanid).arg(starttime); cerr << msg.toLocal8Bit().constData() << endl; delete pginfo; return GENERIC_EXIT_NO_RECORDING_DATA; } infile = pginfo->GetPlaybackURL(false, true); } else { pginfo = new ProgramInfo(infile); if (!pginfo->GetChanID()) { VERBOSE(VB_IMPORTANT, QString("Couldn't find a recording for filename '%1'") .arg(infile)); delete pginfo; pginfo = NULL; } } if (infile.left(7) == "myth://" && (outfile.isNull() || outfile != "-")) { VERBOSE(VB_IMPORTANT, QString("Attempted to transcode %1. " "Mythtranscode is currently unable to transcode remote " "files.") .arg(infile)); return GENERIC_EXIT_REMOTE_FILE; } if (outfile.isNull() && !build_index) outfile = infile + ".tmp"; if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_RUNNING); Transcode *transcode = new Transcode(pginfo); if (!build_index) VERBOSE(VB_GENERAL, QString("Transcoding from %1 to %2") .arg(infile).arg(outfile)); if (showprogress) transcode->ShowProgress(true); if (!recorderOptions.isEmpty()) transcode->SetRecorderOptions(recorderOptions); int result = 0; if (!mpeg2 && !build_index) { result = transcode->TranscodeFile(infile, outfile, profilename, useCutlist, (fifosync || keyframesonly), jobID, fifodir, deleteMap, AudioTrackNo, passthru); if ((result == REENCODE_OK) && (jobID >= 0)) JobQueue::ChangeJobArgs(jobID, "RENAME_TO_NUV"); } int exitcode = GENERIC_EXIT_OK; if ((result == REENCODE_MPEG2TRANS) || mpeg2 || build_index) { void (*update_func)(float) = NULL; int (*check_func)() = NULL; if (useCutlist && !found_infile) pginfo->QueryCutList(deleteMap); if (jobID >= 0) { glbl_jobID = jobID; update_func = &UpdateJobQueue; check_func = &CheckJobQueue; } MPEG2fixup *m2f = new MPEG2fixup( infile, outfile, &deleteMap, NULL, false, false, 20, showprogress, otype, update_func, check_func); if (build_index) { int err = BuildKeyframeIndex(m2f, infile, posMap, jobID); if (err) return err; if (update_index) UpdatePositionMap(posMap, NULL, pginfo); else UpdatePositionMap(posMap, outfile + QString(".map"), pginfo); } else { result = m2f->Start(); if (result == REENCODE_OK) { result = BuildKeyframeIndex(m2f, outfile, posMap, jobID); if (result == REENCODE_OK) { if (update_index) UpdatePositionMap(posMap, NULL, pginfo); else UpdatePositionMap(posMap, outfile + QString(".map"), pginfo); } } } delete m2f; } if (result == REENCODE_OK) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_STOPPING); VERBOSE(VB_GENERAL, QString("%1 %2 done") .arg(build_index ? "Building Index for" : "Transcoding") .arg(infile)); } else if (result == REENCODE_CUTLIST_CHANGE) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_RETRY); VERBOSE(VB_GENERAL, QString("Transcoding %1 aborted because of " "cutlist update").arg(infile)); exitcode = GENERIC_EXIT_RESTART; } else if (result == REENCODE_STOPPED) { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_ABORTING); VERBOSE(VB_GENERAL, QString("Transcoding %1 stopped because of " "stop command").arg(infile)); exitcode = GENERIC_EXIT_KILLED; } else { if (jobID >= 0) JobQueue::ChangeJobStatus(jobID, JOB_ERRORING); VERBOSE(VB_GENERAL, QString("Transcoding %1 failed").arg(infile)); exitcode = result; } if (jobID >= 0) CompleteJob(jobID, pginfo, useCutlist, &deleteMap, exitcode); transcode->deleteLater(); delete gContext; return exitcode; }
int preview_helper(const QString &_chanid, const QString &starttime, long long previewFrameNumber, long long previewSeconds, const QSize &previewSize, const QString &infile, const QString &outfile) { // Lower scheduling priority, to avoid problems with recordings. if (setpriority(PRIO_PROCESS, 0, 9)) VERBOSE(VB_GENERAL, "Setting priority failed." + ENO); uint chanid = _chanid.toUInt(); QDateTime recstartts = myth_dt_from_string(starttime); if (!chanid || !recstartts.isValid()) ProgramInfo::ExtractKeyFromPathname(infile, chanid, recstartts); ProgramInfo *pginfo = NULL; if (chanid && recstartts.isValid()) { pginfo = new ProgramInfo(chanid, recstartts); if (!pginfo->GetChanID()) { VERBOSE(VB_IMPORTANT, QString( "Cannot locate recording made on '%1' at '%2'") .arg(chanid).arg(starttime)); delete pginfo; return PREVIEWGEN_EXIT_NOT_OK; } pginfo->SetPathname(pginfo->GetPlaybackURL(false, true)); } else if (!infile.isEmpty()) { if (!QFileInfo(infile).isReadable()) { VERBOSE(VB_IMPORTANT, QString( "Cannot read this file '%1'").arg(infile)); return PREVIEWGEN_EXIT_NOT_OK; } pginfo = new ProgramInfo( infile, ""/*plot*/, ""/*title*/, ""/*subtitle*/, ""/*director*/, 0/*season*/, 0/*episode*/, 120/*length_in_minutes*/, 1895/*year*/); } else { VERBOSE(VB_IMPORTANT, "Cannot locate recording to preview"); return PREVIEWGEN_EXIT_NOT_OK; } PreviewGenerator *previewgen = new PreviewGenerator( pginfo, QString(), PreviewGenerator::kLocal); if (previewFrameNumber >= 0) previewgen->SetPreviewTimeAsFrameNumber(previewFrameNumber); if (previewSeconds >= 0) previewgen->SetPreviewTimeAsSeconds(previewSeconds); previewgen->SetOutputSize(previewSize); previewgen->SetOutputFilename(outfile); bool ok = previewgen->RunReal(); previewgen->deleteLater(); delete pginfo; return (ok) ? PREVIEWGEN_EXIT_OK : PREVIEWGEN_EXIT_NOT_OK; }