00001 #include "bdringbuffer.h"
00002 #include "avformatdecoderbd.h"
00003 #include "mythbdplayer.h"
00004
00005 #define LOC QString("BDPlayer: ")
00006
00007 MythBDPlayer::MythBDPlayer(PlayerFlags flags)
00008 : MythPlayer(flags), m_stillFrameShowing(false)
00009 {
00010 }
00011
00012 void MythBDPlayer::PreProcessNormalFrame(void)
00013 {
00014 DisplayMenu();
00015 }
00016
00017 bool MythBDPlayer::GoToMenu(QString str)
00018 {
00019 if (player_ctx->buffer->BD() && videoOutput)
00020 {
00021 int64_t pts = 0;
00022 VideoFrame *frame = videoOutput->GetLastShownFrame();
00023 if (frame)
00024 pts = (int64_t)(frame->timecode * 90);
00025 return player_ctx->buffer->BD()->GoToMenu(str, pts);
00026 }
00027 return false;
00028 }
00029
00030 void MythBDPlayer::DisplayMenu(void)
00031 {
00032 if (!player_ctx->buffer->IsBD())
00033 return;
00034
00035 osdLock.lock();
00036 BDOverlay *overlay = NULL;
00037 while (osd && (NULL != (overlay = player_ctx->buffer->BD()->GetOverlay())))
00038 osd->DisplayBDOverlay(overlay);
00039 osdLock.unlock();
00040 }
00041
00042 void MythBDPlayer::DisplayPauseFrame(void)
00043 {
00044 if (player_ctx->buffer->IsBD() &&
00045 player_ctx->buffer->BD()->IsInStillFrame())
00046 {
00047 SetScanType(kScan_Progressive);
00048 }
00049 DisplayMenu();
00050 MythPlayer::DisplayPauseFrame();
00051 }
00052
00053 bool MythBDPlayer::VideoLoop(void)
00054 {
00055 if (!player_ctx->buffer->IsBD())
00056 {
00057 SetErrored("RingBuffer is not a Blu-Ray disc.");
00058 return !IsErrored();
00059 }
00060
00061 int nbframes = videoOutput ? videoOutput->ValidVideoFrames() : 0;
00062
00063
00064 bool drain = player_ctx->buffer->BD()->BDWaitingForPlayer() &&
00065 (nbframes > 0);
00066
00067 if (drain)
00068 {
00069 if (nbframes < 2 && videoOutput)
00070 videoOutput->UpdatePauseFrame(disp_timecode);
00071
00072
00073
00074 DisplayNormalFrame(false);
00075 return !IsErrored();
00076 }
00077
00078
00079 if (player_ctx->buffer->BD()->BDWaitingForPlayer())
00080 {
00081 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Clearing Mythtv BD wait state");
00082 player_ctx->buffer->BD()->SkipBDWaitingForPlayer();
00083 return !IsErrored();
00084 }
00085
00086 if (player_ctx->buffer->BD()->IsInStillFrame())
00087 {
00088 if (nbframes > 1 && !m_stillFrameShowing)
00089 {
00090 videoOutput->UpdatePauseFrame(disp_timecode);
00091 DisplayNormalFrame(false);
00092 return !IsErrored();
00093 }
00094
00095 if (!m_stillFrameShowing)
00096 needNewPauseFrame = true;
00097
00098
00099 if (!videoPaused)
00100 {
00101 PauseVideo();
00102 return !IsErrored();
00103 }
00104
00105
00106 if (nbframes == 0)
00107 {
00108 LOG(VB_PLAYBACK, LOG_WARNING, LOC +
00109 "Warning: In BD Still but no video frames in queue");
00110 usleep(10000);
00111 return !IsErrored();
00112 }
00113
00114 if (!m_stillFrameShowing)
00115 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Entering still frame.");
00116 m_stillFrameShowing = true;
00117 }
00118 else
00119 {
00120 if (videoPaused && m_stillFrameShowing)
00121 {
00122 UnpauseVideo();
00123 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exiting still frame.");
00124 }
00125 m_stillFrameShowing = false;
00126 }
00127
00128 return MythPlayer::VideoLoop();
00129 }
00130
00131 void MythBDPlayer::EventStart(void)
00132 {
00133 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
00134 if (player_ctx->playingInfo)
00135 {
00136 QString name;
00137 QString serialid;
00138 if (player_ctx->playingInfo->GetTitle().isEmpty() &&
00139 player_ctx->buffer->BD()->GetNameAndSerialNum(name, serialid))
00140 {
00141 player_ctx->playingInfo->SetTitle(name);
00142 }
00143 }
00144 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
00145
00146 MythPlayer::EventStart();
00147 }
00148
00149 int MythBDPlayer::GetNumChapters(void)
00150 {
00151 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00152 return player_ctx->buffer->BD()->GetNumChapters();
00153 return -1;
00154 }
00155
00156 int MythBDPlayer::GetCurrentChapter(void)
00157 {
00158 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00159 return player_ctx->buffer->BD()->GetCurrentChapter() + 1;
00160 return -1;
00161 }
00162
00163 int64_t MythBDPlayer::GetChapter(int chapter)
00164 {
00165 uint total = GetNumChapters();
00166 if (!total)
00167 return -1;
00168
00169 return (int64_t)player_ctx->buffer->BD()->GetChapterStartFrame(chapter-1);
00170 }
00171
00172 void MythBDPlayer::GetChapterTimes(QList<long long> ×)
00173 {
00174 uint total = GetNumChapters();
00175 if (!total)
00176 return;
00177
00178 for (uint i = 0; i < total; i++)
00179 times.push_back(player_ctx->buffer->BD()->GetChapterStartTime(i));
00180 }
00181
00182 int MythBDPlayer::GetNumTitles(void) const
00183 {
00184 if (player_ctx->buffer->BD()->IsHDMVNavigation())
00185 return 0;
00186
00187 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00188 return player_ctx->buffer->BD()->GetNumTitles();
00189 return 0;
00190 }
00191
00192 int MythBDPlayer::GetNumAngles(void) const
00193 {
00194 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00195 return player_ctx->buffer->BD()->GetNumAngles();
00196 return 0;
00197 }
00198
00199 int MythBDPlayer::GetCurrentTitle(void) const
00200 {
00201 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00202 return player_ctx->buffer->BD()->GetCurrentTitle();
00203 return -1;
00204 }
00205
00206 int MythBDPlayer::GetCurrentAngle(void) const
00207 {
00208 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen())
00209 return player_ctx->buffer->BD()->GetCurrentAngle();
00210 return -1;
00211 }
00212
00213 int MythBDPlayer::GetTitleDuration(int title) const
00214 {
00215 if (player_ctx->buffer->BD() && player_ctx->buffer->BD()->IsOpen() &&
00216 title >= 0 && title < GetNumTitles())
00217 {
00218 return player_ctx->buffer->BD()->GetTitleDuration(title);
00219 }
00220 return 0;
00221 }
00222
00223 QString MythBDPlayer::GetTitleName(int title) const
00224 {
00225 if (title >= 0 && title < GetNumTitles())
00226 {
00227 int secs = GetTitleDuration(title);
00228
00229 int hours = secs / 60 / 60;
00230 int minutes = (secs / 60) - (hours * 60);
00231 secs = secs % 60;
00232 QString name = QString("%1 (%2:%3:%4)").arg(title+1)
00233 .arg(hours, 2, 10, QChar(48)).arg(minutes, 2, 10, QChar(48))
00234 .arg(secs, 2, 10, QChar(48));
00235 return name;
00236 }
00237 return QString();
00238 }
00239
00240 QString MythBDPlayer::GetAngleName(int angle) const
00241 {
00242 if (angle >= 0 && angle < GetNumAngles())
00243 {
00244 QString name = QObject::tr("Angle %1").arg(angle+1);
00245 return name;
00246 }
00247 return QString();
00248 }
00249
00250 bool MythBDPlayer::SwitchTitle(int title)
00251 {
00252 if (player_ctx->buffer->BD()->IsHDMVNavigation())
00253 return false;
00254
00255 uint total = GetNumTitles();
00256 if (!total || title == GetCurrentTitle() || title >= (int)total)
00257 return false;
00258
00259 Pause();
00260
00261 bool ok = false;
00262 if (player_ctx->buffer->BD()->SwitchTitle(title))
00263 {
00264 ResetCaptions();
00265 if (OpenFile() != 0)
00266 {
00267 SetErrored(QObject::tr("Failed to switch title."));
00268 }
00269 else
00270 {
00271 ok = true;
00272 forcePositionMapSync = true;
00273 }
00274 }
00275
00276 Play();
00277 return ok;
00278 }
00279
00280 bool MythBDPlayer::NextTitle(void)
00281 {
00282 if (player_ctx->buffer->BD()->IsHDMVNavigation())
00283 return false;
00284
00285 uint total = GetNumTitles();
00286 int next = GetCurrentTitle() + 1;
00287 if (!total || next >= (int)total)
00288 return false;
00289
00290 return SwitchTitle(next);
00291 }
00292
00293 bool MythBDPlayer::PrevTitle(void)
00294 {
00295 if (player_ctx->buffer->BD()->IsHDMVNavigation())
00296 return false;
00297
00298 uint total = GetNumTitles();
00299 int prev = GetCurrentTitle() - 1;
00300 if (!total || prev < 0)
00301 return false;
00302
00303 return SwitchTitle(prev);
00304 }
00305
00306 bool MythBDPlayer::SwitchAngle(int angle)
00307 {
00308 uint total = GetNumAngles();
00309 if (!total || angle == GetCurrentAngle())
00310 return false;
00311
00312 if (angle >= (int)total)
00313 angle = 0;
00314
00315 return player_ctx->buffer->BD()->SwitchAngle(angle);
00316 }
00317
00318 bool MythBDPlayer::NextAngle(void)
00319 {
00320 uint total = GetNumAngles();
00321 int next = GetCurrentAngle() + 1;
00322 if (!total)
00323 return false;
00324
00325 if (next >= (int)total)
00326 next = 0;
00327
00328 return SwitchAngle(next);
00329 }
00330
00331 bool MythBDPlayer::PrevAngle(void)
00332 {
00333 uint total = GetNumAngles();
00334 int prev = GetCurrentAngle() - 1;
00335 if (!total || total == 1)
00336 return false;
00337
00338 if (prev < 0)
00339 prev = total;
00340
00341 return SwitchAngle(prev);
00342 }
00343
00344 void MythBDPlayer::CreateDecoder(char *testbuf, int testreadsize)
00345 {
00346 if (AvFormatDecoderBD::CanHandle(testbuf, player_ctx->buffer->GetFilename(),
00347 testreadsize))
00348 {
00349 SetDecoder(new AvFormatDecoderBD(this, *player_ctx->playingInfo,
00350 playerFlags));
00351 }
00352 }