00001
00002
00003 #undef HAVE_AV_CONFIG_H
00004
00005
00006 #include <stdint.h>
00007 #include <cstdio>
00008 #include <cstdlib>
00009 #include <cerrno>
00010 #include <ctime>
00011 #include <cmath>
00012
00013
00014 #include <unistd.h>
00015 #include <fcntl.h>
00016 #include <sched.h>
00017 #include <sys/time.h>
00018 #include <assert.h>
00019
00020
00021 #include <algorithm>
00022 #include <iostream>
00023 using namespace std;
00024
00025
00026 #include <QCoreApplication>
00027 #include <QKeyEvent>
00028 #include <QDir>
00029
00030
00031 #include "mthread.h"
00032 #include "mythconfig.h"
00033 #include "mythdbcon.h"
00034 #include "dialogbox.h"
00035 #include "mythplayer.h"
00036 #include "DetectLetterbox.h"
00037 #include "audioplayer.h"
00038 #include "recordingprofile.h"
00039 #include "teletextscreen.h"
00040 #include "interactivescreen.h"
00041 #include "remoteutil.h"
00042 #include "programinfo.h"
00043 #include "mythcorecontext.h"
00044 #include "fifowriter.h"
00045 #include "filtermanager.h"
00046 #include "mythmiscutil.h"
00047 #include "livetvchain.h"
00048 #include "decoderbase.h"
00049 #include "nuppeldecoder.h"
00050 #include "avformatdecoder.h"
00051 #include "dummydecoder.h"
00052 #include "jobqueue.h"
00053 #include "NuppelVideoRecorder.h"
00054 #include "tv_play.h"
00055 #include "interactivetv.h"
00056 #include "myth_imgconvert.h"
00057 #include "mythsystemevent.h"
00058 #include "mythpainter.h"
00059 #include "mythimage.h"
00060 #include "mythuiimage.h"
00061 #include "mythlogging.h"
00062
00063 extern "C" {
00064 #include "vbitext/vbi.h"
00065 #include "vsync.h"
00066 #include "libavcodec/avcodec.h"
00067 #include "libswscale/swscale.h"
00068 }
00069
00070 #include "remoteencoder.h"
00071
00072 #include "videoout_null.h"
00073
00074 #if ! HAVE_ROUND
00075 #define round(x) ((int) ((x) + 0.5))
00076 #endif
00077
00078 #if CONFIG_DARWIN
00079 extern "C" {
00080 int isnan(double);
00081 }
00082 #endif
00083
00084 static unsigned dbg_ident(const MythPlayer*);
00085
00086 #define LOC QString("Player(%1): ").arg(dbg_ident(this),0,36)
00087 #define LOC_DEC QString("Player(%1): ").arg(dbg_ident(m_mp),0,36)
00088
00089 const int MythPlayer::kNightModeBrightenssAdjustment = 10;
00090 const int MythPlayer::kNightModeContrastAdjustment = 10;
00091
00092
00093 const double MythPlayer::kInaccuracyNone = 0;
00094
00095
00096
00097
00098 const double MythPlayer::kInaccuracyDefault = 0.1;
00099
00100
00101
00102 const double MythPlayer::kInaccuracyEditor = 0.5;
00103
00104
00105
00106 const double MythPlayer::kInaccuracyFull = -1.0;
00107
00108 void DecoderThread::run(void)
00109 {
00110 RunProlog();
00111 LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread starting.");
00112 if (m_mp)
00113 m_mp->DecoderLoop(m_start_paused);
00114 LOG(VB_PLAYBACK, LOG_INFO, LOC_DEC + "Decoder thread exiting.");
00115 RunEpilog();
00116 }
00117
00118 static const int toCaptionType(int type)
00119 {
00120 if (kTrackTypeCC608 == type) return kDisplayCC608;
00121 if (kTrackTypeCC708 == type) return kDisplayCC708;
00122 if (kTrackTypeSubtitle == type) return kDisplayAVSubtitle;
00123 if (kTrackTypeTeletextCaptions == type) return kDisplayTeletextCaptions;
00124 if (kTrackTypeTextSubtitle == type) return kDisplayTextSubtitle;
00125 if (kTrackTypeRawText == type) return kDisplayRawTextSubtitle;
00126 return 0;
00127 }
00128
00129 static const int toTrackType(int type)
00130 {
00131 if (kDisplayCC608 == type) return kTrackTypeCC608;
00132 if (kDisplayCC708 == type) return kTrackTypeCC708;
00133 if (kDisplayAVSubtitle == type) return kTrackTypeSubtitle;
00134 if (kDisplayTeletextCaptions == type) return kTrackTypeTeletextCaptions;
00135 if (kDisplayTextSubtitle == type) return kTrackTypeTextSubtitle;
00136 if (kDisplayRawTextSubtitle == type) return kTrackTypeRawText;
00137 return 0;
00138 }
00139
00140 MythPlayer::MythPlayer(PlayerFlags flags)
00141 : playerFlags(flags),
00142 decoder(NULL), decoder_change_lock(QMutex::Recursive),
00143 videoOutput(NULL), player_ctx(NULL),
00144 decoderThread(NULL), playerThread(NULL),
00145
00146 parentWidget(NULL), embedding(false), embedRect(QRect()),
00147
00148 totalDecoderPause(false), decoderPaused(false),
00149 inJumpToProgramPause(false),
00150 pauseDecoder(false), unpauseDecoder(false),
00151 killdecoder(false), decoderSeek(-1), decodeOneFrame(false),
00152 needNewPauseFrame(false),
00153 bufferPaused(false), videoPaused(false),
00154 allpaused(false), playing(false),
00155 m_double_framerate(false), m_double_process(false),
00156 m_deint_possible(true),
00157 livetv(false),
00158 watchingrecording(false),
00159 transcoding(false),
00160 hasFullPositionMap(false), limitKeyRepeat(false),
00161 errorMsg(QString::null), errorType(kError_None),
00162
00163 jumpchapter(0),
00164
00165 bookmarkseek(0),
00166
00167 fftime(0),
00168
00169 videobuf_retries(0), framesPlayed(0),
00170 totalFrames(0), totalLength(0),
00171 totalDuration(0),
00172 rewindtime(0),
00173
00174 video_disp_dim(0,0), video_dim(0,0),
00175 video_frame_rate(29.97f), video_aspect(4.0f / 3.0f),
00176 forced_video_aspect(-1),
00177 resetScan(kScan_Ignore), m_scan(kScan_Interlaced),
00178 m_scan_locked(false), m_scan_tracker(0), m_scan_initialized(false),
00179 keyframedist(30),
00180
00181 buffering(false),
00182
00183 textDisplayMode(kDisplayNone),
00184 prevTextDisplayMode(kDisplayNone),
00185 prevNonzeroTextDisplayMode(kDisplayNone),
00186
00187 vbimode(VBIMode::None),
00188 ttPageNum(0x888),
00189
00190 textDesired(false), enableCaptions(false), disableCaptions(false),
00191 enableForcedSubtitles(false), disableForcedSubtitles(false),
00192 allowForcedSubtitles(true),
00193
00194 cc608(this), cc708(this),
00195
00196 itvVisible(false),
00197 interactiveTV(NULL),
00198 itvEnabled(false),
00199
00200 osd(NULL), reinit_osd(false), osdLock(QMutex::Recursive),
00201
00202 audio(this, (flags & kAudioMuted)),
00203
00204 pip_active(false), pip_visible(true),
00205
00206 videoFiltersForProgram(""), videoFiltersOverride(""),
00207 postfilt_width(0), postfilt_height(0),
00208 videoFilters(NULL), FiltMan(new FilterManager()),
00209
00210 forcePositionMapSync(false), pausedBeforeEdit(false),
00211 speedBeforeEdit(1.0f),
00212
00213 decoder_lock(QMutex::Recursive),
00214 next_play_speed(1.0f), next_normal_speed(true),
00215 play_speed(1.0f), normal_speed(true),
00216 frame_interval((int)(1000000.0f / 30)), m_frame_interval(0),
00217 ffrew_skip(1),ffrew_adjust(0),
00218
00219 videosync(NULL), avsync_delay(0),
00220 avsync_adjustment(0), avsync_avg(0),
00221 avsync_predictor(0), avsync_predictor_enabled(false),
00222 refreshrate(0),
00223 lastsync(false), repeat_delay(0),
00224 disp_timecode(0), avsync_audiopaused(false),
00225
00226 prevtc(0), prevrp(0),
00227
00228 m_tv(NULL), isDummy(false),
00229
00230 output_jmeter(new Jitterometer(LOC))
00231 {
00232 memset(&tc_lastval, 0, sizeof(tc_lastval));
00233 memset(&tc_wrap, 0, sizeof(tc_wrap));
00234
00235 playerThread = QThread::currentThread();
00236
00237 detect_letter_box = new DetectLetterbox(this);
00238
00239 vbimode = VBIMode::Parse(gCoreContext->GetSetting("VbiFormat"));
00240
00241 defaultDisplayAspect =
00242 gCoreContext->GetFloatSettingOnHost("XineramaMonitorAspectRatio",
00243 gCoreContext->GetHostName(), 1.3333);
00244 captionsEnabledbyDefault = gCoreContext->GetNumSetting("DefaultCCMode");
00245 decode_extra_audio = gCoreContext->GetNumSetting("DecodeExtraAudio", 0);
00246 itvEnabled = gCoreContext->GetNumSetting("EnableMHEG", 0);
00247 clearSavedPosition = gCoreContext->GetNumSetting("ClearSavedPosition", 1);
00248 endExitPrompt = gCoreContext->GetNumSetting("EndOfRecordingExitPrompt");
00249 pip_default_loc = (PIPLocation)gCoreContext->GetNumSetting("PIPLocation", kPIPTopLeft);
00250 tc_wrap[TC_AUDIO] = gCoreContext->GetNumSetting("AudioSyncOffset", 0);
00251 allowForcedSubtitles = gCoreContext->GetNumSetting("AllowForcedSubtitles", 1);
00252
00253
00254 QString mypage = gCoreContext->GetSetting("VBIpageNr", "888");
00255 bool valid = false;
00256 uint tmp = mypage.toInt(&valid, 16);
00257 ttPageNum = (valid) ? tmp : ttPageNum;
00258 cc608.SetTTPageNum(ttPageNum);
00259 }
00260
00261 MythPlayer::~MythPlayer(void)
00262 {
00263 QMutexLocker lk1(&osdLock);
00264 QMutexLocker lk2(&vidExitLock);
00265 QMutexLocker lk3(&videofiltersLock);
00266
00267 if (osd)
00268 {
00269 delete osd;
00270 osd = NULL;
00271 }
00272
00273 SetDecoder(NULL);
00274
00275 if (decoderThread)
00276 {
00277 delete decoderThread;
00278 decoderThread = NULL;
00279 }
00280
00281 if (interactiveTV)
00282 {
00283 delete interactiveTV;
00284 interactiveTV = NULL;
00285 }
00286
00287 if (FiltMan)
00288 {
00289 delete FiltMan;
00290 FiltMan = NULL;
00291 }
00292
00293 if (videoFilters)
00294 {
00295 delete videoFilters;
00296 videoFilters = NULL;
00297 }
00298
00299 if (videosync)
00300 {
00301 delete videosync;
00302 videosync = NULL;
00303 }
00304
00305 if (videoOutput)
00306 {
00307 delete videoOutput;
00308 videoOutput = NULL;
00309 }
00310
00311 if (output_jmeter)
00312 {
00313 delete output_jmeter;
00314 output_jmeter = NULL;
00315 }
00316
00317 if (detect_letter_box)
00318 {
00319 delete detect_letter_box;
00320 detect_letter_box = NULL;
00321 }
00322 }
00323
00324 void MythPlayer::SetWatchingRecording(bool mode)
00325 {
00326 watchingrecording = mode;
00327 if (decoder)
00328 decoder->SetWatchingRecording(mode);
00329 }
00330
00331 bool MythPlayer::IsWatchingInprogress(void) const
00332 {
00333 return watchingrecording && player_ctx->recorder &&
00334 player_ctx->recorder->IsValidRecorder();
00335 }
00336
00337 void MythPlayer::PauseBuffer(void)
00338 {
00339 bufferPauseLock.lock();
00340 if (player_ctx->buffer)
00341 {
00342 player_ctx->buffer->Pause();
00343 player_ctx->buffer->WaitForPause();
00344 }
00345 bufferPaused = true;
00346 bufferPauseLock.unlock();
00347 }
00348
00349 void MythPlayer::UnpauseBuffer(void)
00350 {
00351 bufferPauseLock.lock();
00352 if (player_ctx->buffer)
00353 player_ctx->buffer->Unpause();
00354 bufferPaused = false;
00355 bufferPauseLock.unlock();
00356 }
00357
00358 bool MythPlayer::Pause(void)
00359 {
00360 if (!pauseLock.tryLock(100))
00361 {
00362 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms to get pause lock.");
00363 DecoderPauseCheck();
00364 }
00365 bool already_paused = allpaused;
00366 if (already_paused)
00367 {
00368 pauseLock.unlock();
00369 return already_paused;
00370 }
00371 next_play_speed = 0.0;
00372 next_normal_speed = false;
00373 PauseVideo();
00374 audio.Pause(true);
00375 PauseDecoder();
00376 PauseBuffer();
00377 allpaused = decoderPaused && videoPaused && bufferPaused;
00378 {
00379 if (FlagIsSet(kVideoIsNull) && decoder)
00380 decoder->UpdateFramesPlayed();
00381 else if (videoOutput && !FlagIsSet(kVideoIsNull))
00382 framesPlayed = videoOutput->GetFramesPlayed();
00383 }
00384 pauseLock.unlock();
00385 return already_paused;
00386 }
00387
00388 bool MythPlayer::Play(float speed, bool normal, bool unpauseaudio)
00389 {
00390 pauseLock.lock();
00391 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00392 QString("Play(%1, normal %2, unpause audio %3)")
00393 .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
00394
00395 if (deleteMap.IsEditing())
00396 {
00397 LOG(VB_GENERAL, LOG_ERR, LOC + "Ignoring Play(), in edit mode.");
00398 pauseLock.unlock();
00399 return false;
00400 }
00401
00402 UnpauseBuffer();
00403 UnpauseDecoder();
00404 if (unpauseaudio)
00405 audio.Pause(false);
00406 UnpauseVideo();
00407 allpaused = false;
00408 next_play_speed = speed;
00409 next_normal_speed = normal;
00410 pauseLock.unlock();
00411 return true;
00412 }
00413
00414 void MythPlayer::PauseVideo(void)
00415 {
00416 videoPauseLock.lock();
00417 needNewPauseFrame = true;
00418 videoPaused = true;
00419 videoPauseLock.unlock();
00420 }
00421
00422 void MythPlayer::UnpauseVideo(void)
00423 {
00424 videoPauseLock.lock();
00425 videoPaused = false;
00426 if (videoOutput)
00427 videoOutput->ExposeEvent();
00428 videoPauseLock.unlock();
00429 }
00430
00431 void MythPlayer::SetPlayingInfo(const ProgramInfo &pginfo)
00432 {
00433 assert(player_ctx);
00434 if (!player_ctx)
00435 return;
00436
00437 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
00438 player_ctx->SetPlayingInfo(&pginfo);
00439 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
00440
00441 SetVideoFilters("");
00442 InitFilters();
00443 }
00444
00445 void MythPlayer::SetPlaying(bool is_playing)
00446 {
00447 QMutexLocker locker(&playingLock);
00448
00449 playing = is_playing;
00450
00451 playingWaitCond.wakeAll();
00452 }
00453
00454 bool MythPlayer::IsPlaying(uint wait_in_msec, bool wait_for) const
00455 {
00456 QMutexLocker locker(&playingLock);
00457
00458 if (!wait_in_msec)
00459 return playing;
00460
00461 MythTimer t;
00462 t.start();
00463
00464 while ((wait_for != playing) && ((uint)t.elapsed() < wait_in_msec))
00465 {
00466 playingWaitCond.wait(
00467 &playingLock, max(0,(int)wait_in_msec - t.elapsed()));
00468 }
00469
00470 return playing;
00471 }
00472
00473 bool MythPlayer::InitVideo(void)
00474 {
00475 if (!player_ctx)
00476 return false;
00477
00478 PIPState pipState = player_ctx->GetPIPState();
00479
00480 if (!decoder)
00481 {
00482 LOG(VB_GENERAL, LOG_ERR, LOC +
00483 "Cannot create a video renderer without a decoder.");
00484 return false;
00485 }
00486
00487 videoOutput = VideoOutput::Create(
00488 decoder->GetCodecDecoderName(),
00489 decoder->GetVideoCodecID(),
00490 decoder->GetVideoCodecPrivate(),
00491 pipState, video_disp_dim, video_aspect,
00492 parentWidget, embedRect,
00493 video_frame_rate, (uint)playerFlags);
00494
00495 if (!videoOutput)
00496 {
00497 LOG(VB_GENERAL, LOG_ERR, LOC +
00498 "Couldn't create VideoOutput instance. Exiting..");
00499 SetErrored(QObject::tr("Failed to initialize video output"));
00500 return false;
00501 }
00502
00503 CheckExtraAudioDecode();
00504
00505 if (embedding && pipState == kPIPOff)
00506 videoOutput->EmbedInWidget(embedRect);
00507
00508 InitFilters();
00509
00510 return true;
00511 }
00512
00513 void MythPlayer::CheckExtraAudioDecode(void)
00514 {
00515 if (FlagIsSet(kVideoIsNull))
00516 return;
00517
00518 bool force = false;
00519 if (videoOutput && videoOutput->NeedExtraAudioDecode())
00520 {
00521 LOG(VB_GENERAL, LOG_NOTICE, LOC +
00522 "Forcing decode extra audio option on (Video method requires it).");
00523 force = true;
00524 }
00525
00526 if (decoder)
00527 decoder->SetLowBuffers(decode_extra_audio || force);
00528 }
00529
00530 void MythPlayer::ReinitOSD(void)
00531 {
00532 if (videoOutput && !FlagIsSet(kVideoIsNull))
00533 {
00534 osdLock.lock();
00535 if (!is_current_thread(playerThread))
00536 {
00537 reinit_osd = true;
00538 osdLock.unlock();
00539 return;
00540 }
00541 QRect visible, total;
00542 float aspect, scaling;
00543 if (osd)
00544 {
00545 osd->SetPainter(videoOutput->GetOSDPainter());
00546 videoOutput->GetOSDBounds(total, visible, aspect,
00547 scaling, 1.0f);
00548 int stretch = (int)((aspect * 100) + 0.5f);
00549 if ((osd->Bounds() != visible) ||
00550 (osd->GetFontStretch() != stretch))
00551 {
00552 uint old = textDisplayMode;
00553 ToggleCaptions(old);
00554 osd->Reinit(visible, aspect);
00555 EnableCaptions(old, false);
00556 }
00557 }
00558
00559 #ifdef USING_MHEG
00560 if (GetInteractiveTV())
00561 {
00562 QMutexLocker locker(&itvLock);
00563 total = videoOutput->GetMHEGBounds();
00564 interactiveTV->Reinit(total);
00565 itvVisible = false;
00566 }
00567 #endif // USING_MHEG
00568 reinit_osd = false;
00569 osdLock.unlock();
00570 }
00571 }
00572
00573 void MythPlayer::ReinitVideo(void)
00574 {
00575 if (!videoOutput->IsPreferredRenderer(video_disp_dim))
00576 {
00577 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Need to switch video renderer.");
00578 SetErrored(QObject::tr("Need to switch video renderer."));
00579 errorType |= kError_Switch_Renderer;
00580 return;
00581 }
00582
00583 bool aspect_only = false;
00584 {
00585 QMutexLocker locker1(&osdLock);
00586 QMutexLocker locker2(&vidExitLock);
00587 QMutexLocker locker3(&videofiltersLock);
00588
00589 videoOutput->SetVideoFrameRate(video_frame_rate);
00590 float aspect = (forced_video_aspect > 0) ? forced_video_aspect :
00591 video_aspect;
00592 if (!videoOutput->InputChanged(video_disp_dim, aspect,
00593 decoder->GetVideoCodecID(),
00594 decoder->GetVideoCodecPrivate(),
00595 aspect_only))
00596 {
00597 LOG(VB_GENERAL, LOG_ERR, LOC +
00598 "Failed to Reinitialize Video. Exiting..");
00599 SetErrored(QObject::tr("Failed to reinitialize video output"));
00600 return;
00601 }
00602
00603
00604 if (videosync)
00605 {
00606 int ri = MythDisplay::GetDisplayInfo(frame_interval).Rate();
00607 if (ri != videosync->getRefreshInterval())
00608 {
00609 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00610 QString("Refresh rate has changed from %1 to %2")
00611 .arg(videosync->getRefreshInterval())
00612 .arg(ri));
00613 videosync->setRefreshInterval(ri);
00614 }
00615 }
00616
00617 if (osd)
00618 osd->SetPainter(videoOutput->GetOSDPainter());
00619 ReinitOSD();
00620 }
00621
00622 if (!aspect_only)
00623 {
00624 CheckExtraAudioDecode();
00625 ClearAfterSeek();
00626 InitFilters();
00627 }
00628
00629 if (textDisplayMode)
00630 {
00631 EnableSubtitles(true);
00632 }
00633 }
00634
00635 static inline QString toQString(FrameScanType scan) {
00636 switch (scan) {
00637 case kScan_Ignore: return QString("Ignore Scan");
00638 case kScan_Detect: return QString("Detect Scan");
00639 case kScan_Interlaced: return QString("Interlaced Scan");
00640 case kScan_Progressive: return QString("Progressive Scan");
00641 default: return QString("Unknown Scan");
00642 }
00643 }
00644
00645 FrameScanType MythPlayer::detectInterlace(FrameScanType newScan,
00646 FrameScanType scan,
00647 float fps, int video_height)
00648 {
00649 QString dbg = QString("detectInterlace(") + toQString(newScan) +
00650 QString(", ") + toQString(scan) + QString(", ") +
00651 QString("%1").arg(fps) + QString(", ") +
00652 QString("%1").arg(video_height) + QString(") ->");
00653
00654 if (kScan_Ignore != newScan || kScan_Detect == scan)
00655 {
00656
00657
00658
00659 scan = kScan_Interlaced;
00660 if (720 == video_height)
00661 scan = kScan_Progressive;
00662 else if (fps > 45)
00663 scan = kScan_Progressive;
00664
00665 if (kScan_Detect != newScan)
00666 scan = newScan;
00667 };
00668
00669 LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg+toQString(scan));
00670
00671 return scan;
00672 }
00673
00674 void MythPlayer::SetKeyframeDistance(int keyframedistance)
00675 {
00676 keyframedist = (keyframedistance > 0) ? keyframedistance : keyframedist;
00677 }
00678
00682 void MythPlayer::FallbackDeint(void)
00683 {
00684 m_double_framerate = false;
00685 m_double_process = false;
00686
00687 if (videoOutput)
00688 videoOutput->FallbackDeint();
00689 }
00690
00691 void MythPlayer::AutoDeint(VideoFrame *frame, bool allow_lock)
00692 {
00693 if (!frame || m_scan_locked)
00694 return;
00695
00696 if (frame->interlaced_frame)
00697 {
00698 if (m_scan_tracker < 0)
00699 {
00700 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00701 QString("interlaced frame seen after %1 progressive frames")
00702 .arg(abs(m_scan_tracker)));
00703 m_scan_tracker = 2;
00704 if (allow_lock)
00705 {
00706 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Locking scan to Interlaced.");
00707 SetScanType(kScan_Interlaced);
00708 return;
00709 }
00710 }
00711 m_scan_tracker++;
00712 }
00713 else
00714 {
00715 if (m_scan_tracker > 0)
00716 {
00717 LOG(VB_PLAYBACK, LOG_INFO, LOC +
00718 QString("progressive frame seen after %1 interlaced frames")
00719 .arg(m_scan_tracker));
00720 m_scan_tracker = 0;
00721 }
00722 m_scan_tracker--;
00723 }
00724
00725 if ((m_scan_tracker % 400) == 0)
00726 {
00727 QString type = (m_scan_tracker < 0) ? "progressive" : "interlaced";
00728 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("%1 %2 frames seen.")
00729 .arg(abs(m_scan_tracker)).arg(type));
00730 }
00731
00732 int min_count = !allow_lock ? 0 : 2;
00733 if (abs(m_scan_tracker) <= min_count)
00734 return;
00735
00736 SetScanType((m_scan_tracker > min_count) ? kScan_Interlaced : kScan_Progressive);
00737 m_scan_locked = false;
00738 }
00739
00740 void MythPlayer::SetScanType(FrameScanType scan)
00741 {
00742 QMutexLocker locker(&videofiltersLock);
00743
00744 if (!is_current_thread(playerThread))
00745 {
00746 resetScan = scan;
00747 return;
00748 }
00749
00750 if (!videoOutput || !videosync)
00751 return;
00752
00753 resetScan = kScan_Ignore;
00754
00755 if (m_scan_initialized &&
00756 m_scan == scan &&
00757 m_frame_interval == frame_interval)
00758 return;
00759
00760 m_scan_locked = (scan != kScan_Detect);
00761
00762 m_scan_initialized = true;
00763 m_frame_interval = frame_interval;
00764
00765 bool interlaced = is_interlaced(scan);
00766
00767 if (interlaced && !m_deint_possible)
00768 {
00769 m_scan = scan;
00770 return;
00771 }
00772
00773 if (interlaced)
00774 {
00775 m_deint_possible = videoOutput->SetDeinterlacingEnabled(true);
00776 if (!m_deint_possible)
00777 {
00778 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to enable deinterlacing");
00779 m_scan = scan;
00780 return;
00781 }
00782 if (videoOutput->NeedsDoubleFramerate())
00783 {
00784 m_double_framerate = true;
00785 if (!CanSupportDoubleRate())
00786 {
00787 LOG(VB_GENERAL, LOG_ERR, LOC +
00788 "Video sync method can't support double framerate "
00789 "(refresh rate too low for 2x deint)");
00790 FallbackDeint();
00791 }
00792 }
00793 m_double_process = videoOutput->IsExtraProcessingRequired();
00794 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Enabled deinterlacing");
00795 }
00796 else
00797 {
00798 if (kScan_Progressive == scan)
00799 {
00800 m_double_process = false;
00801 m_double_framerate = false;
00802 videoOutput->SetDeinterlacingEnabled(false);
00803 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Disabled deinterlacing");
00804 }
00805 }
00806
00807 m_scan = scan;
00808 }
00809
00810 void MythPlayer::SetVideoParams(int width, int height, double fps,
00811 FrameScanType scan)
00812 {
00813 if (width < 1 || height < 1 || isnan(fps))
00814 return;
00815
00816 video_dim = QSize((width + 15) & ~0xf, (height + 15) & ~0xf);
00817 video_disp_dim = QSize(width, height);
00818
00819 if (fps > 0.0f && fps < 121.0f)
00820 {
00821 video_frame_rate = fps;
00822 if (ffrew_skip != 0 && ffrew_skip != 1)
00823 {
00824 UpdateFFRewSkip();
00825 videosync->setFrameInterval(frame_interval);
00826 }
00827 else
00828 {
00829 float temp_speed = (play_speed == 0.0f) ?
00830 audio.GetStretchFactor() : play_speed;
00831 SetFrameInterval(kScan_Progressive,
00832 1.0 / (video_frame_rate * temp_speed));
00833 }
00834 }
00835
00836 if (videoOutput)
00837 ReinitVideo();
00838
00839 if (IsErrored())
00840 return;
00841
00842 SetScanType(detectInterlace(scan, m_scan, video_frame_rate,
00843 video_disp_dim.height()));
00844 m_scan_locked = false;
00845 m_scan_tracker = (m_scan == kScan_Interlaced) ? 2 : 0;
00846 }
00847
00848 void MythPlayer::SetFileLength(int total, int frames)
00849 {
00850 totalLength = total;
00851 totalFrames = frames;
00852 }
00853
00854 void MythPlayer::SetDuration(int duration)
00855 {
00856 totalDuration = duration;
00857 }
00858
00859 void MythPlayer::OpenDummy(void)
00860 {
00861 isDummy = true;
00862
00863 if (!videoOutput)
00864 {
00865 SetKeyframeDistance(15);
00866 SetVideoParams(720, 576, 25.00);
00867 }
00868
00869 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
00870 DummyDecoder *dec = new DummyDecoder(this, *(player_ctx->playingInfo));
00871 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
00872 SetDecoder(dec);
00873 }
00874
00875 void MythPlayer::CreateDecoder(char *testbuf, int testreadsize)
00876 {
00877 if (NuppelDecoder::CanHandle(testbuf, testreadsize))
00878 SetDecoder(new NuppelDecoder(this, *player_ctx->playingInfo));
00879 else if (AvFormatDecoder::CanHandle(testbuf,
00880 player_ctx->buffer->GetFilename(),
00881 testreadsize))
00882 {
00883 SetDecoder(new AvFormatDecoder(this, *player_ctx->playingInfo,
00884 playerFlags));
00885 }
00886 }
00887
00888 int MythPlayer::OpenFile(uint retries)
00889 {
00890
00891 if ((player_ctx->IsPBP() && !player_ctx->IsPrimaryPBP()) &&
00892 FlagIsSet(kDecodeAllowGPU))
00893 {
00894 playerFlags = (PlayerFlags)(playerFlags - kDecodeAllowGPU);
00895 }
00896
00897 isDummy = false;
00898
00899 if (!player_ctx || !player_ctx->buffer)
00900 return -1;
00901
00902 livetv = player_ctx->tvchain;
00903
00904 if (player_ctx->tvchain &&
00905 player_ctx->tvchain->GetCardType(player_ctx->tvchain->GetCurPos()) ==
00906 "DUMMY")
00907 {
00908 OpenDummy();
00909 return 0;
00910 }
00911
00912 player_ctx->buffer->Start();
00914 char *testbuf = new char[kDecoderProbeBufferSize];
00915 UnpauseBuffer();
00916
00917
00918 SetDecoder(NULL);
00919 int testreadsize = 2048;
00920
00921 MythTimer bigTimer; bigTimer.start();
00922 int timeout = (retries + 1) * 500;
00923 while (testreadsize <= kDecoderProbeBufferSize)
00924 {
00925 MythTimer peekTimer; peekTimer.start();
00926 while (player_ctx->buffer->Peek(testbuf, testreadsize) != testreadsize)
00927 {
00928 if (peekTimer.elapsed() > 1000 || bigTimer.elapsed() > timeout)
00929 {
00930 LOG(VB_GENERAL, LOG_ERR, LOC +
00931 QString("OpenFile(): Could not read first %1 bytes of '%2'")
00932 .arg(testreadsize)
00933 .arg(player_ctx->buffer->GetFilename()));
00934 delete[] testbuf;
00935 return -1;
00936 }
00937 LOG(VB_GENERAL, LOG_WARNING, LOC + "OpenFile() waiting on data");
00938 usleep(50 * 1000);
00939 }
00940
00941 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
00942 CreateDecoder(testbuf, testreadsize);
00943 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
00944 if (decoder || (bigTimer.elapsed() > timeout))
00945 break;
00946 testreadsize <<= 1;
00947 }
00948
00949 if (!decoder)
00950 {
00951 LOG(VB_GENERAL, LOG_ERR, LOC +
00952 QString("Couldn't find an A/V decoder for: '%1'")
00953 .arg(player_ctx->buffer->GetFilename()));
00954
00955 delete[] testbuf;
00956 return -1;
00957 }
00958 else if (decoder->IsErrored())
00959 {
00960 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not initialize A/V decoder.");
00961 SetDecoder(NULL);
00962
00963 delete[] testbuf;
00964 return -1;
00965 }
00966
00967 decoder->SetSeekSnap(0);
00968 decoder->SetLiveTVMode(livetv);
00969 decoder->SetWatchingRecording(watchingrecording);
00970 decoder->SetTranscoding(transcoding);
00971 CheckExtraAudioDecode();
00972
00973
00974 bool no_video_decode = false;
00975
00976
00977
00978 int ret = decoder->OpenFile(
00979 player_ctx->buffer, no_video_decode, testbuf, testreadsize);
00980 delete[] testbuf;
00981
00982 if (ret < 0)
00983 {
00984 LOG(VB_GENERAL, LOG_ERR, QString("Couldn't open decoder for: %1")
00985 .arg(player_ctx->buffer->GetFilename()));
00986 return -1;
00987 }
00988
00989 audio.CheckFormat();
00990
00991 if (ret > 0)
00992 {
00993 hasFullPositionMap = true;
00994 deleteMap.LoadMap(totalFrames);
00995 deleteMap.TrackerReset(0, totalFrames);
00996 }
00997
00998
00999 bookmarkseek = GetBookmark();
01000 deleteMap.TrackerReset(bookmarkseek, totalFrames);
01001 deleteMap.TrackerWantsToJump(bookmarkseek, totalFrames, bookmarkseek);
01002
01003 if (!gCoreContext->IsDatabaseIgnored() &&
01004 player_ctx->playingInfo->QueryAutoExpire() == kLiveTVAutoExpire)
01005 {
01006 gCoreContext->SaveSetting(
01007 "DefaultChanid", player_ctx->playingInfo->GetChanID());
01008 }
01009
01010 return IsErrored() ? -1 : 0;
01011 }
01012
01013 void MythPlayer::SetFramesPlayed(uint64_t played)
01014 {
01015 framesPlayed = played;
01016 if (videoOutput)
01017 videoOutput->SetFramesPlayed(played);
01018 }
01019
01020 void MythPlayer::SetVideoFilters(const QString &override)
01021 {
01022 videoFiltersOverride = override;
01023 videoFiltersOverride.detach();
01024
01025 videoFiltersForProgram = player_ctx->GetFilters(
01026 (FlagIsSet(kVideoIsNull)) ? "onefield" : "");
01027 }
01028
01029 void MythPlayer::InitFilters(void)
01030 {
01031 QString filters = "";
01032 if (videoOutput)
01033 filters = videoOutput->GetFilters();
01034
01035 LOG(VB_PLAYBACK, LOG_DEBUG, LOC +
01036 QString("InitFilters() vo '%1' prog '%2' over '%3'")
01037 .arg(filters).arg(videoFiltersForProgram)
01038 .arg(videoFiltersOverride));
01039
01040 if (!videoFiltersForProgram.isEmpty())
01041 {
01042 if (videoFiltersForProgram[0] != '+')
01043 {
01044 filters = videoFiltersForProgram;
01045 }
01046 else
01047 {
01048 if ((filters.length() > 1) && (filters.right(1) != ","))
01049 filters += ",";
01050 filters += videoFiltersForProgram.mid(1);
01051 }
01052 }
01053
01054 if (!videoFiltersOverride.isEmpty())
01055 filters = videoFiltersOverride;
01056
01057 filters.detach();
01058
01059 videofiltersLock.lock();
01060
01061 if (videoFilters)
01062 {
01063 delete videoFilters;
01064 videoFilters = NULL;
01065 }
01066
01067 if (!filters.isEmpty())
01068 {
01069 VideoFrameType itmp = FMT_YV12;
01070 VideoFrameType otmp = FMT_YV12;
01071 int btmp;
01072 postfilt_width = video_dim.width();
01073 postfilt_height = video_dim.height();
01074
01075 videoFilters = FiltMan->LoadFilters(
01076 filters, itmp, otmp, postfilt_width, postfilt_height, btmp);
01077 }
01078
01079 videofiltersLock.unlock();
01080
01081 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("LoadFilters('%1'..) -> 0x%2")
01082 .arg(filters).arg((uint64_t)videoFilters,0,16));
01083 }
01084
01088 int MythPlayer::GetFreeVideoFrames(void) const
01089 {
01090 if (videoOutput)
01091 return videoOutput->FreeVideoFrames();
01092 return 0;
01093 }
01094
01108 VideoFrame *MythPlayer::GetNextVideoFrame(void)
01109 {
01110 if (videoOutput)
01111 return videoOutput->GetNextFreeFrame();
01112 return NULL;
01113 }
01114
01118 void MythPlayer::ReleaseNextVideoFrame(VideoFrame *buffer,
01119 int64_t timecode,
01120 bool wrap)
01121 {
01122 if (wrap)
01123 WrapTimecode(timecode, TC_VIDEO);
01124 buffer->timecode = timecode;
01125
01126 if (videoOutput)
01127 videoOutput->ReleaseFrame(buffer);
01128
01129 detect_letter_box->Detect(buffer);
01130 }
01131
01135 void MythPlayer::ClearDummyVideoFrame(VideoFrame *frame)
01136 {
01137 if (videoOutput)
01138 videoOutput->ClearDummyFrame(frame);
01139 }
01140
01144 void MythPlayer::DiscardVideoFrame(VideoFrame *buffer)
01145 {
01146 if (videoOutput)
01147 videoOutput->DiscardFrame(buffer);
01148 }
01149
01161 void MythPlayer::DiscardVideoFrames(bool next_frame_keyframe)
01162 {
01163 if (videoOutput)
01164 videoOutput->DiscardFrames(next_frame_keyframe);
01165 }
01166
01167 void MythPlayer::DrawSlice(VideoFrame *frame, int x, int y, int w, int h)
01168 {
01169 if (videoOutput)
01170 videoOutput->DrawSlice(frame, x, y, w, h);
01171 }
01172
01173 void* MythPlayer::GetDecoderContext(unsigned char* buf, uint8_t*& id)
01174 {
01175 if (videoOutput)
01176 return videoOutput->GetDecoderContext(buf, id);
01177 return NULL;
01178 }
01179
01180 VideoFrame *MythPlayer::GetCurrentFrame(int &w, int &h)
01181 {
01182 w = video_dim.width();
01183 h = video_dim.height();
01184
01185 VideoFrame *retval = NULL;
01186
01187 vidExitLock.lock();
01188 if (videoOutput)
01189 {
01190 retval = videoOutput->GetLastShownFrame();
01191 videofiltersLock.lock();
01192 if (videoFilters && player_ctx->IsPIP())
01193 videoFilters->ProcessFrame(retval);
01194 videofiltersLock.unlock();
01195 }
01196
01197 if (!retval)
01198 vidExitLock.unlock();
01199
01200 return retval;
01201 }
01202
01203 void MythPlayer::DeLimboFrame(VideoFrame *frame)
01204 {
01205 if (videoOutput)
01206 videoOutput->DeLimboFrame(frame);
01207 }
01208
01209 void MythPlayer::ReleaseCurrentFrame(VideoFrame *frame)
01210 {
01211 if (frame)
01212 vidExitLock.unlock();
01213 }
01214
01215 void MythPlayer::EmbedInWidget(QRect rect)
01216 {
01217 if (videoOutput)
01218 videoOutput->EmbedInWidget(rect);
01219 else
01220 {
01221 embedRect = rect;
01222 embedding = true;
01223 }
01224 }
01225
01226 void MythPlayer::StopEmbedding(void)
01227 {
01228 if (videoOutput)
01229 {
01230 videoOutput->StopEmbedding();
01231 ReinitOSD();
01232 }
01233 else
01234 {
01235 embedRect = QRect();
01236 embedding = false;
01237 }
01238 }
01239
01240 void MythPlayer::WindowResized(const QSize &new_size)
01241 {
01242 if (videoOutput)
01243 videoOutput->WindowResized(new_size);
01244 }
01245
01246 void MythPlayer::EnableTeletext(int page)
01247 {
01248 QMutexLocker locker(&osdLock);
01249 if (!osd)
01250 return;
01251
01252 osd->EnableTeletext(true, page);
01253 prevTextDisplayMode = textDisplayMode;
01254 textDisplayMode = kDisplayTeletextMenu;
01255 }
01256
01257 void MythPlayer::DisableTeletext(void)
01258 {
01259 QMutexLocker locker(&osdLock);
01260 if (!osd)
01261 return;
01262
01263 osd->EnableTeletext(false, 0);
01264 textDisplayMode = kDisplayNone;
01265
01266
01267
01268 if (prevTextDisplayMode & kDisplayAllCaptions)
01269 EnableCaptions(prevTextDisplayMode, false);
01270 }
01271
01272 void MythPlayer::ResetTeletext(void)
01273 {
01274 QMutexLocker locker(&osdLock);
01275 if (!osd)
01276 return;
01277
01278 osd->TeletextReset();
01279 }
01280
01284 void MythPlayer::SetTeletextPage(uint page)
01285 {
01286 osdLock.lock();
01287 DisableCaptions(textDisplayMode);
01288 ttPageNum = page;
01289 cc608.SetTTPageNum(ttPageNum);
01290 textDisplayMode &= ~kDisplayAllCaptions;
01291 textDisplayMode |= kDisplayNUVTeletextCaptions;
01292 osdLock.unlock();
01293 }
01294
01295 bool MythPlayer::HandleTeletextAction(const QString &action)
01296 {
01297 if (!(textDisplayMode & kDisplayTeletextMenu) || !osd)
01298 return false;
01299
01300 bool handled = true;
01301
01302 osdLock.lock();
01303 if (action == "MENU" || action == ACTION_TOGGLETT || action == "ESCAPE")
01304 DisableTeletext();
01305 else if (osd)
01306 handled = osd->TeletextAction(action);
01307 osdLock.unlock();
01308
01309 return handled;
01310 }
01311
01312 void MythPlayer::ResetCaptions(void)
01313 {
01314 QMutexLocker locker(&osdLock);
01315 if (!osd)
01316 return;
01317
01318 if (((textDisplayMode & kDisplayAVSubtitle) ||
01319 (textDisplayMode & kDisplayTextSubtitle) ||
01320 (textDisplayMode & kDisplayRawTextSubtitle) ||
01321 (textDisplayMode & kDisplayDVDButton) ||
01322 (textDisplayMode & kDisplayCC608) ||
01323 (textDisplayMode & kDisplayCC708)))
01324 {
01325 osd->ClearSubtitles();
01326 }
01327 else if ((textDisplayMode & kDisplayTeletextCaptions) ||
01328 (textDisplayMode & kDisplayNUVTeletextCaptions))
01329 {
01330 osd->TeletextClear();
01331 }
01332 }
01333
01334 void MythPlayer::DisableCaptions(uint mode, bool osd_msg)
01335 {
01336 if (textDisplayMode)
01337 prevNonzeroTextDisplayMode = textDisplayMode;
01338 textDisplayMode &= ~mode;
01339 ResetCaptions();
01340
01341 QMutexLocker locker(&osdLock);
01342
01343 QString msg = "";
01344 if (kDisplayNUVTeletextCaptions & mode)
01345 msg += QObject::tr("TXT CAP");
01346 if (kDisplayTeletextCaptions & mode)
01347 {
01348 msg += decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
01349 GetTrack(kTrackTypeTeletextCaptions));
01350 DisableTeletext();
01351 }
01352 int preserve = textDisplayMode & (kDisplayCC608 | kDisplayTextSubtitle |
01353 kDisplayAVSubtitle | kDisplayCC708 |
01354 kDisplayRawTextSubtitle);
01355 if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
01356 (kDisplayAVSubtitle & mode) || (kDisplayRawTextSubtitle & mode))
01357 {
01358 int type = toTrackType(mode);
01359 msg += decoder->GetTrackDesc(type, GetTrack(type));
01360 if (osd)
01361 osd->EnableSubtitles(preserve);
01362 }
01363 if (kDisplayTextSubtitle & mode)
01364 {
01365 msg += QObject::tr("Text subtitles");
01366 if (osd)
01367 osd->EnableSubtitles(preserve);
01368 }
01369 if (!msg.isEmpty() && osd_msg)
01370 {
01371 msg += " " + QObject::tr("Off");
01372 SetOSDMessage(msg, kOSDTimeout_Med);
01373 }
01374 }
01375
01376 void MythPlayer::EnableCaptions(uint mode, bool osd_msg)
01377 {
01378 QMutexLocker locker(&osdLock);
01379 QString msg = "";
01380 if ((kDisplayCC608 & mode) || (kDisplayCC708 & mode) ||
01381 (kDisplayAVSubtitle & mode) || kDisplayRawTextSubtitle & mode)
01382 {
01383 int type = toTrackType(mode);
01384 msg += decoder->GetTrackDesc(type, GetTrack(type));
01385 if (osd)
01386 osd->EnableSubtitles(mode);
01387 }
01388 if (kDisplayTextSubtitle & mode)
01389 {
01390 if (osd)
01391 osd->EnableSubtitles(kDisplayTextSubtitle);
01392 msg += QObject::tr("Text subtitles");
01393 }
01394 if (kDisplayNUVTeletextCaptions & mode)
01395 msg += QObject::tr("TXT") + QString(" %1").arg(ttPageNum, 3, 16);
01396 if (kDisplayTeletextCaptions & mode)
01397 {
01398 msg += decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
01399 GetTrack(kTrackTypeTeletextCaptions));
01400
01401 int page = decoder->GetTrackLanguageIndex(
01402 kTrackTypeTeletextCaptions,
01403 GetTrack(kTrackTypeTeletextCaptions));
01404
01405 EnableTeletext(page);
01406 textDisplayMode = kDisplayTeletextCaptions;
01407 }
01408
01409 msg += " " + QObject::tr("On");
01410
01411 LOG(VB_PLAYBACK, LOG_INFO, QString("EnableCaptions(%1) msg: %2")
01412 .arg(mode).arg(msg));
01413
01414 textDisplayMode = mode;
01415 if (textDisplayMode)
01416 prevNonzeroTextDisplayMode = textDisplayMode;
01417 if (osd_msg)
01418 SetOSDMessage(msg, kOSDTimeout_Med);
01419 }
01420
01421 bool MythPlayer::ToggleCaptions(void)
01422 {
01423 SetCaptionsEnabled(!((bool)textDisplayMode));
01424 return textDisplayMode;
01425 }
01426
01427 bool MythPlayer::ToggleCaptions(uint type)
01428 {
01429 QMutexLocker locker(&osdLock);
01430 uint mode = toCaptionType(type);
01431 uint origMode = textDisplayMode;
01432
01433 if (textDisplayMode)
01434 DisableCaptions(textDisplayMode, origMode & mode);
01435 if (origMode & mode)
01436 return textDisplayMode;
01437 if (mode)
01438 EnableCaptions(mode);
01439 return textDisplayMode;
01440 }
01441
01442 void MythPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
01443 {
01444 QMutexLocker locker(&osdLock);
01445 enableCaptions = disableCaptions = false;
01446 uint origMode = textDisplayMode;
01447
01448 textDesired = enable;
01449
01450 if (!enable)
01451 {
01452 DisableCaptions(origMode, osd_msg);
01453 return;
01454 }
01455 int mode = HasCaptionTrack(prevNonzeroTextDisplayMode) ?
01456 prevNonzeroTextDisplayMode : NextCaptionTrack(kDisplayNone);
01457 if (origMode != (uint)mode)
01458 {
01459 DisableCaptions(origMode, false);
01460
01461 if (kDisplayNone == mode)
01462 {
01463 if (osd_msg)
01464 {
01465 SetOSDMessage(QObject::tr(
01466 "No captions",
01467 "CC/Teletext/Subtitle text not available"),
01468 kOSDTimeout_Med);
01469 }
01470 LOG(VB_PLAYBACK, LOG_INFO,
01471 "No captions available yet to enable.");
01472 }
01473 else if (mode)
01474 {
01475 EnableCaptions(mode, osd_msg);
01476 }
01477 ResetCaptions();
01478 }
01479 }
01480
01481 bool MythPlayer::GetCaptionsEnabled(void)
01482 {
01483 return (kDisplayNUVTeletextCaptions == textDisplayMode) ||
01484 (kDisplayTeletextCaptions == textDisplayMode) ||
01485 (kDisplayAVSubtitle == textDisplayMode) ||
01486 (kDisplayCC608 == textDisplayMode) ||
01487 (kDisplayCC708 == textDisplayMode) ||
01488 (kDisplayTextSubtitle == textDisplayMode) ||
01489 (kDisplayRawTextSubtitle == textDisplayMode) ||
01490 (kDisplayTeletextMenu == textDisplayMode);
01491 }
01492
01493 QStringList MythPlayer::GetTracks(uint type)
01494 {
01495 if (decoder)
01496 return decoder->GetTracks(type);
01497 return QStringList();
01498 }
01499
01500 uint MythPlayer::GetTrackCount(uint type)
01501 {
01502 if (decoder)
01503 return decoder->GetTrackCount(type);
01504 return 0;
01505 }
01506
01507 int MythPlayer::SetTrack(uint type, int trackNo)
01508 {
01509 int ret = -1;
01510 if (!decoder)
01511 return ret;
01512
01513 ret = decoder->SetTrack(type, trackNo);
01514 if (kTrackTypeAudio == type)
01515 {
01516 QString msg = "";
01517 if (decoder)
01518 SetOSDMessage(decoder->GetTrackDesc(type, GetTrack(type)),
01519 kOSDTimeout_Med);
01520 return ret;
01521 }
01522
01523 uint subtype = toCaptionType(type);
01524 if (subtype)
01525 {
01526 DisableCaptions(textDisplayMode, false);
01527 EnableCaptions(subtype, true);
01528 if ((kDisplayCC708 == subtype || kDisplayCC608 == subtype) && decoder)
01529 {
01530 int sid = decoder->GetTrackInfo(type, trackNo).stream_id;
01531 if (sid >= 0)
01532 {
01533 (kDisplayCC708 == subtype) ? cc708.SetCurrentService(sid) :
01534 cc608.SetMode(sid);
01535 }
01536 }
01537 }
01538 return ret;
01539 }
01540
01546 void MythPlayer::TracksChanged(uint trackType)
01547 {
01548 if (trackType >= kTrackTypeSubtitle &&
01549 trackType <= kTrackTypeTeletextCaptions && textDesired)
01550 {
01551 enableCaptions = true;
01552 }
01553 }
01554
01555 void MythPlayer::EnableSubtitles(bool enable)
01556 {
01557 if (enable)
01558 enableCaptions = true;
01559 else
01560 disableCaptions = true;
01561 }
01562
01563 void MythPlayer::EnableForcedSubtitles(bool enable)
01564 {
01565 if (enable)
01566 enableForcedSubtitles = true;
01567 else
01568 disableForcedSubtitles = true;
01569 }
01570
01571 void MythPlayer::SetAllowForcedSubtitles(bool allow)
01572 {
01573 bool old = allowForcedSubtitles;
01574 allowForcedSubtitles = allow;
01575 SetOSDMessage(allowForcedSubtitles ?
01576 QObject::tr("Forced Subtitles On") :
01577 QObject::tr("Forced Subtitles Off"),
01578 kOSDTimeout_Med);
01579 if (old != allowForcedSubtitles)
01580 {
01581 gCoreContext->SaveSetting("AllowForcedSubtitles",
01582 allowForcedSubtitles);
01583 }
01584 }
01585
01586 void MythPlayer::DoDisableForcedSubtitles(void)
01587 {
01588 disableForcedSubtitles = false;
01589 osdLock.lock();
01590 if (osd)
01591 osd->DisableForcedSubtitles();
01592 osdLock.unlock();
01593 }
01594
01595 void MythPlayer::DoEnableForcedSubtitles(void)
01596 {
01597 enableForcedSubtitles = false;
01598 if (!allowForcedSubtitles)
01599 return;
01600
01601 osdLock.lock();
01602 if (osd)
01603 osd->EnableSubtitles(kDisplayAVSubtitle, true );
01604 osdLock.unlock();
01605 }
01606
01607 int MythPlayer::GetTrack(uint type)
01608 {
01609 if (decoder)
01610 return decoder->GetTrack(type);
01611 return -1;
01612 }
01613
01614 int MythPlayer::ChangeTrack(uint type, int dir)
01615 {
01616 if (!decoder)
01617 return -1;
01618
01619 int retval = decoder->ChangeTrack(type, dir);
01620 if (retval >= 0)
01621 {
01622 SetOSDMessage(decoder->GetTrackDesc(type, GetTrack(type)),
01623 kOSDTimeout_Med);
01624 return retval;
01625 }
01626 return -1;
01627 }
01628
01629 void MythPlayer::ChangeCaptionTrack(int dir)
01630 {
01631 if (!decoder || (dir < 0))
01632 return;
01633
01634 if (!((textDisplayMode == kDisplayTextSubtitle) ||
01635 (textDisplayMode == kDisplayNUVTeletextCaptions) ||
01636 (textDisplayMode == kDisplayNone)))
01637 {
01638 int tracktype = toTrackType(textDisplayMode);
01639 if (GetTrack(tracktype) < decoder->NextTrack(tracktype))
01640 {
01641 SetTrack(tracktype, decoder->NextTrack(tracktype));
01642 return;
01643 }
01644 }
01645 int nextmode = NextCaptionTrack(textDisplayMode);
01646 if ((nextmode == kDisplayTextSubtitle) ||
01647 (nextmode == kDisplayNUVTeletextCaptions) ||
01648 (nextmode == kDisplayNone))
01649 {
01650 DisableCaptions(textDisplayMode, true);
01651 if (nextmode != kDisplayNone)
01652 EnableCaptions(nextmode, true);
01653 }
01654 else
01655 {
01656 int tracktype = toTrackType(nextmode);
01657 int tracks = decoder->GetTrackCount(tracktype);
01658 if (tracks)
01659 {
01660 DisableCaptions(textDisplayMode, true);
01661 SetTrack(tracktype, 0);
01662 }
01663 }
01664 }
01665
01666 bool MythPlayer::HasCaptionTrack(int mode)
01667 {
01668 if (mode == kDisplayNone)
01669 return false;
01670 if (((mode == kDisplayTextSubtitle) && HasTextSubtitles()) ||
01671 (mode == kDisplayNUVTeletextCaptions))
01672 {
01673 return true;
01674 }
01675 else if (!(mode == kDisplayTextSubtitle) &&
01676 decoder->GetTrackCount(toTrackType(mode)))
01677 {
01678 return true;
01679 }
01680 return false;
01681 }
01682
01683 int MythPlayer::NextCaptionTrack(int mode)
01684 {
01685
01686
01687 bool pal = (vbimode == VBIMode::PAL_TT);
01688 int nextmode = kDisplayNone;
01689
01690 if (kDisplayTextSubtitle == mode)
01691 nextmode = kDisplayRawTextSubtitle;
01692 else if (kDisplayRawTextSubtitle == mode)
01693 nextmode = kDisplayCC708;
01694 else if (kDisplayCC708 == mode)
01695 nextmode = kDisplayCC608;
01696 else if (kDisplayCC608 == mode)
01697 nextmode = kDisplayAVSubtitle;
01698 else if (kDisplayAVSubtitle == mode)
01699 nextmode = kDisplayTeletextCaptions;
01700 else if (kDisplayTeletextCaptions == mode)
01701 nextmode = pal ? kDisplayNUVTeletextCaptions : kDisplayNone;
01702 else if ((kDisplayNUVTeletextCaptions == mode) && pal)
01703 nextmode = kDisplayNone;
01704 else if (kDisplayNone == mode)
01705 nextmode = kDisplayTextSubtitle;
01706
01707 if (nextmode == kDisplayNone || HasCaptionTrack(nextmode))
01708 return nextmode;
01709
01710 return NextCaptionTrack(nextmode);
01711 }
01712
01713 void MythPlayer::SetFrameInterval(FrameScanType scan, double frame_period)
01714 {
01715 frame_interval = (int)(1000000.0f * frame_period + 0.5f);
01716 if (!avsync_predictor_enabled)
01717 avsync_predictor = 0;
01718 avsync_predictor_enabled = false;
01719
01720 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SetFrameInterval ps:%1 scan:%2")
01721 .arg(play_speed).arg(scan));
01722 if (play_speed < 1 || play_speed > 2 || refreshrate <= 0)
01723 return;
01724
01725 avsync_predictor_enabled = ((frame_interval-(frame_interval/200)) <
01726 refreshrate);
01727 }
01728
01729 void MythPlayer::ResetAVSync(void)
01730 {
01731 avsync_avg = 0;
01732 if (!avsync_predictor_enabled || avsync_predictor >= refreshrate)
01733 avsync_predictor = 0;
01734 prevtc = 0;
01735 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "A/V sync reset");
01736 }
01737
01738 void MythPlayer::InitAVSync(void)
01739 {
01740 videosync->Start();
01741
01742 avsync_adjustment = 0;
01743
01744 repeat_delay = 0;
01745
01746 refreshrate = MythDisplay::GetDisplayInfo(frame_interval).Rate();
01747
01748 if (!FlagIsSet(kVideoIsNull))
01749 {
01750 QString timing_type = videosync->getName();
01751
01752 QString msg = QString("Video timing method: %1").arg(timing_type);
01753 LOG(VB_GENERAL, LOG_INFO, LOC + msg);
01754 msg = QString("Display Refresh Rate: %1 Video Frame Rate: %2")
01755 .arg(1000000.0 / refreshrate, 0, 'f', 3)
01756 .arg(1000000.0 / frame_interval, 0, 'f', 3);
01757 LOG(VB_PLAYBACK, LOG_INFO, LOC + msg);
01758
01759 SetFrameInterval(m_scan, 1.0 / (video_frame_rate * play_speed));
01760
01761
01762 myth_nice(-19);
01763 }
01764 }
01765
01766 int64_t MythPlayer::AVSyncGetAudiotime(void)
01767 {
01768 int64_t currentaudiotime = 0;
01769 if (normal_speed)
01770 {
01771 currentaudiotime = audio.GetAudioTime();
01772 }
01773 return currentaudiotime;
01774 }
01775
01776 #define MAXDIVERGE 3.0f
01777 #define DIVERGELIMIT 30.0f
01778 void MythPlayer::AVSync(VideoFrame *buffer, bool limit_delay)
01779 {
01780 int repeat_pict = 0;
01781 int64_t timecode = audio.GetAudioTime();
01782
01783 if (buffer)
01784 {
01785 repeat_pict = buffer->repeat_pict;
01786 timecode = buffer->timecode;
01787 disp_timecode = buffer->disp_timecode;
01788 }
01789
01790 float diverge = 0.0f;
01791 int frameDelay = m_double_framerate ? frame_interval / 2 : frame_interval;
01792 int vsync_delay_clock = 0;
01793
01794
01795 if (videoOutput->IsErrored())
01796 {
01797 LOG(VB_GENERAL, LOG_ERR, LOC +
01798 "AVSync: Unknown error in videoOutput, aborting playback.");
01799 SetErrored(QObject::tr("Failed to initialize A/V Sync"));
01800 return;
01801 }
01802
01803 if (normal_speed)
01804 {
01805 diverge = (float)avsync_avg / (float)frame_interval;
01806 diverge = max(diverge, -DIVERGELIMIT);
01807 diverge = min(diverge, +DIVERGELIMIT);
01808 }
01809
01810 FrameScanType ps = m_scan;
01811 if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
01812 ps = kScan_Progressive;
01813
01814 bool max_video_behind = diverge < -MAXDIVERGE;
01815 bool dropframe = false;
01816 QString dbg;
01817
01818 if (avsync_predictor_enabled)
01819 {
01820 avsync_predictor += frame_interval;
01821 if (avsync_predictor >= refreshrate)
01822 {
01823 int refreshperiodsinframe = avsync_predictor/refreshrate;
01824 avsync_predictor -= refreshrate * refreshperiodsinframe;
01825 }
01826 else
01827 {
01828 dropframe = true;
01829 dbg = "A/V predict drop frame, ";
01830 }
01831 }
01832
01833 if (max_video_behind)
01834 {
01835 dropframe = true;
01836
01837 dbg = QString("Video is %1 frames behind audio (too slow), ")
01838 .arg(-diverge);
01839 }
01840
01841 if (!dropframe && avsync_audiopaused)
01842 {
01843 avsync_audiopaused = false;
01844 audio.Pause(false);
01845 }
01846
01847 if (dropframe)
01848 {
01849
01850 lastsync = true;
01851
01852 LOG(VB_PLAYBACK, LOG_INFO, LOC + dbg + "dropping frame to catch up.");
01853 if (!audio.IsPaused() && max_video_behind)
01854 {
01855 audio.Pause(true);
01856 avsync_audiopaused = true;
01857 }
01858 }
01859 else if (!FlagIsSet(kVideoIsNull))
01860 {
01861
01862 osdLock.lock();
01863 videoOutput->PrepareFrame(buffer, ps, osd);
01864 osdLock.unlock();
01865 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO,
01866 LOC + QString("AVSync waitforframe %1 %2")
01867 .arg(avsync_adjustment).arg(m_double_framerate));
01868 vsync_delay_clock = videosync->WaitForFrame
01869 (frameDelay + avsync_adjustment + repeat_delay);
01870
01871 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC + "AVSync show");
01872 videoOutput->Show(ps);
01873
01874 if (videoOutput->IsErrored())
01875 {
01876 LOG(VB_GENERAL, LOG_ERR, LOC + "Error condition detected "
01877 "in videoOutput after Show(), aborting playback.");
01878 SetErrored(QObject::tr("Serious error detected in Video Output"));
01879 return;
01880 }
01881
01882 if (m_double_framerate)
01883 {
01884
01885 ps = (kScan_Intr2ndField == ps) ?
01886 kScan_Interlaced : kScan_Intr2ndField;
01887 osdLock.lock();
01888 if (m_double_process && ps != kScan_Progressive)
01889 {
01890 videofiltersLock.lock();
01891 videoOutput->ProcessFrame(
01892 buffer, osd, videoFilters, pip_players, ps);
01893 videofiltersLock.unlock();
01894 }
01895
01896 videoOutput->PrepareFrame(buffer, ps, osd);
01897 osdLock.unlock();
01898
01899 vsync_delay_clock = videosync->WaitForFrame(frameDelay +
01900 avsync_adjustment);
01901 videoOutput->Show(ps);
01902 }
01903
01904 repeat_delay = frame_interval * repeat_pict * 0.5;
01905
01906 if (repeat_delay)
01907 LOG(VB_TIMESTAMP, LOG_INFO, LOC +
01908 QString("A/V repeat_pict, adding %1 repeat delay")
01909 .arg(repeat_delay));
01910 }
01911 else
01912 {
01913 vsync_delay_clock = videosync->WaitForFrame(frameDelay);
01914
01915 }
01916
01917 if (output_jmeter && output_jmeter->RecordCycleTime())
01918 {
01919 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
01920 QString("A/V avsync_delay: %1, avsync_avg: %2")
01921 .arg(avsync_delay / 1000).arg(avsync_avg / 1000));
01922 }
01923
01924 avsync_adjustment = 0;
01925
01926 if (diverge > MAXDIVERGE)
01927 {
01928
01929
01930 avsync_adjustment = frame_interval;
01931 lastsync = true;
01932 LOG(VB_PLAYBACK, LOG_INFO, LOC +
01933 QString("Video is %1 frames ahead of audio,\n"
01934 "\t\t\tdoubling video frame interval to slow down.")
01935 .arg(diverge));
01936 }
01937
01938 if (audio.HasAudioOut() && normal_speed)
01939 {
01940
01941 int64_t currentaudiotime = audio.GetAudioTime();
01942 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
01943 QString("A/V timecodes audio %1 video %2 frameinterval %3 "
01944 "avdel %4 avg %5 tcoffset %6 avp %7 avpen %8 avdc %9")
01945 .arg(currentaudiotime)
01946 .arg(timecode)
01947 .arg(frame_interval)
01948 .arg(timecode - currentaudiotime -
01949 (int)(vsync_delay_clock*audio.GetStretchFactor()+500)/1000)
01950 .arg(avsync_avg)
01951 .arg(tc_wrap[TC_AUDIO])
01952 .arg(avsync_predictor)
01953 .arg(avsync_predictor_enabled)
01954 .arg(vsync_delay_clock)
01955 );
01956 if (currentaudiotime != 0 && timecode != 0)
01957 {
01958
01959
01960 if (prevtc != 0)
01961 {
01962 int delta = (int)((timecode - prevtc)/play_speed) -
01963 (frame_interval / 1000);
01964
01965 if (delta > (int) frame_interval / 1200 &&
01966 delta < (int) frame_interval / 1000 * 3 &&
01967 prevrp == 0)
01968 {
01969
01970 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
01971 QString("A/V delay %1").arg(delta));
01972 avsync_adjustment += frame_interval;
01973 }
01974 }
01975 prevtc = timecode;
01976 prevrp = repeat_pict;
01977
01978
01979 avsync_delay = (timecode - currentaudiotime) * 1000 -
01980 (int)(vsync_delay_clock*audio.GetStretchFactor());
01981
01982
01983 if (avsync_delay > 2000000 && limit_delay)
01984 avsync_delay = 90000;
01985 avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;
01986
01987 int avsync_used = avsync_avg;
01988 if (labs(avsync_used) > labs(avsync_delay))
01989 avsync_used = avsync_delay;
01990
01991
01992
01993 if (!lastsync)
01994 {
01995 if (avsync_used > refreshrate)
01996 {
01997 avsync_adjustment += refreshrate;
01998 }
01999 else if (avsync_used < 0 - refreshrate)
02000 {
02001 avsync_adjustment -= refreshrate;
02002 }
02003 }
02004 else
02005 lastsync = false;
02006 }
02007 else
02008 {
02009 ResetAVSync();
02010 }
02011 }
02012 else
02013 {
02014 LOG(VB_PLAYBACK | VB_TIMESTAMP, LOG_INFO, LOC +
02015 QString("A/V no sync proc ns:%1").arg(normal_speed));
02016 }
02017 }
02018
02019 void MythPlayer::RefreshPauseFrame(void)
02020 {
02021 if (needNewPauseFrame)
02022 {
02023 if (videoOutput->ValidVideoFrames())
02024 {
02025 videoOutput->UpdatePauseFrame(disp_timecode);
02026 needNewPauseFrame = false;
02027 }
02028 else
02029 {
02030 decodeOneFrame = true;
02031 }
02032 }
02033 }
02034
02035 void MythPlayer::DisplayPauseFrame(void)
02036 {
02037 if (!videoOutput || ! videosync)
02038 return;
02039
02040 if (videoOutput->IsErrored())
02041 {
02042 SetErrored(QObject::tr("Serious error detected in Video Output"));
02043 return;
02044 }
02045
02046
02047 SetBuffering(false);
02048
02049 RefreshPauseFrame();
02050
02051 osdLock.lock();
02052 videofiltersLock.lock();
02053 videoOutput->ProcessFrame(NULL, osd, videoFilters, pip_players);
02054 videofiltersLock.unlock();
02055 videoOutput->PrepareFrame(NULL, kScan_Ignore, osd);
02056 osdLock.unlock();
02057 videoOutput->Show(kScan_Ignore);
02058 videosync->Start();
02059 }
02060
02061 void MythPlayer::SetBuffering(bool new_buffering)
02062 {
02063 if (!buffering && new_buffering)
02064 {
02065 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waiting for video buffers...");
02066 buffering = true;
02067 buffering_start = QTime::currentTime();
02068 buffering_last_msg = QTime::currentTime();
02069 }
02070 else if (buffering && !new_buffering)
02071 {
02072 buffering = false;
02073 }
02074 }
02075
02076 bool MythPlayer::PrebufferEnoughFrames(int min_buffers)
02077 {
02078 if (!videoOutput)
02079 return false;
02080
02081 if (!(min_buffers ? (videoOutput->ValidVideoFrames() >= min_buffers) :
02082 (videoOutput->hasHWAcceleration() ?
02083 videoOutput->EnoughPrebufferedFrames() :
02084 videoOutput->EnoughDecodedFrames())))
02085 {
02086 SetBuffering(true);
02087 usleep(frame_interval >> 3);
02088 int waited_for = buffering_start.msecsTo(QTime::currentTime());
02089 int last_msg = buffering_last_msg.msecsTo(QTime::currentTime());
02090 if (last_msg > 100)
02091 {
02092 LOG(VB_GENERAL, LOG_NOTICE, LOC +
02093 QString("Waited %1ms for video buffers %2")
02094 .arg(waited_for).arg(videoOutput->GetFrameStatus()));
02095 buffering_last_msg = QTime::currentTime();
02096 if (audio.IsBufferAlmostFull())
02097 {
02098
02099
02100 LOG(VB_AUDIO, LOG_INFO, LOC + "Resetting audio buffer");
02101 audio.Reset();
02102 }
02103 }
02104 if ((waited_for > 500) && !videoOutput->EnoughFreeFrames())
02105 {
02106 LOG(VB_GENERAL, LOG_NOTICE, LOC +
02107 "Timed out waiting for frames, and"
02108 "\n\t\t\tthere are not enough free frames. "
02109 "Discarding buffered frames.");
02110
02111
02112 DiscardVideoFrames(true);
02113 }
02114 if (waited_for > 20000)
02115 {
02116 LOG(VB_GENERAL, LOG_ERR, LOC +
02117 "Waited too long for decoder to fill video buffers. Exiting..");
02118 SetErrored(QObject::tr("Video frame buffering failed too many "
02119 "times."));
02120 }
02121 if (normal_speed)
02122 videosync->Start();
02123 return false;
02124 }
02125
02126 SetBuffering(false);
02127 return true;
02128 }
02129
02130 void MythPlayer::CheckAspectRatio(VideoFrame* frame)
02131 {
02132 if (!frame)
02133 return;
02134
02135 if (!qFuzzyCompare(frame->aspect, video_aspect) && frame->aspect > 0.0f)
02136 {
02137 LOG(VB_PLAYBACK, LOG_INFO, LOC +
02138 QString("Video Aspect ratio changed from %1 to %2")
02139 .arg(video_aspect).arg(frame->aspect));
02140 video_aspect = frame->aspect;
02141 if (videoOutput)
02142 {
02143 videoOutput->VideoAspectRatioChanged(video_aspect);
02144 ReinitOSD();
02145 }
02146 }
02147 }
02148
02149 void MythPlayer::DisplayNormalFrame(bool check_prebuffer)
02150 {
02151 if (allpaused || (check_prebuffer && !PrebufferEnoughFrames()))
02152 return;
02153
02154
02155 SetBuffering(false);
02156
02157
02158 videoOutput->StartDisplayingFrame();
02159 VideoFrame *frame = videoOutput->GetLastShownFrame();
02160
02161
02162 CheckAspectRatio(frame);
02163
02164
02165 PreProcessNormalFrame();
02166
02167
02168 AutoDeint(frame);
02169 detect_letter_box->SwitchTo(frame);
02170
02171 FrameScanType ps = m_scan;
02172 if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
02173 ps = kScan_Progressive;
02174
02175 osdLock.lock();
02176 videofiltersLock.lock();
02177 videoOutput->ProcessFrame(frame, osd, videoFilters, pip_players, ps);
02178 videofiltersLock.unlock();
02179 osdLock.unlock();
02180
02181 AVSync(frame, 0);
02182 videoOutput->DoneDisplayingFrame(frame);
02183 }
02184
02185 void MythPlayer::PreProcessNormalFrame(void)
02186 {
02187 #ifdef USING_MHEG
02188
02189 if (GetInteractiveTV())
02190 {
02191 osdLock.lock();
02192 itvLock.lock();
02193 if (osd && videoOutput->GetOSDPainter())
02194 {
02195 InteractiveScreen *window =
02196 (InteractiveScreen*)osd->GetWindow(OSD_WIN_INTERACT);
02197 if ((interactiveTV->ImageHasChanged() || !itvVisible) && window)
02198 {
02199 interactiveTV->UpdateOSD(window, videoOutput->GetOSDPainter());
02200 itvVisible = true;
02201 }
02202 }
02203 itvLock.unlock();
02204 osdLock.unlock();
02205 }
02206 #endif // USING_MHEG
02207 }
02208
02209 bool MythPlayer::CanSupportDoubleRate(void)
02210 {
02211 if (!videosync)
02212 return false;
02213 return (frame_interval / 2 > videosync->getRefreshInterval() * 0.995);
02214 }
02215
02216 void MythPlayer::EnableFrameRateMonitor(bool enable)
02217 {
02218 if (!output_jmeter)
02219 return;
02220 int rate = enable ? video_frame_rate :
02221 VERBOSE_LEVEL_CHECK(VB_PLAYBACK, LOG_ANY) ?
02222 (video_frame_rate * 4) : 0;
02223 output_jmeter->SetNumCycles(rate);
02224 }
02225
02226 void MythPlayer::ForceDeinterlacer(const QString &override)
02227 {
02228 if (!videoOutput)
02229 return;
02230
02231 bool normal = play_speed > 0.99f && play_speed < 1.01f && normal_speed;
02232 videofiltersLock.lock();
02233
02234 m_double_framerate =
02235 videoOutput->SetupDeinterlace(true, override) &&
02236 videoOutput->NeedsDoubleFramerate();
02237 m_double_process = videoOutput->IsExtraProcessingRequired();
02238
02239 if ((m_double_framerate && !CanSupportDoubleRate()) || !normal)
02240 FallbackDeint();
02241
02242 videofiltersLock.unlock();
02243 }
02244
02245 void MythPlayer::VideoStart(void)
02246 {
02247 if (!FlagIsSet(kVideoIsNull) && !player_ctx->IsPIP())
02248 {
02249 QRect visible, total;
02250 float aspect, scaling;
02251
02252 osdLock.lock();
02253 osd = new OSD(this, m_tv, videoOutput->GetOSDPainter());
02254
02255 videoOutput->GetOSDBounds(total, visible, aspect, scaling, 1.0f);
02256 osd->Init(visible, aspect);
02257 videoOutput->InitOSD(osd);
02258 osd->EnableSubtitles(kDisplayNone);
02259
02260 #ifdef USING_MHEG
02261 if (GetInteractiveTV())
02262 {
02263 QMutexLocker locker(&itvLock);
02264 total = videoOutput->GetMHEGBounds();
02265 interactiveTV->Reinit(total);
02266 }
02267 #endif // USING_MHEG
02268
02269 SetCaptionsEnabled(captionsEnabledbyDefault, false);
02270 osdLock.unlock();
02271 }
02272
02273 SetPlaying(true);
02274 ClearAfterSeek(false);
02275
02276 avsync_delay = 0;
02277 avsync_avg = 0;
02278 refreshrate = 0;
02279 lastsync = false;
02280
02281 EnableFrameRateMonitor();
02282 refreshrate = frame_interval;
02283
02284 float temp_speed = (play_speed == 0.0) ? audio.GetStretchFactor() : play_speed;
02285 int fr_int = (1000000.0 / video_frame_rate / temp_speed);
02286 int rf_int = MythDisplay::GetDisplayInfo(fr_int).Rate();
02287
02288
02289
02290
02291
02292 m_scan = kScan_Interlaced;
02293 m_scan_locked = false;
02294 m_double_framerate = false;
02295 m_scan_tracker = 2;
02296
02297 if (player_ctx->IsPIP() && FlagIsSet(kVideoIsNull))
02298 {
02299 videosync = new DummyVideoSync(videoOutput, fr_int, 0, false);
02300 }
02301 else if (FlagIsSet(kVideoIsNull))
02302 {
02303 videosync = new USleepVideoSync(videoOutput, fr_int, 0, false);
02304 }
02305 else if (videoOutput)
02306 {
02307
02308 m_double_framerate =
02309 (videoOutput->SetupDeinterlace(true) &&
02310 videoOutput->NeedsDoubleFramerate());
02311
02312 m_double_process = videoOutput->IsExtraProcessingRequired();
02313
02314 videosync = VideoSync::BestMethod(
02315 videoOutput, (uint)fr_int, (uint)rf_int, m_double_framerate);
02316
02317
02318 if (videosync != NULL && m_double_framerate)
02319 {
02320 if (!CanSupportDoubleRate())
02321 {
02322 LOG(VB_GENERAL, LOG_ERR, LOC +
02323 "Video sync method can't support double framerate "
02324 "(refresh rate too low for 2x deint)");
02325 FallbackDeint();
02326 }
02327 }
02328 }
02329 if (!videosync)
02330 {
02331 videosync = new BusyWaitVideoSync(
02332 videoOutput, fr_int, rf_int, m_double_framerate);
02333 }
02334
02335 InitAVSync();
02336 videosync->Start();
02337 }
02338
02339 bool MythPlayer::VideoLoop(void)
02340 {
02341 if (videoPaused || isDummy)
02342 {
02343 usleep(frame_interval);
02344 DisplayPauseFrame();
02345 }
02346 else
02347 DisplayNormalFrame();
02348
02349 if (FlagIsSet(kVideoIsNull) && decoder)
02350 decoder->UpdateFramesPlayed();
02351 else
02352 framesPlayed = videoOutput->GetFramesPlayed();
02353 return !IsErrored();
02354 }
02355
02356 void MythPlayer::VideoEnd(void)
02357 {
02358 osdLock.lock();
02359 vidExitLock.lock();
02360 delete osd;
02361 delete videosync;
02362 delete videoOutput;
02363 osd = NULL;
02364 videosync = NULL;
02365 videoOutput = NULL;
02366 vidExitLock.unlock();
02367 osdLock.unlock();
02368 }
02369
02370 bool MythPlayer::FastForward(float seconds)
02371 {
02372 if (!videoOutput)
02373 return false;
02374
02375 if (fftime <= 0)
02376 fftime = (long long)(seconds * video_frame_rate);
02377 return fftime > CalcMaxFFTime(fftime, false);
02378 }
02379
02380 bool MythPlayer::Rewind(float seconds)
02381 {
02382 if (!videoOutput)
02383 return false;
02384
02385 if (rewindtime <= 0)
02386 rewindtime = (long long)(seconds * video_frame_rate);
02387 return (uint64_t)rewindtime >= framesPlayed;
02388 }
02389
02390 bool MythPlayer::JumpToFrame(uint64_t frame)
02391 {
02392 if (!videoOutput)
02393 return false;
02394
02395 bool ret = false;
02396 fftime = rewindtime = 0;
02397 if (frame > framesPlayed)
02398 {
02399 fftime = frame - framesPlayed;
02400 ret = fftime > CalcMaxFFTime(fftime, false);
02401 }
02402 else if (frame < framesPlayed)
02403 {
02404 rewindtime = framesPlayed - frame;
02405 ret = fftime > CalcMaxFFTime(fftime, false);
02406 }
02407 return ret;
02408 }
02409
02410
02411 void MythPlayer::JumpChapter(int chapter)
02412 {
02413 if (jumpchapter == 0)
02414 jumpchapter = chapter;
02415 }
02416
02417 void MythPlayer::ResetPlaying(bool resetframes)
02418 {
02419 ClearAfterSeek();
02420 ffrew_skip = 1;
02421 if (resetframes)
02422 framesPlayed = 0;
02423 if (decoder)
02424 {
02425 decoder->Reset(true, true, true);
02426 if (decoder->IsErrored())
02427 SetErrored("Unable to reset video decoder");
02428 }
02429 }
02430
02431 void MythPlayer::CheckTVChain(void)
02432 {
02433 bool last = !(player_ctx->tvchain->HasNext());
02434 SetWatchingRecording(last);
02435 }
02436
02437 void MythPlayer::SwitchToProgram(void)
02438 {
02439 if (!IsReallyNearEnd())
02440 return;
02441
02442 LOG(VB_PLAYBACK, LOG_INFO, LOC + "SwitchToProgram - start");
02443 bool discontinuity = false, newtype = false;
02444 int newid = -1;
02445 ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
02446 discontinuity, newtype, newid);
02447 if (!pginfo)
02448 return;
02449
02450 bool newIsDummy = player_ctx->tvchain->GetCardType(newid) == "DUMMY";
02451
02452 SetPlayingInfo(*pginfo);
02453 Pause();
02454 ChangeSpeed();
02455
02456 if (newIsDummy)
02457 {
02458 OpenDummy();
02459 ResetPlaying();
02460 SetEof(false);
02461 delete pginfo;
02462 return;
02463 }
02464
02465 player_ctx->buffer->OpenFile(
02466 pginfo->GetPlaybackURL(), RingBuffer::kLiveTVOpenTimeout);
02467
02468 if (!player_ctx->buffer->IsOpen())
02469 {
02470 LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram's OpenFile failed " +
02471 QString("(card type: %1).")
02472 .arg(player_ctx->tvchain->GetCardType(newid)));
02473 LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString());
02474 SetEof(true);
02475 SetErrored(QObject::tr("Error opening switch program buffer"));
02476 delete pginfo;
02477 return;
02478 }
02479
02480 if (GetEof())
02481 {
02482 discontinuity = true;
02483 ResetCaptions();
02484 }
02485
02486 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("SwitchToProgram(void) "
02487 "discont: %1 newtype: %2 newid: %3 decoderEof: %4")
02488 .arg(discontinuity).arg(newtype).arg(newid).arg(GetEof()));
02489
02490 if (discontinuity || newtype)
02491 {
02492 player_ctx->tvchain->SetProgram(*pginfo);
02493 if (decoder)
02494 decoder->SetProgramInfo(*pginfo);
02495
02496 player_ctx->buffer->Reset(true);
02497 if (newtype)
02498 {
02499 if (OpenFile() < 0)
02500 SetErrored(QObject::tr("Error opening switch program file"));
02501 }
02502 else
02503 ResetPlaying();
02504 }
02505 else
02506 {
02507 player_ctx->SetPlayerChangingBuffers(true);
02508 if (decoder)
02509 {
02510 decoder->SetReadAdjust(player_ctx->buffer->SetAdjustFilesize());
02511 decoder->SetWaitForChange();
02512 }
02513 }
02514 delete pginfo;
02515
02516 if (IsErrored())
02517 {
02518 LOG(VB_GENERAL, LOG_ERR, LOC + "SwitchToProgram failed.");
02519 SetEof(true);
02520 return;
02521 }
02522
02523 SetEof(false);
02524
02525
02526 if (decoder)
02527 player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate());
02528 player_ctx->buffer->Unpause();
02529
02530 if (discontinuity || newtype)
02531 {
02532 CheckTVChain();
02533 forcePositionMapSync = true;
02534 }
02535
02536 Play();
02537 LOG(VB_PLAYBACK, LOG_INFO, LOC + "SwitchToProgram - end");
02538 }
02539
02540 void MythPlayer::FileChangedCallback(void)
02541 {
02542 LOG(VB_PLAYBACK, LOG_INFO, LOC + "FileChangedCallback");
02543
02544 Pause();
02545 ChangeSpeed();
02546 if (dynamic_cast<AvFormatDecoder *>(decoder))
02547 player_ctx->buffer->Reset(false, true);
02548 else
02549 player_ctx->buffer->Reset(false, true, true);
02550 SetEof(false);
02551 Play();
02552
02553 player_ctx->SetPlayerChangingBuffers(false);
02554
02555 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
02556 player_ctx->tvchain->SetProgram(*player_ctx->playingInfo);
02557 if (decoder)
02558 decoder->SetProgramInfo(*player_ctx->playingInfo);
02559 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
02560
02561 CheckTVChain();
02562 forcePositionMapSync = true;
02563 }
02564
02565 void MythPlayer::JumpToProgram(void)
02566 {
02567 LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToProgram - start");
02568 bool discontinuity = false, newtype = false;
02569 int newid = -1;
02570 long long nextpos = player_ctx->tvchain->GetJumpPos();
02571 ProgramInfo *pginfo = player_ctx->tvchain->GetSwitchProgram(
02572 discontinuity, newtype, newid);
02573 if (!pginfo)
02574 return;
02575
02576 inJumpToProgramPause = true;
02577
02578 bool newIsDummy = player_ctx->tvchain->GetCardType(newid) == "DUMMY";
02579 SetPlayingInfo(*pginfo);
02580
02581 Pause();
02582 ChangeSpeed();
02583 ResetCaptions();
02584 player_ctx->tvchain->SetProgram(*pginfo);
02585 player_ctx->buffer->Reset(true);
02586
02587 if (newIsDummy)
02588 {
02589 OpenDummy();
02590 ResetPlaying();
02591 SetEof(false);
02592 delete pginfo;
02593 inJumpToProgramPause = false;
02594 return;
02595 }
02596
02597 SendMythSystemPlayEvent("PLAY_CHANGED", pginfo);
02598
02599 player_ctx->buffer->OpenFile(
02600 pginfo->GetPlaybackURL(), RingBuffer::kLiveTVOpenTimeout);
02601
02602 if (!player_ctx->buffer->IsOpen())
02603 {
02604 LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToProgram's OpenFile failed " +
02605 QString("(card type: %1).")
02606 .arg(player_ctx->tvchain->GetCardType(newid)));
02607 LOG(VB_GENERAL, LOG_ERR, player_ctx->tvchain->toString());
02608 SetEof(true);
02609 SetErrored(QObject::tr("Error opening jump program file buffer"));
02610 delete pginfo;
02611 inJumpToProgramPause = false;
02612 return;
02613 }
02614
02615 bool wasDummy = isDummy;
02616 if (newtype || wasDummy)
02617 {
02618 if (OpenFile() < 0)
02619 SetErrored(QObject::tr("Error opening jump program file"));
02620 }
02621 else
02622 ResetPlaying();
02623
02624 if (IsErrored() || !decoder)
02625 {
02626 LOG(VB_GENERAL, LOG_ERR, LOC + "JumpToProgram failed.");
02627 if (!IsErrored())
02628 SetErrored(QObject::tr("Error reopening video decoder"));
02629 delete pginfo;
02630 inJumpToProgramPause = false;
02631 return;
02632 }
02633
02634 SetEof(false);
02635
02636
02637 player_ctx->buffer->UpdateRawBitrate(decoder->GetRawBitrate());
02638 player_ctx->buffer->IgnoreLiveEOF(false);
02639
02640 decoder->SetProgramInfo(*pginfo);
02641 delete pginfo;
02642
02643 CheckTVChain();
02644 forcePositionMapSync = true;
02645 inJumpToProgramPause = false;
02646 Play();
02647 ChangeSpeed();
02648
02649 if (nextpos < 0)
02650 nextpos += totalFrames;
02651 if (nextpos < 0)
02652 nextpos = 0;
02653
02654 if (nextpos > 10)
02655 DoJumpToFrame(nextpos, kInaccuracyNone);
02656
02657 player_ctx->SetPlayerChangingBuffers(false);
02658 LOG(VB_PLAYBACK, LOG_INFO, LOC + "JumpToProgram - end");
02659 }
02660
02661 bool MythPlayer::StartPlaying(void)
02662 {
02663 if (OpenFile() < 0)
02664 {
02665 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to open video file.");
02666 return false;
02667 }
02668
02669 framesPlayed = 0;
02670 rewindtime = fftime = 0;
02671 next_play_speed = audio.GetStretchFactor();
02672 jumpchapter = 0;
02673 commBreakMap.SkipCommercials(0);
02674
02675 if (!InitVideo())
02676 {
02677 LOG(VB_GENERAL, LOG_ERR, LOC + "Unable to initialize video.");
02678 audio.DeleteOutput();
02679 return false;
02680 }
02681
02682 bool seek = bookmarkseek > 30;
02683 EventStart();
02684 DecoderStart(true);
02685 if (seek)
02686 InitialSeek();
02687 VideoStart();
02688
02689 playerThread->setPriority(QThread::TimeCriticalPriority);
02690 UnpauseDecoder();
02691 return !IsErrored();
02692 }
02693
02694 void MythPlayer::InitialSeek(void)
02695 {
02696
02697 if (bookmarkseek > 30)
02698 {
02699 DoJumpToFrame(bookmarkseek, kInaccuracyNone);
02700 if (clearSavedPosition && !player_ctx->IsPIP())
02701 SetBookmark(true);
02702 }
02703 }
02704
02705
02706 void MythPlayer::StopPlaying()
02707 {
02708 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - begin"));
02709 playerThread->setPriority(QThread::NormalPriority);
02710
02711 DecoderEnd();
02712 VideoEnd();
02713 AudioEnd();
02714
02715 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("StopPlaying - end"));
02716 }
02717
02718 void MythPlayer::EventStart(void)
02719 {
02720 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
02721 {
02722 if (player_ctx->playingInfo)
02723 player_ctx->playingInfo->SetIgnoreBookmark(false);
02724 }
02725 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
02726 commBreakMap.LoadMap(player_ctx, framesPlayed);
02727 }
02728
02729 void MythPlayer::EventLoop(void)
02730 {
02731
02732 if (reinit_osd)
02733 ReinitOSD();
02734
02735
02736 if (enableCaptions)
02737 SetCaptionsEnabled(true, false);
02738 if (disableCaptions)
02739 SetCaptionsEnabled(false, false);
02740
02741
02742 if (enableForcedSubtitles)
02743 DoEnableForcedSubtitles();
02744 if (disableForcedSubtitles)
02745 DoDisableForcedSubtitles();
02746
02747
02748 if (resetScan != kScan_Ignore)
02749 SetScanType(resetScan);
02750
02751
02752 if (hasFullPositionMap && IsWatchingInprogress() && deleteMap.IsEditing())
02753 {
02754 if (editUpdateTimer.elapsed() > 2000)
02755 {
02756
02757 forcePositionMapSync = true;
02758 osdLock.lock();
02759 deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate,
02760 osd);
02761 osdLock.unlock();
02762 editUpdateTimer.start();
02763 }
02764 }
02765
02766
02767 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
02768 if (player_ctx->playingInfo)
02769 player_ctx->playingInfo->UpdateInUseMark();
02770 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
02771
02772
02773 if (ffrew_skip == 1 && (play_speed > 1.0f) && IsNearEnd())
02774 {
02775 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near end, Slowing down playback.");
02776 Play(1.0f, true, true);
02777 }
02778
02779 if (isDummy && player_ctx->tvchain && player_ctx->tvchain->HasNext())
02780 {
02781
02782 player_ctx->tvchain->JumpToNext(true, 1);
02783 JumpToProgram();
02784 }
02785 else if ((!allpaused || GetEof()) && player_ctx->tvchain &&
02786 (decoder && !decoder->GetWaitForChange()))
02787 {
02788
02789 if (player_ctx->tvchain->NeedsToSwitch())
02790 SwitchToProgram();
02791 }
02792
02793
02794 if (player_ctx->tvchain && player_ctx->tvchain->NeedsToJump())
02795 {
02796 JumpToProgram();
02797 }
02798
02799
02800 if (ffrew_skip > 1 && (CalcMaxFFTime(100, false) < 100))
02801 {
02802 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near end, stopping fastforward.");
02803 Play(1.0f, true, true);
02804 }
02805
02806
02807 if (CalcRWTime(-ffrew_skip) > 0 && (framesPlayed <= keyframedist))
02808 {
02809 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Near start, stopping rewind.");
02810 float stretch = (ffrew_skip > 0) ? 1.0f : audio.GetStretchFactor();
02811 Play(stretch, true, true);
02812 }
02813
02814
02815 if (IsErrored() || player_ctx->IsRecorderErrored())
02816 {
02817 LOG(VB_GENERAL, LOG_ERR, LOC +
02818 "Unknown recorder error, exiting decoder");
02819 if (!IsErrored())
02820 SetErrored(QObject::tr("Irrecoverable recorder error"));
02821 killdecoder = true;
02822 return;
02823 }
02824
02825
02826 if (play_speed != next_play_speed &&
02827 (!player_ctx->tvchain ||
02828 (player_ctx->tvchain && !player_ctx->tvchain->NeedsToJump())))
02829 {
02830 ChangeSpeed();
02831 return;
02832 }
02833
02834
02835 if (GetEof())
02836 {
02837 if (player_ctx->tvchain)
02838 {
02839 if (!allpaused && player_ctx->tvchain->HasNext())
02840 {
02841 LOG(VB_GENERAL, LOG_NOTICE, LOC + "LiveTV forcing JumpTo 1");
02842 player_ctx->tvchain->JumpToNext(true, 1);
02843 return;
02844 }
02845 }
02846 else if (!allpaused)
02847 {
02848 SetPlaying(false);
02849 return;
02850 }
02851 }
02852
02853
02854 if (rewindtime > 0 && (ffrew_skip == 1 || ffrew_skip == 0))
02855 {
02856 rewindtime = CalcRWTime(rewindtime);
02857 if (rewindtime > 0)
02858 DoRewind(rewindtime, kInaccuracyDefault);
02859 }
02860
02861
02862 if (fftime > 0 && (ffrew_skip == 1 || ffrew_skip == 0))
02863 {
02864 fftime = CalcMaxFFTime(fftime);
02865 if (fftime > 0)
02866 {
02867 DoFastForward(fftime, kInaccuracyDefault);
02868 if (GetEof())
02869 return;
02870 }
02871 }
02872
02873
02874 if (jumpchapter != 0)
02875 DoJumpChapter(jumpchapter);
02876
02877
02878 if (commBreakMap.GetSkipCommercials() != 0 && (ffrew_skip == 1))
02879 {
02880 if (!commBreakMap.HasMap())
02881 {
02882 SetOSDStatus(QObject::tr("Not Flagged"), kOSDTimeout_Med);
02883 QString message = "COMMFLAG_REQUEST ";
02884 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
02885 message += player_ctx->playingInfo->GetChanID() + " " +
02886 player_ctx->playingInfo->MakeUniqueKey();
02887 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
02888 gCoreContext->SendMessage(message);
02889 }
02890 else
02891 {
02892 QString msg;
02893 uint64_t jumpto = 0;
02894 bool jump = commBreakMap.DoSkipCommercials(jumpto, framesPlayed,
02895 video_frame_rate, totalFrames, msg);
02896 if (!msg.isEmpty())
02897 SetOSDStatus(msg, kOSDTimeout_Med);
02898 if (jump)
02899 DoJumpToFrame(jumpto, kInaccuracyNone);
02900 }
02901 commBreakMap.SkipCommercials(0);
02902 return;
02903 }
02904
02905
02906 uint64_t jumpto = 0;
02907 if (deleteMap.IsEmpty() && (ffrew_skip == 1) &&
02908 (kCommSkipOff != commBreakMap.GetAutoCommercialSkip()))
02909 {
02910 QString msg;
02911 bool jump = commBreakMap.AutoCommercialSkip(jumpto, framesPlayed,
02912 video_frame_rate,
02913 totalFrames, msg);
02914 if (!msg.isEmpty())
02915 SetOSDStatus(msg, kOSDTimeout_Med);
02916 if (jump)
02917 DoJumpToFrame(jumpto, kInaccuracyNone);
02918 }
02919
02920
02921 if (!allpaused && (ffrew_skip == 1) &&
02922 deleteMap.TrackerWantsToJump(framesPlayed, totalFrames, jumpto))
02923 {
02924 if (jumpto == totalFrames)
02925 {
02926 if (!(endExitPrompt == 1 && !player_ctx->IsPIP() &&
02927 player_ctx->GetState() == kState_WatchingPreRecorded))
02928 {
02929 SetEof(true);
02930 }
02931 }
02932 else
02933 {
02934 DoJumpToFrame(jumpto, kInaccuracyNone);
02935 }
02936 }
02937 }
02938
02939 void MythPlayer::AudioEnd(void)
02940 {
02941 audio.DeleteOutput();
02942 }
02943
02944 bool MythPlayer::PauseDecoder(void)
02945 {
02946 decoderPauseLock.lock();
02947 if (is_current_thread(decoderThread))
02948 {
02949 decoderPaused = true;
02950 decoderThreadPause.wakeAll();
02951 decoderPauseLock.unlock();
02952 return decoderPaused;
02953 }
02954
02955 int tries = 0;
02956 pauseDecoder = true;
02957 while (decoderThread && !killdecoder && (tries++ < 100) &&
02958 !decoderThreadPause.wait(&decoderPauseLock, 100))
02959 {
02960 LOG(VB_GENERAL, LOG_WARNING, LOC + "Waited 100ms for decoder to pause");
02961 }
02962 pauseDecoder = false;
02963 decoderPauseLock.unlock();
02964 return decoderPaused;
02965 }
02966
02967 void MythPlayer::UnpauseDecoder(void)
02968 {
02969 decoderPauseLock.lock();
02970
02971 if (is_current_thread(decoderThread))
02972 {
02973 decoderPaused = false;
02974 decoderThreadUnpause.wakeAll();
02975 decoderPauseLock.unlock();
02976 return;
02977 }
02978
02979 int tries = 0;
02980 unpauseDecoder = true;
02981 while (decoderThread && !killdecoder && (tries++ < 100) &&
02982 !decoderThreadUnpause.wait(&decoderPauseLock, 100))
02983 {
02984 LOG(VB_GENERAL, LOG_WARNING, LOC +
02985 "Waited 100ms for decoder to unpause");
02986 }
02987 unpauseDecoder = false;
02988 decoderPauseLock.unlock();
02989 }
02990
02991 void MythPlayer::DecoderStart(bool start_paused)
02992 {
02993 if (decoderThread)
02994 {
02995 if (decoderThread->isRunning())
02996 {
02997 LOG(VB_GENERAL, LOG_ERR, LOC + "Decoder thread already running");
02998 }
02999 delete decoderThread;
03000 }
03001
03002 killdecoder = false;
03003 decoderThread = new DecoderThread(this, start_paused);
03004 if (decoderThread)
03005 decoderThread->start();
03006 }
03007
03008 void MythPlayer::DecoderEnd(void)
03009 {
03010 PauseDecoder();
03011 SetPlaying(false);
03012 killdecoder = true;
03013 int tries = 0;
03014 while (decoderThread && !decoderThread->wait(100) && (tries++ < 50))
03015 LOG(VB_PLAYBACK, LOG_INFO, LOC +
03016 "Waited 100ms for decoder loop to stop");
03017
03018 if (decoderThread && decoderThread->isRunning())
03019 LOG(VB_GENERAL, LOG_ERR, LOC + "Failed to stop decoder loop.");
03020 else
03021 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Exited decoder loop.");
03022 }
03023
03024 void MythPlayer::DecoderPauseCheck(void)
03025 {
03026 if (is_current_thread(decoderThread))
03027 {
03028 if (pauseDecoder)
03029 PauseDecoder();
03030 if (unpauseDecoder)
03031 UnpauseDecoder();
03032 }
03033 }
03034
03036 bool MythPlayer::GetEof(void)
03037 {
03038 if (is_current_thread(playerThread))
03039 return decoder ? decoder->GetEof() : true;
03040
03041 if (!decoder_change_lock.tryLock(50))
03042 return false;
03043
03044 bool eof = decoder ? decoder->GetEof() : true;
03045 decoder_change_lock.unlock();
03046 return eof;
03047 }
03048
03049 void MythPlayer::SetEof(bool eof)
03050 {
03051 if (is_current_thread(playerThread))
03052 {
03053 if (decoder)
03054 decoder->SetEof(eof);
03055 return;
03056 }
03057
03058 if (!decoder_change_lock.tryLock(50))
03059 return;
03060
03061 if (decoder)
03062 decoder->SetEof(eof);
03063 decoder_change_lock.unlock();
03064 }
03066
03067 void MythPlayer::DecoderLoop(bool pause)
03068 {
03069 if (pause)
03070 PauseDecoder();
03071
03072 while (!killdecoder && !IsErrored())
03073 {
03074 DecoderPauseCheck();
03075
03076 if (totalDecoderPause || inJumpToProgramPause)
03077 {
03078 usleep(1000);
03079 continue;
03080 }
03081
03082 if (forcePositionMapSync)
03083 {
03084 if (!decoder_change_lock.tryLock(1))
03085 continue;
03086 if (decoder)
03087 {
03088 forcePositionMapSync = false;
03089 decoder->SyncPositionMap();
03090 }
03091 decoder_change_lock.unlock();
03092 }
03093
03094 if (decoderSeek >= 0)
03095 {
03096 if (!decoder_change_lock.tryLock(1))
03097 continue;
03098 if (decoder)
03099 {
03100 decoderSeekLock.lock();
03101 if (((uint64_t)decoderSeek < framesPlayed) && decoder)
03102 decoder->DoRewind(decoderSeek);
03103 else if (decoder)
03104 decoder->DoFastForward(decoderSeek);
03105 decoderSeek = -1;
03106 decoderSeekLock.unlock();
03107 }
03108 decoder_change_lock.unlock();
03109 }
03110
03111 bool obey_eof = GetEof() &&
03112 !(GetEof() && player_ctx->tvchain && !allpaused);
03113 if (isDummy || ((decoderPaused || ffrew_skip == 0 || obey_eof) &&
03114 !decodeOneFrame))
03115 {
03116 usleep(1000);
03117 continue;
03118 }
03119
03120 DecodeType dt = (audio.HasAudioOut() && normal_speed) ?
03121 kDecodeAV : kDecodeVideo;
03122
03123 DecoderGetFrame(dt);
03124 decodeOneFrame = false;
03125 }
03126
03127
03128 DecoderPauseCheck();
03129 decoderSeek = -1;
03130 }
03131
03132 bool MythPlayer::DecoderGetFrameFFREW(void)
03133 {
03134 if (ffrew_skip > 0)
03135 {
03136 long long delta = decoder->GetFramesRead() - framesPlayed;
03137 long long real_skip = CalcMaxFFTime(ffrew_skip - ffrew_adjust + delta) - delta;
03138 long long target_frame = decoder->GetFramesRead() + real_skip;
03139 if (real_skip >= 0)
03140 {
03141 decoder->DoFastForward(target_frame, false);
03142 }
03143 long long seek_frame = decoder->GetFramesRead();
03144 ffrew_adjust = seek_frame - target_frame;
03145 }
03146 else if (CalcRWTime(-ffrew_skip) >= 0)
03147 {
03148 DecoderGetFrameREW();
03149 }
03150 return decoder->GetFrame(kDecodeVideo);
03151 }
03152
03153 bool MythPlayer::DecoderGetFrameREW(void)
03154 {
03155 long long cur_frame = decoder->GetFramesPlayed();
03156 bool toBegin = -cur_frame > ffrew_skip + ffrew_adjust;
03157 long long real_skip = (toBegin) ? -cur_frame : ffrew_skip + ffrew_adjust;
03158 long long target_frame = cur_frame + real_skip;
03159 bool ret = decoder->DoRewind(target_frame, false);
03160 long long seek_frame = decoder->GetFramesPlayed();
03161 ffrew_adjust = target_frame - seek_frame;
03162 return ret;
03163 }
03164
03165 bool MythPlayer::DecoderGetFrame(DecodeType decodetype, bool unsafe)
03166 {
03167 bool ret = false;
03168 if (!videoOutput)
03169 return false;
03170
03171
03172 if (!videoOutput->EnoughFreeFrames() && !unsafe && !killdecoder)
03173 {
03174 int tries = 0;
03175 while (!videoOutput->EnoughFreeFrames() && (tries++ < 10))
03176 usleep(1000);
03177 if (!videoOutput->EnoughFreeFrames())
03178 {
03179 if (++videobuf_retries >= 2000)
03180 {
03181 LOG(VB_GENERAL, LOG_ERR, LOC +
03182 "Decoder timed out waiting for free video buffers.");
03183 videobuf_retries = 0;
03184 }
03185 return false;
03186 }
03187 }
03188 videobuf_retries = 0;
03189
03190 if (!decoder_change_lock.tryLock(5))
03191 return false;
03192 if (killdecoder || !decoder || IsErrored())
03193 {
03194 decoder_change_lock.unlock();
03195 return false;
03196 }
03197
03198 if (ffrew_skip == 1 || decodeOneFrame)
03199 ret = decoder->GetFrame(decodetype);
03200 else if (ffrew_skip != 0)
03201 ret = DecoderGetFrameFFREW();
03202 decoder_change_lock.unlock();
03203 return ret;
03204 }
03205
03206 void MythPlayer::SetTranscoding(bool value)
03207 {
03208 transcoding = value;
03209
03210 if (decoder)
03211 decoder->SetTranscoding(value);
03212 }
03213
03214 bool MythPlayer::AddPIPPlayer(MythPlayer *pip, PIPLocation loc, uint timeout)
03215 {
03216 if (!is_current_thread(playerThread))
03217 {
03218 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot add PiP from another thread");
03219 return false;
03220 }
03221
03222 if (pip_players.contains(pip))
03223 {
03224 LOG(VB_GENERAL, LOG_ERR, LOC + "PiPMap already contains PiP.");
03225 return false;
03226 }
03227
03228 QList<PIPLocation> locs = pip_players.values();
03229 if (locs.contains(loc))
03230 {
03231 LOG(VB_GENERAL, LOG_ERR, LOC +"Already have a PiP at that location.");
03232 return false;
03233 }
03234
03235 pip_players.insert(pip, loc);
03236 return true;
03237 }
03238
03239 bool MythPlayer::RemovePIPPlayer(MythPlayer *pip, uint timeout)
03240 {
03241 if (!is_current_thread(playerThread))
03242 return false;
03243
03244 if (!pip_players.contains(pip))
03245 return false;
03246
03247 pip_players.remove(pip);
03248 if (videoOutput)
03249 videoOutput->RemovePIP(pip);
03250 return true;
03251 }
03252
03253 PIPLocation MythPlayer::GetNextPIPLocation(void) const
03254 {
03255 if (!is_current_thread(playerThread))
03256 return kPIP_END;
03257
03258 if (pip_players.isEmpty())
03259 return pip_default_loc;
03260
03261
03262 PIPLocation ols[] =
03263 { kPIPTopLeft, kPIPTopRight, kPIPBottomLeft, kPIPBottomRight };
03264
03265 for (uint i = 0; i < sizeof(ols)/sizeof(PIPLocation); i++)
03266 {
03267 PIPMap::const_iterator it = pip_players.begin();
03268 for (; it != pip_players.end() && (*it != ols[i]); ++it);
03269
03270 if (it == pip_players.end())
03271 return ols[i];
03272 }
03273
03274 return kPIP_END;
03275 }
03276
03277 int64_t MythPlayer::AdjustAudioTimecodeOffset(int64_t v, int newsync)
03278 {
03279 if ((newsync >= -1000) && (newsync <= 1000))
03280 tc_wrap[TC_AUDIO] = newsync;
03281 else
03282 tc_wrap[TC_AUDIO] += v;
03283 gCoreContext->SaveSetting("AudioSyncOffset", tc_wrap[TC_AUDIO]);
03284 return tc_wrap[TC_AUDIO];
03285 }
03286
03287 void MythPlayer::WrapTimecode(int64_t &timecode, TCTypes tc_type)
03288 {
03289 timecode += tc_wrap[tc_type];
03290 }
03291
03292 bool MythPlayer::PrepareAudioSample(int64_t &timecode)
03293 {
03294 WrapTimecode(timecode, TC_AUDIO);
03295 return false;
03296 }
03297
03312 void MythPlayer::SetWatched(bool forceWatched)
03313 {
03314 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03315 if (!player_ctx->playingInfo)
03316 {
03317 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03318 return;
03319 }
03320
03321 long long numFrames = totalFrames;
03322
03323
03324
03325
03326
03327 if (player_ctx->playingInfo->IsRecording() &&
03328 player_ctx->playingInfo->QueryTranscodeStatus() !=
03329 TRANSCODING_COMPLETE)
03330 {
03331 uint endtime;
03332
03333
03334
03335 if (player_ctx->playingInfo->GetRecordingEndTime().toTime_t() <
03336 player_ctx->playingInfo->GetScheduledEndTime().toTime_t())
03337 {
03338 endtime = player_ctx->playingInfo->GetRecordingEndTime().toTime_t();
03339 }
03340 else
03341 {
03342 endtime = player_ctx->playingInfo->GetScheduledEndTime().toTime_t();
03343 }
03344
03345 numFrames = (long long)
03346 ((endtime -
03347 player_ctx->playingInfo->GetRecordingStartTime().toTime_t()) *
03348 video_frame_rate);
03349 }
03350
03351 int offset = (int) round(0.14 * (numFrames / video_frame_rate));
03352
03353 if (offset < 240)
03354 offset = 240;
03355 else if (offset > 720)
03356 offset = 720;
03357
03358 if (forceWatched || framesPlayed > numFrames - (offset * video_frame_rate))
03359 {
03360 player_ctx->playingInfo->SaveWatched(true);
03361 LOG(VB_GENERAL, LOG_INFO, LOC +
03362 QString("Marking recording as watched using offset %1 minutes")
03363 .arg(offset/60));
03364 }
03365
03366 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03367 }
03368
03369 void MythPlayer::SetBookmark(bool clear)
03370 {
03371 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03372 if (player_ctx->playingInfo)
03373 player_ctx->playingInfo->SaveBookmark(clear ? 0 : framesPlayed);
03374 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03375 }
03376
03377 uint64_t MythPlayer::GetBookmark(void)
03378 {
03379 uint64_t bookmark = 0;
03380
03381 if (gCoreContext->IsDatabaseIgnored() ||
03382 (player_ctx->buffer && !player_ctx->buffer->IsBookmarkAllowed()))
03383 bookmark = 0;
03384 else
03385 {
03386 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03387 if (player_ctx->playingInfo)
03388 bookmark = player_ctx->playingInfo->QueryBookmark();
03389 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03390 }
03391
03392 return bookmark;
03393 }
03394
03395 bool MythPlayer::UpdateFFRewSkip(void)
03396 {
03397 bool skip_changed;
03398
03399 float temp_speed = (play_speed == 0.0) ?
03400 audio.GetStretchFactor() : play_speed;
03401 if (play_speed >= 0.0f && play_speed <= 3.0f)
03402 {
03403 skip_changed = (ffrew_skip != 1);
03404 frame_interval = (int) (1000000.0f / video_frame_rate / temp_speed);
03405 ffrew_skip = (play_speed != 0.0f);
03406 }
03407 else
03408 {
03409 skip_changed = true;
03410 frame_interval = 200000;
03411 frame_interval = (fabs(play_speed) >= 3.0) ? 133466 : frame_interval;
03412 frame_interval = (fabs(play_speed) >= 5.0) ? 133466 : frame_interval;
03413 frame_interval = (fabs(play_speed) >= 8.0) ? 250250 : frame_interval;
03414 frame_interval = (fabs(play_speed) >= 10.0) ? 133466 : frame_interval;
03415 frame_interval = (fabs(play_speed) >= 16.0) ? 187687 : frame_interval;
03416 frame_interval = (fabs(play_speed) >= 20.0) ? 150150 : frame_interval;
03417 frame_interval = (fabs(play_speed) >= 30.0) ? 133466 : frame_interval;
03418 frame_interval = (fabs(play_speed) >= 60.0) ? 133466 : frame_interval;
03419 frame_interval = (fabs(play_speed) >= 120.0) ? 133466 : frame_interval;
03420 frame_interval = (fabs(play_speed) >= 180.0) ? 133466 : frame_interval;
03421 float ffw_fps = fabs(play_speed) * video_frame_rate;
03422 float dis_fps = 1000000.0f / frame_interval;
03423 ffrew_skip = (int)ceil(ffw_fps / dis_fps);
03424 ffrew_skip = play_speed < 0.0f ? -ffrew_skip : ffrew_skip;
03425 ffrew_adjust = 0;
03426 }
03427
03428 return skip_changed;
03429 }
03430
03431 void MythPlayer::ChangeSpeed(void)
03432 {
03433 float last_speed = play_speed;
03434 play_speed = next_play_speed;
03435 normal_speed = next_normal_speed;
03436
03437 bool skip_changed = UpdateFFRewSkip();
03438 videosync->setFrameInterval(frame_interval);
03439
03440 if (skip_changed && videoOutput)
03441 {
03442 videoOutput->SetPrebuffering(ffrew_skip == 1);
03443 if (play_speed != 0.0f && !(last_speed == 0.0f && ffrew_skip == 1))
03444 DoJumpToFrame(framesPlayed + fftime - rewindtime, kInaccuracyFull);
03445 }
03446
03447 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Play speed: " +
03448 QString("rate: %1 speed: %2 skip: %3 => new interval %4")
03449 .arg(video_frame_rate).arg(play_speed)
03450 .arg(ffrew_skip).arg(frame_interval));
03451
03452 if (videoOutput && videosync)
03453 {
03454
03455 videoOutput->SetVideoFrameRate(video_frame_rate);
03456
03457
03458
03459 bool play_1 = play_speed > 0.99f && play_speed < 1.01f && normal_speed;
03460 bool inter = (kScan_Interlaced == m_scan ||
03461 kScan_Intr2ndField == m_scan);
03462
03463 videofiltersLock.lock();
03464 if (m_double_framerate && !play_1)
03465 videoOutput->FallbackDeint();
03466 else if (!m_double_framerate && CanSupportDoubleRate() && play_1 &&
03467 inter)
03468 videoOutput->BestDeint();
03469 videofiltersLock.unlock();
03470
03471 m_double_framerate = videoOutput->NeedsDoubleFramerate();
03472 m_double_process = videoOutput->IsExtraProcessingRequired();
03473 }
03474
03475 if (normal_speed && audio.HasAudioOut())
03476 {
03477 audio.SetStretchFactor(play_speed);
03478 syncWithAudioStretch();
03479 }
03480 }
03481
03482 bool MythPlayer::DoRewind(uint64_t frames, double inaccuracy)
03483 {
03484 if (player_ctx->buffer && !player_ctx->buffer->IsSeekingAllowed())
03485 return false;
03486
03487 uint64_t number = frames + 1;
03488 uint64_t desiredFrame = (framesPlayed > number) ? framesPlayed - number : 0;
03489
03490 limitKeyRepeat = false;
03491 if (desiredFrame < video_frame_rate)
03492 limitKeyRepeat = true;
03493
03494 uint64_t seeksnap_wanted = -1;
03495 if (inaccuracy != kInaccuracyFull)
03496 seeksnap_wanted = frames * inaccuracy;
03497 WaitForSeek(desiredFrame, seeksnap_wanted);
03498 rewindtime = 0;
03499 ClearAfterSeek();
03500 return true;
03501 }
03502
03503 long long MythPlayer::CalcRWTime(long long rw) const
03504 {
03505 bool hasliveprev = (livetv && player_ctx->tvchain &&
03506 player_ctx->tvchain->HasPrev());
03507
03508 if (!hasliveprev || ((int64_t)framesPlayed > (rw - 1)))
03509 return rw;
03510
03511 player_ctx->tvchain->JumpToNext(false, (int)(-15.0 * video_frame_rate));
03512 return -1;
03513 }
03514
03515 long long MythPlayer::CalcMaxFFTime(long long ff, bool setjump) const
03516 {
03517 long long maxtime = (long long)(1.0 * video_frame_rate);
03518 bool islivetvcur = (livetv && player_ctx->tvchain &&
03519 !player_ctx->tvchain->HasNext());
03520
03521 if (livetv || IsWatchingInprogress())
03522 maxtime = (long long)(3.0 * video_frame_rate);
03523
03524 long long ret = ff;
03525
03526 limitKeyRepeat = false;
03527
03528 if (livetv && !islivetvcur && player_ctx->tvchain)
03529 {
03530 if (totalFrames > 0)
03531 {
03532 long long behind = totalFrames - framesPlayed;
03533 if (behind < maxtime || behind - ff <= maxtime * 2)
03534 {
03535 ret = -1;
03536 if (setjump)
03537 player_ctx->tvchain->JumpToNext(true, 1);
03538 }
03539 }
03540 }
03541 else if (islivetvcur || IsWatchingInprogress())
03542 {
03543 long long behind = player_ctx->recorder->GetFramesWritten() -
03544 framesPlayed;
03545
03546 if (behind < maxtime)
03547 ret = 0;
03548 else if (behind - ff <= maxtime)
03549 ret = behind - maxtime;
03550
03551 if (behind < maxtime * 3)
03552 limitKeyRepeat = true;
03553 }
03554 else
03555 {
03556 if (totalFrames > 0)
03557 {
03558 long long behind = totalFrames - framesPlayed;
03559 if (behind < maxtime)
03560 ret = 0;
03561 else if (behind - ff <= maxtime * 2)
03562 ret = behind - maxtime * 2;
03563 }
03564 }
03565
03566 return ret;
03567 }
03568
03575 bool MythPlayer::IsReallyNearEnd(void) const
03576 {
03577 if (!videoOutput || !decoder)
03578 return false;
03579
03580 return player_ctx->buffer->IsNearEnd(
03581 decoder->GetFPS(), videoOutput->ValidVideoFrames());
03582 }
03583
03586 bool MythPlayer::IsNearEnd(void)
03587 {
03588 uint64_t framesRead, framesLeft = 0;
03589
03590 if (!player_ctx)
03591 return false;
03592
03593 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03594 if (!player_ctx->playingInfo || player_ctx->playingInfo->IsVideo() ||
03595 !decoder)
03596 {
03597 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03598 return false;
03599 }
03600 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03601
03602 long long margin = (long long)(video_frame_rate * 2);
03603 margin = (long long) (margin * audio.GetStretchFactor());
03604 bool watchingTV = IsWatchingInprogress();
03605
03606 framesRead = decoder->GetFramesRead();
03607
03608 if (!player_ctx->IsPIP() &&
03609 player_ctx->GetState() == kState_WatchingPreRecorded)
03610 {
03611 if (framesRead >= deleteMap.GetLastFrame(totalFrames))
03612 return true;
03613 framesLeft = (totalFrames > framesRead) ? totalFrames - framesRead : 0;
03614 return (framesLeft < (uint64_t)margin);
03615 }
03616
03617 if (!livetv && !watchingTV)
03618 return false;
03619
03620 if (livetv && player_ctx->tvchain && player_ctx->tvchain->HasNext())
03621 return false;
03622
03623 if (player_ctx->recorder)
03624 {
03625 framesLeft =
03626 player_ctx->recorder->GetCachedFramesWritten() - framesRead;
03627
03628
03629 if (framesLeft < (uint64_t)margin)
03630 framesLeft = player_ctx->recorder->GetFramesWritten() - framesRead;
03631 }
03632
03633 return (framesLeft < (uint64_t)margin);
03634 }
03635
03636 bool MythPlayer::DoFastForward(uint64_t frames, double inaccuracy)
03637 {
03638 if (player_ctx->buffer && !player_ctx->buffer->IsSeekingAllowed())
03639 return false;
03640
03641 uint64_t number = (frames ? frames - 1 : 0);
03642 uint64_t desiredFrame = framesPlayed + number;
03643
03644 if (!deleteMap.IsEditing() && IsInDelete(desiredFrame))
03645 {
03646 uint64_t endcheck = deleteMap.GetLastFrame(totalFrames);
03647 if (desiredFrame > endcheck)
03648 desiredFrame = endcheck;
03649 }
03650
03651 uint64_t seeksnap_wanted = -1;
03652 if (inaccuracy != kInaccuracyFull)
03653 seeksnap_wanted = frames * inaccuracy;
03654 WaitForSeek(desiredFrame, seeksnap_wanted);
03655 fftime = 0;
03656 ClearAfterSeek(false);
03657 return true;
03658 }
03659
03660 void MythPlayer::DoJumpToFrame(uint64_t frame, double inaccuracy)
03661 {
03662 if (frame > framesPlayed)
03663 DoFastForward(frame - framesPlayed, inaccuracy);
03664 else if (frame <= framesPlayed)
03665 DoRewind(framesPlayed - frame, inaccuracy);
03666 }
03667
03668 void MythPlayer::WaitForSeek(uint64_t frame, uint64_t seeksnap_wanted)
03669 {
03670 if (!decoder)
03671 return;
03672
03673 decoder->SetSeekSnap(seeksnap_wanted);
03674
03675 bool islivetvcur = (livetv && player_ctx->tvchain &&
03676 !player_ctx->tvchain->HasNext());
03677
03678 uint64_t max = totalFrames;
03679 if (islivetvcur || IsWatchingInprogress())
03680 {
03681 max = (uint64_t)player_ctx->recorder->GetFramesWritten();
03682 }
03683 if (frame >= max)
03684 frame = max - 1;
03685
03686 decoderSeekLock.lock();
03687 decoderSeek = frame;
03688 decoderSeekLock.unlock();
03689
03690 int count = 0;
03691 bool need_clear = false;
03692 while (decoderSeek >= 0)
03693 {
03694 usleep(1000);
03695
03696
03697 count++;
03698 if (!(count % 150) && !hasFullPositionMap)
03699 {
03700 int num = (count / 150) % 4;
03701 SetOSDMessage(QObject::tr("Searching") + QString().fill('.', num),
03702 kOSDTimeout_Short);
03703 DisplayPauseFrame();
03704 need_clear = true;
03705 }
03706 }
03707 if (need_clear)
03708 {
03709 osdLock.lock();
03710 if (osd)
03711 osd->HideWindow("osd_message");
03712 osdLock.unlock();
03713 }
03714 }
03715
03728 void MythPlayer::ClearAfterSeek(bool clearvideobuffers)
03729 {
03730 LOG(VB_PLAYBACK, LOG_INFO, LOC + QString("ClearAfterSeek(%1)")
03731 .arg(clearvideobuffers));
03732
03733 if (clearvideobuffers && videoOutput)
03734 videoOutput->ClearAfterSeek();
03735
03736 int64_t savedAudioTimecodeOffset = tc_wrap[TC_AUDIO];
03737
03738 for (int j = 0; j < TCTYPESMAX; j++)
03739 tc_wrap[j] = tc_lastval[j] = 0;
03740
03741 tc_wrap[TC_AUDIO] = savedAudioTimecodeOffset;
03742
03743 audio.Reset();
03744 ResetCaptions();
03745 deleteMap.TrackerReset(framesPlayed, totalFrames);
03746 commBreakMap.SetTracker(framesPlayed);
03747 commBreakMap.ResetLastSkip();
03748 needNewPauseFrame = true;
03749 ResetAVSync();
03750 }
03751
03752 void MythPlayer::SetPlayerInfo(TV *tv, QWidget *widget, PlayerContext *ctx)
03753 {
03754 deleteMap.SetPlayerContext(ctx);
03755 m_tv = tv;
03756 parentWidget = widget;
03757 player_ctx = ctx;
03758 livetv = ctx->tvchain;
03759 }
03760
03761 bool MythPlayer::EnableEdit(void)
03762 {
03763 deleteMap.SetEditing(false);
03764
03765 if (!hasFullPositionMap)
03766 {
03767 LOG(VB_GENERAL, LOG_ERR, LOC + "Cannot edit - no full position map");
03768 SetOSDStatus(QObject::tr("No Seektable"), kOSDTimeout_Med);
03769 return false;
03770 }
03771
03772 if (deleteMap.IsFileEditing())
03773 return false;
03774
03775 QMutexLocker locker(&osdLock);
03776 if (!osd)
03777 return false;
03778
03779 speedBeforeEdit = play_speed;
03780 pausedBeforeEdit = Pause();
03781 deleteMap.SetEditing(true);
03782 osd->DialogQuit();
03783 ResetCaptions();
03784 osd->HideAll();
03785
03786 bool loadedAutoSave = deleteMap.LoadAutoSaveMap(totalFrames);
03787 if (loadedAutoSave)
03788 {
03789 SetOSDMessage(QObject::tr("Using previously auto-saved cuts"),
03790 kOSDTimeout_Short);
03791 }
03792
03793 deleteMap.UpdateSeekAmount(0, video_frame_rate);
03794 deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate, osd);
03795 deleteMap.SetFileEditing(true);
03796 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03797 if (player_ctx->playingInfo)
03798 player_ctx->playingInfo->SaveEditing(true);
03799 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03800 editUpdateTimer.start();
03801
03802 return deleteMap.IsEditing();
03803 }
03804
03812 void MythPlayer::DisableEdit(int howToSave)
03813 {
03814 QMutexLocker locker(&osdLock);
03815 if (!osd)
03816 return;
03817
03818 deleteMap.SetEditing(false, osd);
03819 if (howToSave == 0)
03820 deleteMap.LoadMap(totalFrames);
03821
03822 if (howToSave >= 0)
03823 deleteMap.SaveMap(totalFrames);
03824 deleteMap.TrackerReset(framesPlayed, totalFrames);
03825 deleteMap.SetFileEditing(false);
03826 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
03827 if (player_ctx->playingInfo)
03828 player_ctx->playingInfo->SaveEditing(false);
03829 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
03830 if (!pausedBeforeEdit)
03831 Play(speedBeforeEdit);
03832 else
03833 SetOSDStatus(QObject::tr("Paused"), kOSDTimeout_None);
03834 }
03835
03836 bool MythPlayer::HandleProgramEditorActions(QStringList &actions,
03837 long long frame)
03838 {
03839 bool handled = false;
03840 bool refresh = true;
03841
03842 for (int i = 0; i < actions.size() && !handled; i++)
03843 {
03844 QString action = actions[i];
03845 handled = true;
03846 int seekamount = deleteMap.GetSeekAmount();
03847 if (action == ACTION_LEFT)
03848 {
03849 if (deleteMap.GetSeekAmount() > 0)
03850 {
03851 DoRewind(seekamount, seekamount > 1 ?
03852 kInaccuracyEditor : kInaccuracyNone);
03853 }
03854 else
03855 HandleArbSeek(false);
03856 }
03857 else if (action == ACTION_RIGHT)
03858 {
03859 if (deleteMap.GetSeekAmount() > 0)
03860 {
03861 DoFastForward(seekamount, seekamount > 1 ?
03862 kInaccuracyEditor : kInaccuracyNone);
03863 }
03864 else
03865 HandleArbSeek(true);
03866 }
03867 else if (action == ACTION_LOADCOMMSKIP)
03868 {
03869 if (commBreakMap.HasMap())
03870 {
03871 frm_dir_map_t map;
03872 commBreakMap.GetMap(map);
03873 deleteMap.LoadCommBreakMap(totalFrames, map);
03874 }
03875 }
03876 else if (action == ACTION_PREVCUT)
03877 {
03878 int old_seekamount = deleteMap.GetSeekAmount();
03879 deleteMap.SetSeekAmount(-2);
03880 HandleArbSeek(false);
03881 deleteMap.SetSeekAmount(old_seekamount);
03882 }
03883 else if (action == ACTION_NEXTCUT)
03884 {
03885 int old_seekamount = deleteMap.GetSeekAmount();
03886 deleteMap.SetSeekAmount(-2);
03887 HandleArbSeek(true);
03888 deleteMap.SetSeekAmount(old_seekamount);
03889 }
03890 #define FFREW_MULTICOUNT 10
03891 else if (action == ACTION_BIGJUMPREW)
03892 {
03893 if (seekamount > 0)
03894 DoRewind(seekamount * FFREW_MULTICOUNT, seekamount > 1 ?
03895 kInaccuracyEditor : kInaccuracyNone);
03896 else
03897 {
03898 int fps = (int)ceil(video_frame_rate);
03899 DoRewind(fps * FFREW_MULTICOUNT / 2, kInaccuracyNone);
03900 }
03901 }
03902 else if (action == ACTION_BIGJUMPFWD)
03903 {
03904 if (seekamount > 0)
03905 DoFastForward(seekamount * FFREW_MULTICOUNT, seekamount > 1 ?
03906 kInaccuracyEditor : kInaccuracyNone);
03907 else
03908 {
03909 int fps = (int)ceil(video_frame_rate);
03910 DoFastForward(fps * FFREW_MULTICOUNT / 2,
03911 kInaccuracyNone);
03912 }
03913 }
03914 else if (action == ACTION_SELECT)
03915 {
03916 deleteMap.NewCut(frame, totalFrames);
03917 SetOSDMessage(QObject::tr("New cut added."), kOSDTimeout_Short);
03918 refresh = true;
03919 }
03920 else if (action == "DELETE")
03921 {
03922 deleteMap.Delete(frame, totalFrames,
03923 QObject::tr("Delete"));
03924 refresh = true;
03925 }
03926 else if (action == "REVERT")
03927 {
03928 deleteMap.LoadMap(totalFrames, QObject::tr("Undo Changes"));
03929 refresh = true;
03930 }
03931 else if (action == "REVERTEXIT")
03932 {
03933 DisableEdit(0);
03934 refresh = false;
03935 }
03936 else if (action == ACTION_SAVEMAP)
03937 {
03938 deleteMap.SaveMap(totalFrames);
03939 refresh = true;
03940 }
03941 else if (action == "EDIT" || action == "SAVEEXIT")
03942 {
03943 DisableEdit(1);
03944 refresh = false;
03945 }
03946 else
03947 {
03948 QString undoMessage = deleteMap.GetUndoMessage();
03949 QString redoMessage = deleteMap.GetRedoMessage();
03950 handled = deleteMap.HandleAction(action, frame, framesPlayed,
03951 totalFrames, video_frame_rate);
03952 if (handled && (action == "CUTTOBEGINNING" ||
03953 action == "CUTTOEND" || action == "NEWCUT"))
03954 {
03955 SetOSDMessage(QObject::tr("New cut added."), kOSDTimeout_Short);
03956 }
03957 else if (handled && action == "UNDO")
03958 {
03959 SetOSDMessage(QObject::tr("Undo") + " - " + undoMessage,
03960 kOSDTimeout_Short);
03961 }
03962 else if (handled && action == "REDO")
03963 {
03964 SetOSDMessage(QObject::tr("Redo") + " - " + redoMessage,
03965 kOSDTimeout_Short);
03966 }
03967 }
03968 }
03969
03970 if (handled && refresh)
03971 {
03972 osdLock.lock();
03973 if (osd)
03974 {
03975 deleteMap.UpdateOSD(framesPlayed, totalFrames, video_frame_rate,
03976 osd);
03977 }
03978 osdLock.unlock();
03979 }
03980
03981 return handled;
03982 }
03983
03984 bool MythPlayer::IsInDelete(uint64_t frame)
03985 {
03986 return deleteMap.IsInDelete(frame);
03987 }
03988
03989 uint64_t MythPlayer::GetNearestMark(uint64_t frame, bool right)
03990 {
03991 return deleteMap.GetNearestMark(frame, totalFrames, right);
03992 }
03993
03994 bool MythPlayer::IsTemporaryMark(uint64_t frame)
03995 {
03996 return deleteMap.IsTemporaryMark(frame);
03997 }
03998
03999 bool MythPlayer::HasTemporaryMark(void)
04000 {
04001 return deleteMap.HasTemporaryMark();
04002 }
04003
04004 void MythPlayer::HandleArbSeek(bool right)
04005 {
04006 if (deleteMap.GetSeekAmount() == -2)
04007 {
04008 long long framenum = deleteMap.GetNearestMark(framesPlayed,
04009 totalFrames, right);
04010 if (right && (framenum > (int64_t)framesPlayed))
04011 DoFastForward(framenum - framesPlayed, kInaccuracyNone);
04012 else if (!right && ((int64_t)framesPlayed > framenum))
04013 DoRewind(framesPlayed - framenum, kInaccuracyNone);
04014 }
04015 else
04016 {
04017 if (right)
04018 {
04019 DoFastForward(2, kInaccuracyFull);
04020 }
04021 else
04022 {
04023 DoRewind(2, kInaccuracyFull);
04024 }
04025 }
04026 }
04027
04028 AspectOverrideMode MythPlayer::GetAspectOverride(void) const
04029 {
04030 if (videoOutput)
04031 return videoOutput->GetAspectOverride();
04032 return kAspect_Off;
04033 }
04034
04035 AdjustFillMode MythPlayer::GetAdjustFill(void) const
04036 {
04037 if (videoOutput)
04038 return videoOutput->GetAdjustFill();
04039 return kAdjustFill_Off;
04040 }
04041
04042 void MythPlayer::ToggleAspectOverride(AspectOverrideMode aspectMode)
04043 {
04044 if (videoOutput)
04045 {
04046 videoOutput->ToggleAspectOverride(aspectMode);
04047 ReinitOSD();
04048 }
04049 }
04050
04051 void MythPlayer::ToggleAdjustFill(AdjustFillMode adjustfillMode)
04052 {
04053 if (videoOutput)
04054 {
04055 detect_letter_box->SetDetectLetterbox(false);
04056 videoOutput->ToggleAdjustFill(adjustfillMode);
04057 ReinitOSD();
04058 }
04059 }
04060
04061 void MythPlayer::Zoom(ZoomDirection direction)
04062 {
04063 if (videoOutput)
04064 {
04065 videoOutput->Zoom(direction);
04066 ReinitOSD();
04067 }
04068 }
04069
04070 void MythPlayer::ExposeEvent(void)
04071 {
04072 if (videoOutput)
04073 videoOutput->ExposeEvent();
04074 }
04075
04076 bool MythPlayer::IsEmbedding(void)
04077 {
04078 if (videoOutput)
04079 return videoOutput->IsEmbedding();
04080 return false;
04081 }
04082
04083 bool MythPlayer::GetScreenShot(int width, int height, QString filename)
04084 {
04085 if (videoOutput)
04086 return videoOutput->GetScreenShot(width, height, filename);
04087 return false;
04088 }
04089
04090 bool MythPlayer::HasTVChainNext(void) const
04091 {
04092 return player_ctx->tvchain && player_ctx->tvchain->HasNext();
04093 }
04094
04110 char *MythPlayer::GetScreenGrab(int secondsin, int &bufflen,
04111 int &vw, int &vh, float &ar)
04112 {
04113 long long frameNum = (long long)(secondsin * video_frame_rate);
04114
04115 return GetScreenGrabAtFrame(frameNum, false, bufflen, vw, vh, ar);
04116 }
04117
04134 char *MythPlayer::GetScreenGrabAtFrame(uint64_t frameNum, bool absolute,
04135 int &bufflen, int &vw, int &vh,
04136 float &ar)
04137 {
04138 uint64_t number = 0;
04139 unsigned char *data = NULL;
04140 unsigned char *outputbuf = NULL;
04141 VideoFrame *frame = NULL;
04142 AVPicture orig;
04143 AVPicture retbuf;
04144 memset(&orig, 0, sizeof(AVPicture));
04145 memset(&retbuf, 0, sizeof(AVPicture));
04146
04147 if (OpenFile(0) < 0)
04148 {
04149 LOG(VB_GENERAL, LOG_ERR, LOC + "Could not open file for preview.");
04150 return NULL;
04151 }
04152
04153 if ((video_dim.width() <= 0) || (video_dim.height() <= 0))
04154 {
04155 LOG(VB_PLAYBACK, LOG_ERR, LOC +
04156 QString("Video Resolution invalid %1x%2")
04157 .arg(video_dim.width()).arg(video_dim.height()));
04158
04159
04160 vw = 640;
04161 vh = 480;
04162 ar = 4.0f / 3.0f;
04163
04164 bufflen = vw * vh * 4;
04165 outputbuf = new unsigned char[bufflen];
04166 memset(outputbuf, 0x3f, bufflen * sizeof(unsigned char));
04167 return (char*) outputbuf;
04168 }
04169
04170 if (!InitVideo())
04171 {
04172 LOG(VB_GENERAL, LOG_ERR, LOC +
04173 "Unable to initialize video for screen grab.");
04174 return NULL;
04175 }
04176
04177 ClearAfterSeek();
04178 if (!decoderThread)
04179 DecoderStart(true );
04180 SeekForScreenGrab(number, frameNum, absolute);
04181 int tries = 0;
04182 while (!videoOutput->ValidVideoFrames() && ((tries++) < 500))
04183 {
04184 decodeOneFrame = true;
04185 usleep(10000);
04186 if ((tries & 10) == 10)
04187 LOG(VB_PLAYBACK, LOG_INFO, LOC +
04188 "ScreenGrab: Waited 100ms for video frame");
04189 }
04190
04191 if (!(frame = videoOutput->GetLastDecodedFrame()))
04192 {
04193 bufflen = 0;
04194 vw = vh = 0;
04195 ar = 0;
04196 return NULL;
04197 }
04198
04199 if (!(data = frame->buf))
04200 {
04201 bufflen = 0;
04202 vw = vh = 0;
04203 ar = 0;
04204 DiscardVideoFrame(frame);
04205 return NULL;
04206 }
04207
04208 avpicture_fill(&orig, data, PIX_FMT_YUV420P,
04209 video_dim.width(), video_dim.height());
04210
04211 avpicture_deinterlace(&orig, &orig, PIX_FMT_YUV420P,
04212 video_dim.width(), video_dim.height());
04213
04214 bufflen = video_dim.width() * video_dim.height() * 4;
04215 outputbuf = new unsigned char[bufflen];
04216
04217 avpicture_fill(&retbuf, outputbuf, PIX_FMT_RGB32,
04218 video_dim.width(), video_dim.height());
04219
04220 myth_sws_img_convert(
04221 &retbuf, PIX_FMT_RGB32, &orig, PIX_FMT_YUV420P,
04222 video_dim.width(), video_dim.height());
04223
04224 vw = video_dim.width();
04225 vh = video_dim.height();
04226 ar = frame->aspect;
04227
04228 DiscardVideoFrame(frame);
04229 return (char *)outputbuf;
04230 }
04231
04232 void MythPlayer::SeekForScreenGrab(uint64_t &number, uint64_t frameNum,
04233 bool absolute)
04234 {
04235 if (!hasFullPositionMap)
04236 {
04237 LOG(VB_GENERAL, LOG_ERR, LOC +
04238 "GetScreenGrabAtFrame: Recording does not "
04239 "have position map so we will be unable to grab the desired "
04240 "frame.");
04241 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
04242 if (player_ctx->playingInfo)
04243 {
04244 LOG(VB_GENERAL, LOG_ERR, LOC +
04245 QString("Run 'mythcommflag --file %1 --rebuild' to fix.")
04246 .arg(player_ctx->playingInfo->GetBasename()));
04247 LOG(VB_GENERAL, LOG_ERR, LOC +
04248 QString("If that does not work and this is a .mpg file, "
04249 "try 'mythtranscode --mpeg2 --buildindex "
04250 "--allkeys -c %1 -s %2'.")
04251 .arg(player_ctx->playingInfo->GetChanID())
04252 .arg(player_ctx->playingInfo->GetRecordingStartTime()
04253 .toString("yyyyMMddhhmmss")));
04254 }
04255 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
04256 }
04257
04258 number = frameNum;
04259 if (number >= totalFrames)
04260 {
04261 LOG(VB_PLAYBACK, LOG_ERR, LOC +
04262 "Screen grab requested for frame number beyond end of file.");
04263 number = totalFrames / 2;
04264 }
04265
04266 if (!absolute && hasFullPositionMap)
04267 {
04268 bookmarkseek = GetBookmark();
04269
04270
04271 if (bookmarkseek > 30)
04272 {
04273 number = bookmarkseek;
04274 }
04275 else
04276 {
04277 uint64_t oldnumber = number;
04278 deleteMap.LoadMap(totalFrames);
04279 commBreakMap.LoadMap(player_ctx, framesPlayed);
04280
04281 bool started_in_break_map = false;
04282 while (commBreakMap.IsInCommBreak(number) ||
04283 IsInDelete(number))
04284 {
04285 started_in_break_map = true;
04286 number += (uint64_t) (30 * video_frame_rate);
04287 if (number >= totalFrames)
04288 {
04289 number = oldnumber;
04290 break;
04291 }
04292 }
04293
04294
04295 if (started_in_break_map)
04296 {
04297 oldnumber = number;
04298 number += (long long) (10 * video_frame_rate);
04299 if (number >= totalFrames)
04300 number = oldnumber;
04301 }
04302 }
04303 }
04304
04305
04306 if (hasFullPositionMap)
04307 {
04308 DiscardVideoFrame(videoOutput->GetLastDecodedFrame());
04309 DoJumpToFrame(number, kInaccuracyNone);
04310 }
04311 }
04312
04320 VideoFrame* MythPlayer::GetRawVideoFrame(long long frameNumber)
04321 {
04322 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
04323 if (player_ctx->playingInfo)
04324 player_ctx->playingInfo->UpdateInUseMark();
04325 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
04326
04327 if (!decoderThread)
04328 DecoderStart(false);
04329
04330 if (frameNumber >= 0)
04331 {
04332 DoJumpToFrame(frameNumber, kInaccuracyNone);
04333 ClearAfterSeek();
04334 }
04335
04336 int tries = 0;
04337 while (!videoOutput->ValidVideoFrames() && ((tries++) < 100))
04338 {
04339 decodeOneFrame = true;
04340 usleep(10000);
04341 if ((tries & 10) == 10)
04342 LOG(VB_PLAYBACK, LOG_INFO, LOC + "Waited 100ms for video frame");
04343 }
04344
04345 videoOutput->StartDisplayingFrame();
04346 return videoOutput->GetLastShownFrame();
04347 }
04348
04349 QString MythPlayer::GetEncodingType(void) const
04350 {
04351 if (decoder)
04352 return get_encoding_type(decoder->GetVideoCodecID());
04353 return QString();
04354 }
04355
04356 void MythPlayer::GetCodecDescription(InfoMap &infoMap)
04357 {
04358 infoMap["audiocodec"] = ff_codec_id_string((CodecID)audio.GetCodec());
04359 infoMap["audiochannels"] = QString::number(audio.GetOrigChannels());
04360
04361 int width = video_disp_dim.width();
04362 int height = video_disp_dim.height();
04363 infoMap["videocodec"] = GetEncodingType();
04364 if (decoder)
04365 infoMap["videocodecdesc"] = decoder->GetRawEncodingType();
04366 infoMap["videowidth"] = QString::number(width);
04367 infoMap["videoheight"] = QString::number(height);
04368 infoMap["videoframerate"] = QString::number(video_frame_rate, 'f', 2);
04369
04370 if (height < 480)
04371 return;
04372
04373 bool interlaced = is_interlaced(m_scan);
04374 if (height == 480 || height == 576)
04375 infoMap["videodescrip"] = "SD";
04376 else if (height == 720 && !interlaced)
04377 infoMap["videodescrip"] = "HD_720_P";
04378 else if (height == 1080 || height == 1088)
04379 infoMap["videodescrip"] = interlaced ? "HD_1080_I" : "HD_1080_P";
04380 }
04381
04382 bool MythPlayer::GetRawAudioState(void) const
04383 {
04384 if (decoder)
04385 return decoder->GetRawAudioState();
04386 return false;
04387 }
04388
04389 QString MythPlayer::GetXDS(const QString &key) const
04390 {
04391 if (!decoder)
04392 return QString::null;
04393 return decoder->GetXDS(key);
04394 }
04395
04396 void MythPlayer::InitForTranscode(bool copyaudio, bool copyvideo)
04397 {
04398
04399 SetPlaying(true);
04400 keyframedist = 30;
04401
04402 if (!InitVideo())
04403 {
04404 LOG(VB_GENERAL, LOG_ERR, LOC +
04405 "Unable to initialize video for transcode.");
04406 SetPlaying(false);
04407 return;
04408 }
04409
04410 framesPlayed = 0;
04411 ClearAfterSeek();
04412
04413 if (copyvideo && decoder)
04414 decoder->SetRawVideoState(true);
04415 if (copyaudio && decoder)
04416 decoder->SetRawAudioState(true);
04417
04418 if (decoder)
04419 {
04420 decoder->SetSeekSnap(0);
04421 decoder->SetLowBuffers(true);
04422 }
04423 }
04424
04425 bool MythPlayer::TranscodeGetNextFrame(
04426 frm_dir_map_t::iterator &dm_iter,
04427 int &did_ff, bool &is_key, bool honorCutList)
04428 {
04429 player_ctx->LockPlayingInfo(__FILE__, __LINE__);
04430 if (player_ctx->playingInfo)
04431 player_ctx->playingInfo->UpdateInUseMark();
04432 player_ctx->UnlockPlayingInfo(__FILE__, __LINE__);
04433
04434 int64_t lastDecodedFrameNumber =
04435 videoOutput->GetLastDecodedFrame()->frameNumber;
04436
04437 if ((lastDecodedFrameNumber == 0) && honorCutList)
04438 deleteMap.TrackerReset(0, 0);
04439
04440 if (!decoderThread)
04441 DecoderStart(true);
04442
04443 if (!decoder)
04444 return false;
04445
04446 if (!decoder->GetFrame(kDecodeAV))
04447 return false;
04448
04449 if (GetEof())
04450 return false;
04451
04452 if (honorCutList && !deleteMap.IsEmpty())
04453 {
04454 if (totalFrames && lastDecodedFrameNumber >= (int64_t)totalFrames)
04455 return false;
04456
04457 uint64_t jumpto = 0;
04458 if (deleteMap.TrackerWantsToJump(lastDecodedFrameNumber, totalFrames,
04459 jumpto))
04460 {
04461 LOG(VB_GENERAL, LOG_INFO, LOC +
04462 QString("Fast-Forwarding from %1 to %2")
04463 .arg(lastDecodedFrameNumber).arg(jumpto));
04464 if (jumpto >= totalFrames)
04465 return false;
04466
04467
04468 WaitForSeek(jumpto, 0);
04469 decoder->ClearStoredData();
04470 ClearAfterSeek();
04471 decoder->GetFrame(kDecodeAV);
04472 did_ff = 1;
04473 }
04474 }
04475 if (GetEof())
04476 return false;
04477 is_key = decoder->IsLastFrameKey();
04478
04479 videofiltersLock.lock();
04480 if (videoFilters)
04481 {
04482 FrameScanType ps = m_scan;
04483 if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
04484 ps = kScan_Progressive;
04485
04486 videoFilters->ProcessFrame(videoOutput->GetLastDecodedFrame(), ps);
04487 }
04488 videofiltersLock.unlock();
04489
04490 return true;
04491 }
04492
04493 long MythPlayer::UpdateStoredFrameNum(long curFrameNum)
04494 {
04495 if (decoder)
04496 return decoder->UpdateStoredFrameNum(curFrameNum);
04497 return 0;
04498 }
04499
04500 void MythPlayer::SetCutList(const frm_dir_map_t &newCutList)
04501 {
04502 deleteMap.SetMap(newCutList);
04503 }
04504
04505 bool MythPlayer::WriteStoredData(RingBuffer *outRingBuffer,
04506 bool writevideo, long timecodeOffset)
04507 {
04508 if (!decoder)
04509 return false;
04510 if (writevideo && !decoder->GetRawVideoState())
04511 writevideo = false;
04512 decoder->WriteStoredData(outRingBuffer, writevideo, timecodeOffset);
04513 return writevideo;
04514 }
04515
04516 void MythPlayer::SetCommBreakMap(frm_dir_map_t &newMap)
04517 {
04518 commBreakMap.SetMap(newMap, framesPlayed);
04519 forcePositionMapSync = true;
04520 }
04521
04522 int MythPlayer::GetStatusbarPos(void) const
04523 {
04524 double spos = 0.0;
04525
04526 if (livetv || IsWatchingInprogress())
04527 {
04528 spos = 1000.0 * framesPlayed / player_ctx->recorder->GetFramesWritten();
04529 }
04530 else if (totalFrames)
04531 {
04532 spos = 1000.0 * framesPlayed / totalFrames;
04533 }
04534
04535 return((int)spos);
04536 }
04537
04538 void MythPlayer::GetPlaybackData(InfoMap &infoMap)
04539 {
04540 QString samplerate = RingBuffer::BitrateToString(audio.GetSampleRate(),
04541 true);
04542 infoMap.insert("samplerate", samplerate);
04543 infoMap.insert("filename", player_ctx->buffer->GetSafeFilename());
04544 infoMap.insert("decoderrate", player_ctx->buffer->GetDecoderRate());
04545 infoMap.insert("storagerate", player_ctx->buffer->GetStorageRate());
04546 infoMap.insert("bufferavail", player_ctx->buffer->GetAvailableBuffer());
04547 infoMap.insert("buffersize",
04548 QString::number(player_ctx->buffer->GetBufferSize() >> 20));
04549 infoMap.insert("avsync",
04550 QString::number((float)avsync_avg / (float)frame_interval, 'f', 2));
04551 if (videoOutput)
04552 {
04553 QString frames = QString("%1/%2").arg(videoOutput->ValidVideoFrames())
04554 .arg(videoOutput->FreeVideoFrames());
04555 infoMap.insert("videoframes", frames);
04556 }
04557 if (decoder)
04558 infoMap["videodecoder"] = decoder->GetCodecDecoderName();
04559 if (output_jmeter)
04560 {
04561 infoMap["framerate"] = QString("%1%2%3")
04562 .arg(output_jmeter->GetLastFPS(), 0, 'f', 2)
04563 .arg(QChar(0xB1, 0))
04564 .arg(output_jmeter->GetLastSD(), 0, 'f', 2);
04565 infoMap["load"] = output_jmeter->GetLastCPUStats();
04566 }
04567 GetCodecDescription(infoMap);
04568 }
04569
04570 int MythPlayer::GetSecondsBehind(void) const
04571 {
04572 if (!player_ctx->recorder)
04573 return 0;
04574
04575 long long written = player_ctx->recorder->GetFramesWritten();
04576 long long played = framesPlayed;
04577
04578 if (played > written)
04579 played = written;
04580 if (played < 0)
04581 played = 0;
04582
04583 return (int)((float)(written - played) / video_frame_rate);
04584 }
04585
04586 int64_t MythPlayer::GetSecondsPlayed(void)
04587 {
04588 return decoder->IsCodecMPEG() ?
04589 (disp_timecode / 1000.f) :
04590 (framesPlayed / video_frame_rate);
04591 }
04592
04593 int64_t MythPlayer::GetTotalSeconds(void) const
04594 {
04595 return totalDuration;
04596 }
04597
04598 void MythPlayer::calcSliderPos(osdInfo &info, bool paddedFields)
04599 {
04600 if (!decoder)
04601 return;
04602
04603 bool islive = false;
04604 info.text.insert("chapteridx", QString());
04605 info.text.insert("totalchapters", QString());
04606 info.text.insert("titleidx", QString());
04607 info.text.insert("totaltitles", QString());
04608 info.text.insert("angleidx", QString());
04609 info.text.insert("totalangles", QString());
04610 info.values.insert("position", 0);
04611 info.values.insert("progbefore", 0);
04612 info.values.insert("progafter", 0);
04613
04614 int playbackLen = GetTotalSeconds();
04615 float secsplayed = (float)GetSecondsPlayed();
04616
04617 if (totalDuration == 0 || decoder->GetCodecDecoderName() == "nuppel")
04618 playbackLen = totalLength;
04619
04620 if (livetv && player_ctx->tvchain)
04621 {
04622 info.values["progbefore"] = (int)player_ctx->tvchain->HasPrev();
04623 info.values["progafter"] = (int)player_ctx->tvchain->HasNext();
04624 playbackLen = player_ctx->tvchain->GetLengthAtCurPos();
04625 islive = true;
04626 }
04627 else if (IsWatchingInprogress())
04628 {
04629 playbackLen =
04630 (int)(((float)player_ctx->recorder->GetFramesWritten() /
04631 video_frame_rate));
04632 islive = true;
04633 }
04634 else
04635 {
04636 int chapter = GetCurrentChapter();
04637 int chapters = GetNumChapters();
04638 if (chapter && chapters > 1)
04639 {
04640 info.text["chapteridx"] = QString::number(chapter + 1);
04641 info.text["totalchapters"] = QString::number(chapters);
04642 }
04643
04644 int title = GetCurrentTitle();
04645 int titles = GetNumTitles();
04646 if (title && titles > 1)
04647 {
04648 info.text["titleidx"] = QString::number(title + 1);
04649 info.text["totaltitles"] = QString::number(titles);
04650 }
04651
04652 int angle = GetCurrentAngle();
04653 int angles = GetNumAngles();
04654 if (angle && angles > 1)
04655 {
04656 info.text["angleidx"] = QString::number(angle + 1);
04657 info.text["totalangles"] = QString::number(angles);
04658 }
04659 }
04660
04661 playbackLen = max(playbackLen, 1);
04662 secsplayed = min((float)playbackLen, max(secsplayed, 0.0f));
04663
04664
04665 for (int i = 0; i < 2 ; ++i)
04666 {
04667 QString relPrefix = (i == 0 ? "" : "rel");
04668 if (i > 0)
04669 {
04670 playbackLen = deleteMap.TranslatePositionAbsToRel(playbackLen * video_frame_rate) /
04671 video_frame_rate;
04672 secsplayed = deleteMap.TranslatePositionAbsToRel(secsplayed * video_frame_rate) /
04673 video_frame_rate;
04674 }
04675
04676 info.values.insert(relPrefix + "secondsplayed", (int)secsplayed);
04677 info.values.insert(relPrefix + "totalseconds", playbackLen);
04678 info.values[relPrefix + "position"] = (int)(1000.0f * (secsplayed / (float)playbackLen));
04679
04680 int phours = (int)secsplayed / 3600;
04681 int pmins = ((int)secsplayed - phours * 3600) / 60;
04682 int psecs = ((int)secsplayed - phours * 3600 - pmins * 60);
04683
04684 int shours = playbackLen / 3600;
04685 int smins = (playbackLen - shours * 3600) / 60;
04686 int ssecs = (playbackLen - shours * 3600 - smins * 60);
04687
04688 int secsbehind = max((playbackLen - (int) secsplayed), 0);
04689 int sbhours = secsbehind / 3600;
04690 int sbmins = (secsbehind - sbhours * 3600) / 60;
04691 int sbsecs = (secsbehind - sbhours * 3600 - sbmins * 60);
04692
04693 QString text1, text2, text3;
04694 if (paddedFields)
04695 {
04696 text1.sprintf("%02d:%02d:%02d", phours, pmins, psecs);
04697 text2.sprintf("%02d:%02d:%02d", shours, smins, ssecs);
04698 text3.sprintf("%02d:%02d:%02d", sbhours, sbmins, sbsecs);
04699 }
04700 else
04701 {
04702 if (shours > 0)
04703 {
04704 text1.sprintf("%d:%02d:%02d", phours, pmins, psecs);
04705 text2.sprintf("%d:%02d:%02d", shours, smins, ssecs);
04706 }
04707 else
04708 {
04709 text1.sprintf("%d:%02d", pmins, psecs);
04710 text2.sprintf("%d:%02d", smins, ssecs);
04711 }
04712
04713 if (sbhours > 0)
04714 {
04715 text3.sprintf("%d:%02d:%02d", sbhours, sbmins, sbsecs);
04716 }
04717 else if (sbmins > 0)
04718 {
04719 text3.sprintf("%d:%02d", sbmins, sbsecs);
04720 }
04721 else
04722 {
04723 text3 = QObject::tr("%n second(s)", "", sbsecs);
04724 }
04725 }
04726
04727 info.text[relPrefix + "description"] = QObject::tr("%1 of %2").arg(text1).arg(text2);
04728 info.text[relPrefix + "playedtime"] = text1;
04729 info.text[relPrefix + "totaltime"] = text2;
04730 info.text[relPrefix + "remainingtime"] = islive ? QString() : text3;
04731 info.text[relPrefix + "behindtime"] = islive ? text3 : QString();
04732 }
04733 }
04734
04735 int MythPlayer::GetNumChapters()
04736 {
04737 if (decoder)
04738 return decoder->GetNumChapters();
04739 return 0;
04740 }
04741
04742 int MythPlayer::GetCurrentChapter()
04743 {
04744 if (decoder)
04745 return decoder->GetCurrentChapter(framesPlayed);
04746 return 0;
04747 }
04748
04749 void MythPlayer::GetChapterTimes(QList<long long> ×)
04750 {
04751 if (decoder)
04752 return decoder->GetChapterTimes(times);
04753 }
04754
04755 bool MythPlayer::DoJumpChapter(int chapter)
04756 {
04757 int64_t desiredFrame = -1;
04758 int total = GetNumChapters();
04759 int current = GetCurrentChapter();
04760
04761 if (chapter < 0 || chapter > total)
04762 {
04763
04764 if (chapter < 0)
04765 {
04766 chapter = current -1;
04767 if (chapter < 0) chapter = 0;
04768 }
04769 else if (chapter > total)
04770 {
04771 chapter = current + 1;
04772 if (chapter > total) chapter = total;
04773 }
04774 }
04775
04776 desiredFrame = GetChapter(chapter);
04777 LOG(VB_PLAYBACK, LOG_INFO, LOC +
04778 QString("DoJumpChapter: current %1 want %2 (frame %3)")
04779 .arg(current).arg(chapter).arg(desiredFrame));
04780
04781 if (desiredFrame < 0)
04782 {
04783 LOG(VB_PLAYBACK, LOG_ERR, LOC + QString("DoJumpChapter failed."));
04784 jumpchapter = 0;
04785 return false;
04786 }
04787
04788 DoJumpToFrame(desiredFrame, kInaccuracyNone);
04789 jumpchapter = 0;
04790 return true;
04791 }
04792
04793 int64_t MythPlayer::GetChapter(int chapter)
04794 {
04795 if (decoder)
04796 return decoder->GetChapter(chapter);
04797 return 0;
04798 }
04799
04800 InteractiveTV *MythPlayer::GetInteractiveTV(void)
04801 {
04802 #ifdef USING_MHEG
04803 if (!interactiveTV && itvEnabled)
04804 {
04805 QMutexLocker locker1(&osdLock);
04806 QMutexLocker locker2(&itvLock);
04807 if (osd)
04808 interactiveTV = new InteractiveTV(this);
04809 }
04810 #endif // USING_MHEG
04811 return interactiveTV;
04812 }
04813
04814 bool MythPlayer::ITVHandleAction(const QString &action)
04815 {
04816 bool result = false;
04817
04818 #ifdef USING_MHEG
04819 if (!GetInteractiveTV())
04820 return result;
04821
04822 QMutexLocker locker(&itvLock);
04823 result = interactiveTV->OfferKey(action);
04824 #endif // USING_MHEG
04825
04826 return result;
04827 }
04828
04832 void MythPlayer::ITVRestart(uint chanid, uint cardid, bool isLiveTV)
04833 {
04834 #ifdef USING_MHEG
04835 if (!GetInteractiveTV())
04836 return;
04837
04838 QMutexLocker locker(&itvLock);
04839 interactiveTV->Restart(chanid, cardid, isLiveTV);
04840 itvVisible = false;
04841 #endif // USING_MHEG
04842 }
04843
04844 void MythPlayer::SetVideoResize(const QRect &videoRect)
04845 {
04846 if (videoOutput)
04847 videoOutput->SetVideoResize(videoRect);
04848 }
04849
04853 bool MythPlayer::SetAudioByComponentTag(int tag)
04854 {
04855 QMutexLocker locker(&decoder_change_lock);
04856 if (decoder)
04857 return decoder->SetAudioByComponentTag(tag);
04858 return false;
04859 }
04860
04864 bool MythPlayer::SetVideoByComponentTag(int tag)
04865 {
04866 QMutexLocker locker(&decoder_change_lock);
04867 if (decoder)
04868 return decoder->SetVideoByComponentTag(tag);
04869 return false;
04870 }
04871
04875 void MythPlayer::SetDecoder(DecoderBase *dec)
04876 {
04877 totalDecoderPause = true;
04878 PauseDecoder();
04879
04880 {
04881 while (!decoder_change_lock.tryLock(10))
04882 LOG(VB_GENERAL, LOG_INFO, LOC + "Waited 10ms for decoder lock");
04883
04884 if (!decoder)
04885 decoder = dec;
04886 else
04887 {
04888 DecoderBase *d = decoder;
04889 decoder = dec;
04890 delete d;
04891 }
04892 decoder_change_lock.unlock();
04893 }
04894 syncWithAudioStretch();
04895 totalDecoderPause = false;
04896 }
04897
04898 bool MythPlayer::PosMapFromEnc(unsigned long long start,
04899 QMap<long long, long long> &posMap)
04900 {
04901
04902 if (!(livetv || (player_ctx->recorder &&
04903 player_ctx->recorder->IsValidRecorder())))
04904 return false;
04905
04906
04907 if (HasTVChainNext())
04908 return false;
04909
04910 LOG(VB_PLAYBACK, LOG_INFO, LOC +
04911 QString("Filling position map from %1 to %2") .arg(start).arg("end"));
04912
04913 player_ctx->recorder->FillPositionMap(start, -1, posMap);
04914
04915 return true;
04916 }
04917
04918 void MythPlayer::SetErrored(const QString &reason) const
04919 {
04920 QMutexLocker locker(&errorLock);
04921
04922 if (videoOutput)
04923 errorType |= videoOutput->GetError();
04924
04925 if (errorMsg.isEmpty())
04926 {
04927 errorMsg = reason;
04928 errorMsg.detach();
04929 }
04930 else
04931 {
04932 LOG(VB_GENERAL, LOG_ERR, LOC + QString("%1").arg(reason));
04933 }
04934 }
04935
04936 bool MythPlayer::IsErrored(void) const
04937 {
04938 QMutexLocker locker(&errorLock);
04939 return !errorMsg.isEmpty();
04940 }
04941
04942 QString MythPlayer::GetError(void) const
04943 {
04944 QMutexLocker locker(&errorLock);
04945 QString tmp = errorMsg;
04946 tmp.detach();
04947 return tmp;
04948 }
04949
04950 void MythPlayer::ToggleStudioLevels(void)
04951 {
04952 if (!videoOutput)
04953 return;
04954
04955 if (!(videoOutput->GetSupportedPictureAttributes() &
04956 kPictureAttributeSupported_StudioLevels))
04957 return;
04958
04959 int val = videoOutput->GetPictureAttribute(kPictureAttribute_StudioLevels);
04960 val = (val > 0) ? 0 : 1;
04961 videoOutput->SetPictureAttribute(kPictureAttribute_StudioLevels, val);
04962 QString msg = (val > 0) ? QObject::tr("Enabled Studio Levels") :
04963 QObject::tr("Disabled Studio Levels");
04964 SetOSDMessage(msg, kOSDTimeout_Med);
04965 }
04966
04967 void MythPlayer::ToggleNightMode(void)
04968 {
04969 if (!videoOutput)
04970 return;
04971
04972 if (!(videoOutput->GetSupportedPictureAttributes() &
04973 kPictureAttributeSupported_Brightness))
04974 return;
04975
04976 int b = videoOutput->GetPictureAttribute(kPictureAttribute_Brightness);
04977 int c = 0;
04978 bool has_contrast = (videoOutput->GetSupportedPictureAttributes() &
04979 kPictureAttributeSupported_Contrast);
04980 if (has_contrast)
04981 c = videoOutput->GetPictureAttribute(kPictureAttribute_Contrast);
04982
04983 int nm = gCoreContext->GetNumSetting("NightModeEnabled", 0);
04984 QString msg;
04985 if (!nm)
04986 {
04987 msg = QObject::tr("Enabled Night Mode");
04988 b -= kNightModeBrightenssAdjustment;
04989 c -= kNightModeContrastAdjustment;
04990 }
04991 else
04992 {
04993 msg = QObject::tr("Disabled Night Mode");
04994 b += kNightModeBrightenssAdjustment;
04995 c += kNightModeContrastAdjustment;
04996 }
04997 b = clamp(b, 0, 100);
04998 c = clamp(c, 0, 100);
04999
05000 gCoreContext->SaveSetting("NightModeEnabled", nm ? "0" : "1");
05001 videoOutput->SetPictureAttribute(kPictureAttribute_Brightness, b);
05002 if (has_contrast)
05003 videoOutput->SetPictureAttribute(kPictureAttribute_Contrast, c);
05004
05005 SetOSDMessage(msg, kOSDTimeout_Med);
05006 }
05007
05008 bool MythPlayer::CanVisualise(void)
05009 {
05010 if (videoOutput)
05011 return videoOutput->CanVisualise(&audio, NULL);
05012 return false;
05013 }
05014
05015 bool MythPlayer::IsVisualising(void)
05016 {
05017 if (videoOutput)
05018 return videoOutput->GetVisualisation();
05019 return false;
05020 }
05021
05022 QString MythPlayer::GetVisualiserName(void)
05023 {
05024 if (videoOutput)
05025 return videoOutput->GetVisualiserName();
05026 return QString("");
05027 }
05028
05029 QStringList MythPlayer::GetVisualiserList(void)
05030 {
05031 if (videoOutput)
05032 return videoOutput->GetVisualiserList();
05033 return QStringList();
05034 }
05035
05036 bool MythPlayer::EnableVisualisation(bool enable, const QString &name)
05037 {
05038 if (videoOutput)
05039 return videoOutput->EnableVisualisation(&audio, enable, name);
05040 return false;
05041 }
05042
05043 void MythPlayer::SetOSDMessage(const QString &msg, OSDTimeout timeout)
05044 {
05045 QMutexLocker locker(&osdLock);
05046 if (!osd)
05047 return;
05048
05049 QHash<QString,QString> info;
05050 info.insert("message_text", msg);
05051 osd->SetText("osd_message", info, timeout);
05052 }
05053
05054 void MythPlayer::SetOSDStatus(const QString &title, OSDTimeout timeout)
05055 {
05056 QMutexLocker locker(&osdLock);
05057 if (!osd)
05058 return;
05059
05060 osdInfo info;
05061 calcSliderPos(info);
05062 info.text.insert("title", title);
05063 osd->SetText("osd_status", info.text, timeout);
05064 osd->SetValues("osd_status", info.values, timeout);
05065 }
05066
05067 void MythPlayer::SaveTotalDuration(void)
05068 {
05069 if (!decoder)
05070 return;
05071
05072 decoder->SaveTotalDuration();
05073 }
05074
05075 void MythPlayer::ResetTotalDuration(void)
05076 {
05077 if (!decoder)
05078 return;
05079
05080 decoder->ResetTotalDuration();
05081 }
05082
05083 void MythPlayer::SaveTotalFrames(void)
05084 {
05085 if (!decoder)
05086 return;
05087
05088 decoder->SaveTotalFrames();
05089 }
05090
05091 void MythPlayer::syncWithAudioStretch()
05092 {
05093 if (decoder && audio.HasAudioOut())
05094 {
05095 float stretch = audio.GetStretchFactor();
05096 bool disable = (stretch < 0.99f) || (stretch > 1.01f);
05097 LOG(VB_PLAYBACK, LOG_INFO, LOC +
05098 QString("Stretch Factor %1, %2 passthru ")
05099 .arg(audio.GetStretchFactor())
05100 .arg((disable) ? "disable" : "allow"));
05101 decoder->SetDisablePassThrough(disable);
05102 }
05103 return;
05104 }
05105
05106 static unsigned dbg_ident(const MythPlayer *player)
05107 {
05108 static QMutex dbg_lock;
05109 static unsigned dbg_next_ident = 0;
05110 typedef QMap<const MythPlayer*, unsigned> DbgMapType;
05111 static DbgMapType dbg_ident;
05112
05113 QMutexLocker locker(&dbg_lock);
05114 DbgMapType::iterator it = dbg_ident.find(player);
05115 if (it != dbg_ident.end())
05116 return *it;
05117 return dbg_ident[player] = dbg_next_ident++;
05118 }
05119
05120
05121