|
MythTV
0.26-pre
|
00001 #include <algorithm> 00002 using namespace std; 00003 00004 #include "mythcorecontext.h" 00005 00006 #include <QCoreApplication> 00007 00008 #include "tvbrowsehelper.h" 00009 #include "playercontext.h" 00010 #include "remoteencoder.h" 00011 #include "recordinginfo.h" 00012 #include "mythplayer.h" 00013 #include "cardutil.h" 00014 #include "tv_play.h" 00015 #include "mythlogging.h" 00016 00017 #define LOC QString("BH: ") 00018 00019 #define GetPlayer(X,Y) GetPlayerHaveLock(X, Y, __FILE__ , __LINE__) 00020 #define GetOSDLock(X) GetOSDL(X, __FILE__, __LINE__) 00021 00022 static void format_time(int seconds, QString &tMin, QString &tHrsMin) 00023 { 00024 int minutes = seconds / 60; 00025 int hours = minutes / 60; 00026 int min = minutes % 60; 00027 00028 tMin = TV::tr("%n minute(s)", "", minutes); 00029 tHrsMin.sprintf("%d:%02d", hours, min); 00030 } 00031 00032 TVBrowseHelper::TVBrowseHelper( 00033 TV *tv, 00034 QString time_format, 00035 QString short_date_format, 00036 uint browse_max_forward, 00037 bool browse_all_tuners, 00038 bool use_channel_groups, 00039 QString db_channel_ordering) : 00040 MThread("TVBrowseHelper"), 00041 m_tv(tv), 00042 db_time_format(time_format), 00043 db_short_date_format(short_date_format), 00044 db_browse_max_forward(browse_max_forward), 00045 db_browse_all_tuners(browse_all_tuners), 00046 db_use_channel_groups(use_channel_groups), 00047 m_ctx(NULL), 00048 m_chanid(0), 00049 m_run(true) 00050 { 00051 db_all_channels = ChannelUtil::GetChannels( 00052 0, true, "channum, callsign"); 00053 ChannelUtil::SortChannels( 00054 db_all_channels, db_channel_ordering, false); 00055 00056 DBChanList::const_iterator it = db_all_channels.begin(); 00057 for (; it != db_all_channels.end(); ++it) 00058 { 00059 db_chanid_to_channum[(*it).chanid] = (*it).channum; 00060 db_chanid_to_sourceid[(*it).chanid] = (*it).sourceid; 00061 db_channum_to_chanids.insert((*it).channum,(*it).chanid); 00062 } 00063 00064 db_all_visible_channels = ChannelUtil::GetChannels( 00065 0, true, "channum, callsign"); 00066 ChannelUtil::SortChannels( 00067 db_all_visible_channels, db_channel_ordering, false); 00068 00069 start(); 00070 } 00071 00072 00075 bool TVBrowseHelper::BrowseStart(PlayerContext *ctx, bool skip_browse) 00076 { 00077 if (!gCoreContext->IsUIThread()) 00078 return false; 00079 00080 QMutexLocker locker(&m_lock); 00081 00082 if (m_ctx) 00083 return m_ctx == ctx; 00084 00085 m_tv->ClearOSD(ctx); 00086 00087 ctx->LockPlayingInfo(__FILE__, __LINE__); 00088 if (ctx->playingInfo) 00089 { 00090 m_ctx = ctx; 00091 m_channum = ctx->playingInfo->GetChanNum(); 00092 m_chanid = ctx->playingInfo->GetChanID(); 00093 m_starttime = ctx->playingInfo->GetScheduledStartTime(ISODate); 00094 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00095 00096 if (!skip_browse) 00097 { 00098 BrowseInfo bi(BROWSE_SAME, m_channum, m_chanid, m_starttime); 00099 locker.unlock(); 00100 BrowseDispInfo(ctx, bi); 00101 } 00102 return true; 00103 } 00104 else 00105 { 00106 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 00107 return false; 00108 } 00109 } 00110 00117 void TVBrowseHelper::BrowseEnd(PlayerContext *ctx, bool change_channel) 00118 { 00119 if (!gCoreContext->IsUIThread()) 00120 return; 00121 00122 QMutexLocker locker(&m_lock); 00123 00124 if (ctx && m_ctx != ctx) 00125 return; 00126 00127 if (!m_ctx) 00128 return; 00129 00130 { 00131 QMutexLocker locker(&m_tv->timerIdLock); 00132 if (m_tv->browseTimerId) 00133 { 00134 m_tv->KillTimer(m_tv->browseTimerId); 00135 m_tv->browseTimerId = 0; 00136 } 00137 } 00138 00139 m_list.clear(); 00140 m_wait.wakeAll(); 00141 00142 OSD *osd = m_tv->GetOSDLock(ctx); 00143 if (osd) 00144 osd->HideWindow("browse_info"); 00145 m_tv->ReturnOSDLock(ctx, osd); 00146 00147 if (change_channel) 00148 m_tv->ChangeChannel(ctx, 0, m_channum); 00149 00150 m_ctx = NULL; 00151 } 00152 00153 void TVBrowseHelper::BrowseDispInfo(PlayerContext *ctx, BrowseInfo &bi) 00154 { 00155 if (!gCoreContext->IsUIThread()) 00156 return; 00157 00158 if (!BrowseStart(ctx, true)) 00159 return; 00160 00161 { 00162 QMutexLocker locker(&m_tv->timerIdLock); 00163 if (m_tv->browseTimerId) 00164 { 00165 m_tv->KillTimer(m_tv->browseTimerId); 00166 m_tv->browseTimerId = 00167 m_tv->StartTimer(TV::kBrowseTimeout, __LINE__); 00168 } 00169 } 00170 00171 QMutexLocker locker(&m_lock); 00172 if (BROWSE_SAME == bi.m_dir) 00173 m_list.clear(); 00174 m_list.push_back(bi); 00175 m_wait.wakeAll(); 00176 } 00177 00178 void TVBrowseHelper::BrowseChannel(PlayerContext *ctx, const QString &channum) 00179 { 00180 if (!gCoreContext->IsUIThread()) 00181 return; 00182 00183 if (db_browse_all_tuners) 00184 { 00185 BrowseInfo bi(channum, 0); 00186 BrowseDispInfo(ctx, bi); 00187 return; 00188 } 00189 00190 if (!ctx->recorder || !ctx->last_cardid) 00191 return; 00192 00193 QString inputname = ctx->recorder->GetInput(); 00194 uint inputid = CardUtil::GetInputID(ctx->last_cardid, inputname); 00195 uint sourceid = CardUtil::GetSourceID(inputid); 00196 if (sourceid) 00197 { 00198 BrowseInfo bi(channum, sourceid); 00199 BrowseDispInfo(ctx, bi); 00200 } 00201 } 00202 00203 BrowseInfo TVBrowseHelper::GetBrowsedInfo(void) const 00204 { 00205 QMutexLocker locker(&m_lock); 00206 BrowseInfo bi(BROWSE_SAME); 00207 if (m_ctx != NULL) 00208 { 00209 bi.m_channum = m_channum; 00210 bi.m_chanid = m_chanid; 00211 bi.m_starttime = m_starttime; 00212 } 00213 return bi; 00214 } 00215 00219 bool TVBrowseHelper::IsBrowsing(void) const 00220 { 00221 if (!gCoreContext->IsUIThread()) 00222 return true; 00223 00224 return m_ctx != NULL; 00225 } 00226 00234 uint TVBrowseHelper::GetChanId( 00235 const QString &channum, uint pref_cardid, uint pref_sourceid) const 00236 { 00237 if (pref_sourceid) 00238 { 00239 DBChanList::const_iterator it = db_all_channels.begin(); 00240 for (; it != db_all_channels.end(); ++it) 00241 { 00242 if ((*it).sourceid == pref_sourceid && (*it).channum == channum) 00243 return (*it).chanid; 00244 } 00245 } 00246 00247 if (pref_cardid) 00248 { 00249 DBChanList::const_iterator it = db_all_channels.begin(); 00250 for (; it != db_all_channels.end(); ++it) 00251 { 00252 if ((*it).cardid == pref_cardid && (*it).channum == channum) 00253 return (*it).chanid; 00254 } 00255 } 00256 00257 if (db_browse_all_tuners) 00258 { 00259 DBChanList::const_iterator it = db_all_channels.begin(); 00260 for (; it != db_all_channels.end(); ++it) 00261 { 00262 if ((*it).channum == channum) 00263 return (*it).chanid; 00264 } 00265 } 00266 00267 return 0; 00268 } 00269 00276 void TVBrowseHelper::GetNextProgram( 00277 BrowseDirection direction, InfoMap &infoMap) const 00278 { 00279 if (!m_ctx->recorder) 00280 return; 00281 00282 QString title, subtitle, desc, category, endtime, callsign, iconpath; 00283 QDateTime begts, endts; 00284 00285 QString starttime = infoMap["dbstarttime"]; 00286 QString chanid = infoMap["chanid"]; 00287 QString channum = infoMap["channum"]; 00288 QString seriesid = infoMap["seriesid"]; 00289 QString programid = infoMap["programid"]; 00290 00291 m_ctx->recorder->GetNextProgram( 00292 direction, 00293 title, subtitle, desc, category, 00294 starttime, endtime, callsign, iconpath, 00295 channum, chanid, seriesid, programid); 00296 00297 if (!starttime.isEmpty()) 00298 begts = QDateTime::fromString(starttime, Qt::ISODate); 00299 else 00300 begts = QDateTime::fromString(infoMap["dbstarttime"], Qt::ISODate); 00301 00302 infoMap["starttime"] = begts.toString(db_time_format); 00303 infoMap["startdate"] = begts.toString(db_short_date_format); 00304 00305 infoMap["endtime"] = infoMap["enddate"] = ""; 00306 if (!endtime.isEmpty()) 00307 { 00308 endts = QDateTime::fromString(endtime, Qt::ISODate); 00309 infoMap["endtime"] = endts.toString(db_time_format); 00310 infoMap["enddate"] = endts.toString(db_short_date_format); 00311 } 00312 00313 infoMap["lenmins"] = TV::tr("%n minute(s)", "", 0); 00314 infoMap["lentime"] = "0:00"; 00315 if (begts.isValid() && endts.isValid()) 00316 { 00317 QString lenM, lenHM; 00318 format_time(begts.secsTo(endts), lenM, lenHM); 00319 infoMap["lenmins"] = lenM; 00320 infoMap["lentime"] = lenHM; 00321 } 00322 00323 infoMap["dbstarttime"] = starttime; 00324 infoMap["dbendtime"] = endtime; 00325 infoMap["title"] = title; 00326 infoMap["subtitle"] = subtitle; 00327 infoMap["description"] = desc; 00328 infoMap["category"] = category; 00329 infoMap["callsign"] = callsign; 00330 infoMap["channum"] = channum; 00331 infoMap["chanid"] = chanid; 00332 infoMap["iconpath"] = iconpath; 00333 infoMap["seriesid"] = seriesid; 00334 infoMap["programid"] = programid; 00335 } 00336 00337 void TVBrowseHelper::GetNextProgramDB( 00338 BrowseDirection direction, InfoMap &infoMap) const 00339 { 00340 uint chanid = infoMap["chanid"].toUInt(); 00341 if (!chanid) 00342 { 00343 LOG(VB_GENERAL, LOG_ERR, LOC + "GetNextProgramDB() requires a chanid"); 00344 return; 00345 } 00346 00347 int chandir = -1; 00348 switch (direction) 00349 { 00350 case BROWSE_UP: chandir = CHANNEL_DIRECTION_UP; break; 00351 case BROWSE_DOWN: chandir = CHANNEL_DIRECTION_DOWN; break; 00352 case BROWSE_FAVORITE: chandir = CHANNEL_DIRECTION_FAVORITE; break; 00353 } 00354 if (chandir != -1) 00355 { 00356 chanid = ChannelUtil::GetNextChannel( 00357 db_all_visible_channels, chanid, 0 /*mplexid_restriction*/, 00358 chandir, true /*skip non visible*/, true /*skip same callsign*/); 00359 } 00360 00361 infoMap["chanid"] = QString::number(chanid); 00362 infoMap["channum"] = db_chanid_to_channum[chanid]; 00363 00364 QDateTime nowtime = QDateTime::currentDateTime(); 00365 QDateTime latesttime = nowtime.addSecs(6*60*60); 00366 QDateTime browsetime = QDateTime::fromString( 00367 infoMap["dbstarttime"], Qt::ISODate); 00368 00369 MSqlBindings bindings; 00370 bindings[":CHANID"] = chanid; 00371 bindings[":NOWTS"] = nowtime; 00372 bindings[":LATESTTS"] = latesttime; 00373 bindings[":BROWSETS"] = browsetime; 00374 bindings[":BROWSETS2"] = browsetime; 00375 00376 QString querystr = " WHERE program.chanid = :CHANID "; 00377 switch (direction) 00378 { 00379 case BROWSE_LEFT: 00380 querystr += " AND program.endtime <= :BROWSETS " 00381 " AND program.endtime > :NOWTS "; 00382 break; 00383 00384 case BROWSE_RIGHT: 00385 querystr += " AND program.starttime > :BROWSETS " 00386 " AND program.starttime < :LATESTTS "; 00387 break; 00388 00389 default: 00390 querystr += " AND program.starttime <= :BROWSETS " 00391 " AND program.endtime > :BROWSETS2 "; 00392 }; 00393 00394 ProgramList progList; 00395 ProgramList dummySched; 00396 LoadFromProgram(progList, querystr, bindings, dummySched); 00397 00398 if (progList.empty()) 00399 { 00400 infoMap["dbstarttime"] = ""; 00401 return; 00402 } 00403 00404 const ProgramInfo *prog = (direction == BROWSE_LEFT) ? 00405 progList[progList.size() - 1] : progList[0]; 00406 00407 infoMap["dbstarttime"] = prog->GetScheduledStartTime(ISODate); 00408 } 00409 00410 inline static QString toString(const InfoMap &infoMap, const QString sep="\n") 00411 { 00412 QString str(""); 00413 InfoMap::const_iterator it = infoMap.begin(); 00414 for (; it != infoMap.end() ; ++it) 00415 str += QString("[%1]:%2%3").arg(it.key()).arg(*it).arg(sep); 00416 return str; 00417 } 00418 00419 void TVBrowseHelper::run() 00420 { 00421 RunProlog(); 00422 QMutexLocker locker(&m_lock); 00423 while (true) 00424 { 00425 while (m_list.empty() && m_run) 00426 m_wait.wait(&m_lock); 00427 00428 if (!m_run) 00429 break; 00430 00431 BrowseInfo bi = m_list.front(); 00432 m_list.pop_front(); 00433 00434 PlayerContext *ctx = m_ctx; 00435 00436 vector<uint> chanids; 00437 if (BROWSE_SAME == bi.m_dir) 00438 { 00439 if (!bi.m_chanid) 00440 { 00441 vector<uint> chanids_extra; 00442 uint sourceid = db_chanid_to_sourceid[m_chanid]; 00443 QMultiMap<QString,uint>::iterator it; 00444 it = db_channum_to_chanids.lowerBound(bi.m_channum); 00445 for ( ; (it != db_channum_to_chanids.end()) && 00446 (it.key() == bi.m_channum); ++it) 00447 { 00448 if (db_chanid_to_sourceid[*it] == sourceid) 00449 chanids.push_back(*it); 00450 else 00451 chanids_extra.push_back(*it); 00452 } 00453 chanids.insert(chanids.end(), 00454 chanids_extra.begin(), 00455 chanids_extra.end()); 00456 } 00457 m_channum = bi.m_channum; 00458 m_chanid = (chanids.empty()) ? bi.m_chanid : chanids[0]; 00459 m_starttime = bi.m_starttime; 00460 } 00461 00462 BrowseDirection direction = bi.m_dir; 00463 00464 QDateTime lasttime = QDateTime::fromString( 00465 m_starttime, Qt::ISODate); 00466 QDateTime curtime = QDateTime::currentDateTime(); 00467 if (lasttime < curtime) 00468 m_starttime = curtime.toString(Qt::ISODate); 00469 00470 QDateTime maxtime = curtime.addSecs(db_browse_max_forward); 00471 if ((lasttime > maxtime) && (direction == BROWSE_RIGHT)) 00472 continue; 00473 00474 m_lock.unlock(); 00475 00476 // if browsing channel groups is enabled or 00477 // direction if BROWSE_FAVORITES 00478 // Then pick the next channel in the channel group list to browse 00479 // If channel group is ALL CHANNELS (-1), then bypass picking from 00480 // the channel group list 00481 if ((db_use_channel_groups || (direction == BROWSE_FAVORITE)) && 00482 (direction != BROWSE_RIGHT) && (direction != BROWSE_LEFT) && 00483 (direction != BROWSE_SAME)) 00484 { 00485 m_tv->channelGroupLock.lock(); 00486 if (m_tv->channelGroupId > -1) 00487 { 00488 int dir = direction; 00489 if ((direction == BROWSE_UP) || (direction == BROWSE_FAVORITE)) 00490 dir = CHANNEL_DIRECTION_UP; 00491 else if (direction == BROWSE_DOWN) 00492 dir = CHANNEL_DIRECTION_DOWN; 00493 00494 uint chanid = ChannelUtil::GetNextChannel( 00495 m_tv->channelGroupChannelList, m_chanid, 0, dir); 00496 direction = BROWSE_SAME; 00497 00498 m_tv->channelGroupLock.unlock(); 00499 00500 m_lock.lock(); 00501 m_chanid = chanid; 00502 m_channum = QString::null; 00503 m_lock.unlock(); 00504 } 00505 else 00506 m_tv->channelGroupLock.unlock(); 00507 } 00508 00509 if (direction == BROWSE_FAVORITE) 00510 direction = BROWSE_UP; 00511 00512 InfoMap infoMap; 00513 infoMap["dbstarttime"] = m_starttime; 00514 infoMap["channum"] = m_channum; 00515 infoMap["chanid"] = QString::number(m_chanid); 00516 00517 m_tv->GetPlayerReadLock(0,__FILE__,__LINE__); 00518 bool still_there = false; 00519 for (uint i = 0; i < m_tv->player.size() && !still_there; i++) 00520 still_there |= (ctx == m_tv->player[i]); 00521 if (still_there) 00522 { 00523 if (!db_browse_all_tuners) 00524 { 00525 GetNextProgram(direction, infoMap); 00526 } 00527 else 00528 { 00529 if (!chanids.empty()) 00530 { 00531 for (uint i = 0; i < chanids.size(); i++) 00532 { 00533 if (m_tv->IsTunable(ctx, chanids[i])) 00534 { 00535 infoMap["chanid"] = QString::number(chanids[i]); 00536 GetNextProgramDB(direction, infoMap); 00537 break; 00538 } 00539 } 00540 } 00541 else 00542 { 00543 uint orig_chanid = infoMap["chanid"].toUInt(); 00544 GetNextProgramDB(direction, infoMap); 00545 while (!m_tv->IsTunable(ctx, infoMap["chanid"].toUInt()) && 00546 (infoMap["chanid"].toUInt() != orig_chanid)) 00547 { 00548 GetNextProgramDB(direction, infoMap); 00549 } 00550 } 00551 } 00552 } 00553 m_tv->ReturnPlayerLock(ctx); 00554 00555 m_lock.lock(); 00556 if (!m_ctx && !still_there) 00557 continue; 00558 00559 m_channum = infoMap["channum"]; 00560 m_chanid = infoMap["chanid"].toUInt(); 00561 00562 if (((direction == BROWSE_LEFT) || (direction == BROWSE_RIGHT)) && 00563 !infoMap["dbstarttime"].isEmpty()) 00564 { 00565 m_starttime = infoMap["dbstarttime"]; 00566 } 00567 00568 if (!m_list.empty()) 00569 { 00570 // send partial info to UI for appearance of responsiveness 00571 QCoreApplication::postEvent( 00572 m_tv, new UpdateBrowseInfoEvent(infoMap)); 00573 continue; 00574 } 00575 m_lock.unlock(); 00576 00577 // pull in additional data from the DB... 00578 QDateTime startts = QDateTime::fromString( 00579 m_starttime, Qt::ISODate); 00580 RecordingInfo recinfo(m_chanid, startts, false); 00581 recinfo.ToMap(infoMap); 00582 infoMap["iconpath"] = ChannelUtil::GetIcon(recinfo.GetChanID()); 00583 00584 m_lock.lock(); 00585 if (m_ctx) 00586 { 00587 QCoreApplication::postEvent( 00588 m_tv, new UpdateBrowseInfoEvent(infoMap)); 00589 } 00590 } 00591 RunEpilog(); 00592 }
1.7.6.1