00001
00002
00003
00004 #include <cstdio>
00005 #include <cstdlib>
00006 #include <cassert>
00007 #include <cerrno>
00008 #include <ctime>
00009 #include <cmath>
00010
00011
00012 #include <unistd.h>
00013 #include <fcntl.h>
00014 #include <sched.h>
00015 #include <sys/time.h>
00016
00017
00018 #include <algorithm>
00019 #include <iostream>
00020 using namespace std;
00021
00022
00023 #include <qapplication.h>
00024 #include <qstringlist.h>
00025 #include <qdeepcopy.h>
00026 #include <qmap.h>
00027
00028
00029 #include "config.h"
00030 #include "mythdbcon.h"
00031 #include "dialogbox.h"
00032 #include "NuppelVideoPlayer.h"
00033 #include "audiooutput.h"
00034 #include "recordingprofile.h"
00035 #include "osdtypes.h"
00036 #include "osdsurface.h"
00037 #include "osdtypeteletext.h"
00038 #include "remoteutil.h"
00039 #include "programinfo.h"
00040 #include "mythcontext.h"
00041 #include "fifowriter.h"
00042 #include "filtermanager.h"
00043 #include "util.h"
00044 #include "livetvchain.h"
00045 #include "decoderbase.h"
00046 #include "nuppeldecoder.h"
00047 #include "avformatdecoder.h"
00048 #include "dummydecoder.h"
00049 #include "jobqueue.h"
00050 #include "DVDRingBuffer.h"
00051 #include "NuppelVideoRecorder.h"
00052 #include "tv_play.h"
00053 #include "interactivetv.h"
00054 #include "util-osx-cocoa.h"
00055
00056 extern "C" {
00057 #include "vbitext/vbi.h"
00058 #include "vsync.h"
00059 }
00060
00061 #include "remoteencoder.h"
00062
00063 #include "videoout_null.h"
00064
00065 #ifdef USING_IVTV
00066 #include "videoout_ivtv.h"
00067 #include "ivtvdecoder.h"
00068 #endif
00069
00070 #ifdef USING_DIRECTX
00071 #include "videoout_dx.h"
00072 #undef GetFreeSpace
00073 #undef GetFileSize
00074 #ifdef CONFIG_CYGWIN
00075 #undef DialogBox
00076 #endif
00077 #endif
00078
00079 #ifndef HAVE_ROUND
00080 #define round(x) ((int) ((x) + 0.5))
00081 #endif
00082
00083 #ifdef CONFIG_DARWIN
00084 extern "C" {
00085 int isnan(double);
00086 }
00087 #endif
00088
00089 #define FAST_RESTART 0
00090 #define LOC QString("NVP: ")
00091 #define LOC_ERR QString("NVP, Error: ")
00092
00093 QString track_type_to_string(uint type)
00094 {
00095 QString str = QObject::tr("Track");
00096
00097 if (kTrackTypeAudio == type)
00098 str = QObject::tr("Audio track");
00099 else if (kTrackTypeSubtitle == type)
00100 str = QObject::tr("Subtitle track");
00101 else if (kTrackTypeCC608 == type)
00102 str = QObject::tr("CC", "EIA-608 closed captions");
00103 else if (kTrackTypeCC708 == type)
00104 str = QObject::tr("ATSC CC", "EIA-708 closed captions");
00105 else if (kTrackTypeTeletextCaptions == type)
00106 str = QObject::tr("TT CC", "Teletext closed captions");
00107 else if (kTrackTypeTeletextMenu == type)
00108 str = QObject::tr("TT Menu", "Teletext Menu");
00109 return str;
00110 }
00111
00112 int type_string_to_track_type(const QString &str)
00113 {
00114 int ret = -1;
00115
00116 if (str.left(5) == "AUDIO")
00117 ret = kTrackTypeAudio;
00118 else if (str.left(8) == "SUBTITLE")
00119 ret = kTrackTypeSubtitle;
00120 else if (str.left(5) == "CC608")
00121 ret = kTrackTypeCC608;
00122 else if (str.left(5) == "CC708")
00123 ret = kTrackTypeCC708;
00124 else if (str.left(3) == "TTC")
00125 ret = kTrackTypeTeletextCaptions;
00126 else if (str.left(3) == "TTM")
00127 ret = kTrackTypeTeletextMenu;
00128 return ret;
00129 }
00130
00131 uint track_type_to_display_mode[kTrackTypeCount+2] =
00132 {
00133 kDisplayNone,
00134 kDisplayAVSubtitle,
00135 kDisplayCC608,
00136 kDisplayCC708,
00137 kDisplayTeletextCaptions,
00138 kDisplayNone,
00139 kDisplayNUVTeletextCaptions,
00140 };
00141
00142 NuppelVideoPlayer::NuppelVideoPlayer(QString inUseID, const ProgramInfo *info)
00143 : decoder(NULL), decoder_change_lock(true),
00144 videoOutput(NULL), nvr_enc(NULL),
00145 m_playbackinfo(NULL),
00146
00147 parentWidget(NULL), embedid(0), embx(-1), emby(-1), embw(-1), embh(-1),
00148 embed_saved_scan_type((FrameScanType)-2),
00149 embed_saved_scan_lock(false),
00150
00151 eof(false),
00152 m_double_framerate(false), m_double_process(false),
00153 m_can_double(false), m_deint_possible(true),
00154 paused(false),
00155 pausevideo(false), actuallypaused(false),
00156 video_actually_paused(false), playing(false),
00157 decoder_thread_alive(true), killplayer(false),
00158 killvideo(false), livetv(false),
00159 watchingrecording(false), editmode(false),
00160 resetvideo(false), using_null_videoout(false),
00161 no_audio_in(false), no_audio_out(false),
00162 transcoding(false),
00163 hasFullPositionMap(false), limitKeyRepeat(false),
00164 errored(false),
00165
00166 bookmarkseek(0), previewFromBookmark(false),
00167
00168 fftime(0), seekamountpos(4),
00169 seekamount(30), exactseeks(false),
00170
00171 videobuf_retries(0), framesPlayed(0),
00172 totalFrames(0), totalLength(0),
00173 rewindtime(0), m_recusage(inUseID),
00174
00175 video_disp_dim(0,0), video_dim(0,0),
00176 video_frame_rate(29.97f), video_aspect(4.0f / 3.0f),
00177 forced_video_aspect(-1),
00178 m_scan(kScan_Interlaced), m_scan_locked(false),
00179 m_scan_tracker(0),
00180 keyframedist(30),
00181
00182 filename("output.nuv"), weMadeBuffer(false), ringBuffer(NULL),
00183
00184 prebuffering(false), prebuffer_tries(0),
00185
00186
00187 db_prefer708(true),
00188 textDisplayMode(kDisplayNone),
00189 prevTextDisplayMode(kDisplayNone),
00190
00191 vbimode(VBIMode::None),
00192 ttPageNum(0x888), ccmode(CC_CC1),
00193 wtxt(0), rtxt(0), text_size(0), ccline(""), cccol(0), ccrow(0),
00194
00195 textDesired(false),
00196 osdHasSubtitles(false), osdSubtitlesExpireAt(-1),
00197
00198
00199 itvVisible(false),
00200 interactiveTV(NULL),
00201 itvEnabled(false),
00202
00203
00204 osd(NULL), timedisplay(NULL),
00205 dialogname(""), dialogtype(0),
00206
00207 audioOutput(NULL),
00208 audio_main_device(QString::null),
00209 audio_passthru_device(QString::null),
00210 audio_channels(2), audio_bits(-1),
00211 audio_samplerate(44100), audio_stretchfactor(1.0f),
00212 audio_codec(NULL),
00213
00214 pipplayer(NULL), setpipplayer(NULL), needsetpipplayer(false),
00215
00216 argb_buf(NULL), argb_size(0,0),
00217 yuv2argb_conv(yuv2rgb_init_mmx(32, MODE_RGB)),
00218 yuv_need_copy(false), yuv_desired_size(0,0),
00219 yuv_scaler(NULL), yuv_frame_scaled(NULL),
00220 yuv_scaler_in_size(0,0), yuv_scaler_out_size(0,0),
00221
00222 videoFiltersForProgram(""), videoFiltersOverride(""),
00223 postfilt_width(0), postfilt_height(0),
00224 videoFilters(NULL), FiltMan(new FilterManager()),
00225
00226 skipcommercials(0), autocommercialskip(0),
00227 commrewindamount(0),
00228 commnotifyamount(0), lastCommSkipDirection(0),
00229 lastCommSkipTime(0), lastCommSkipStart(0),
00230 lastSkipTime(0 ),
00231 deleteframe(0),
00232 hasdeletetable(false), hasblanktable(false),
00233 hascommbreaktable(false),
00234 deleteIter(deleteMap.end()), blankIter(blankMap.end()),
00235 commBreakIter(commBreakMap.end()),
00236 forcePositionMapSync(false),
00237
00238 decoder_lock(true),
00239 next_play_speed(1.0f), next_normal_speed(true),
00240 play_speed(1.0f), normal_speed(true),
00241 frame_interval((int)(1000000.0f / 30)), ffrew_skip(1),
00242
00243 videosync(NULL), delay(0),
00244 vsynctol(30/4), avsync_delay(0),
00245 avsync_adjustment(0), avsync_avg(0),
00246 avsync_oldavg(0), refreshrate(0),
00247 lastsync(false), m_playing_slower(false),
00248 m_stored_audio_stretchfactor(1.0),
00249 audio_paused(false),
00250
00251 usevideotimebase(false),
00252 warpfactor(1.0f), warpfactor_avg(1.0f),
00253 warplbuff(NULL), warprbuff(NULL),
00254 warpbuffsize(0),
00255
00256 prevtc(0),
00257 tc_avcheck_framecounter(0), tc_diff_estimate(0),
00258 savedAudioTimecodeOffset(0),
00259
00260 livetvchain(NULL), m_tv(NULL),
00261 isDummy(false),
00262
00263 hidedvdbutton(true), need_change_dvd_track(0),
00264 dvd_stillframe_showing(false),
00265
00266 output_jmeter(NULL)
00267 {
00268 vbimode = VBIMode::Parse(gContext->GetSetting("VbiFormat"));
00269
00270 if (info)
00271 SetPlaybackInfo(new ProgramInfo(*info));
00272
00273 commrewindamount = gContext->GetNumSetting("CommRewindAmount",0);
00274 commnotifyamount = gContext->GetNumSetting("CommNotifyAmount",0);
00275 decode_extra_audio=gContext->GetNumSetting("DecodeExtraAudio", 0);
00276 itvEnabled = gContext->GetNumSetting("EnableMHEG", 0);
00277 db_prefer708 = gContext->GetNumSetting("Prefer708Captions", 1);
00278
00279 lastIgnoredManualSkip = QDateTime::currentDateTime().addSecs(-10);
00280
00281 bzero(&txtbuffers, sizeof(txtbuffers));
00282 bzero(&tc_lastval, sizeof(tc_lastval));
00283 bzero(&tc_wrap, sizeof(tc_wrap));
00284
00285
00286 QString mypage = gContext->GetSetting("VBIpageNr", "888");
00287 bool valid = false;
00288 uint tmp = mypage.toInt(&valid, 16);
00289 ttPageNum = (valid) ? tmp : ttPageNum;
00290
00291 text_size = 8 * (sizeof(teletextsubtitle) + VT_WIDTH);
00292 for (int i = 0; i < MAXTBUFFER; i++)
00293 txtbuffers[i].buffer = new unsigned char[text_size + 1];
00294 }
00295
00296 NuppelVideoPlayer::~NuppelVideoPlayer(void)
00297 {
00298 if (audioOutput)
00299 {
00300 delete audioOutput;
00301 audioOutput = NULL;
00302 }
00303
00304 SetPlaybackInfo(NULL);
00305
00306 if (weMadeBuffer && ringBuffer)
00307 {
00308 delete ringBuffer;
00309 ringBuffer = NULL;
00310 }
00311
00312 if (osdHasSubtitles || !nonDisplayedAVSubtitles.empty())
00313 ClearSubtitles();
00314
00315 if (osd)
00316 {
00317 delete osd;
00318 osd = NULL;
00319 }
00320
00321 for (int i = 0; i < MAXTBUFFER; i++)
00322 {
00323 if (txtbuffers[i].buffer)
00324 {
00325 delete [] txtbuffers[i].buffer;
00326 txtbuffers[i].buffer = NULL;
00327 }
00328 }
00329
00330 SetDecoder(NULL);
00331
00332 if (interactiveTV)
00333 {
00334 delete interactiveTV;
00335 interactiveTV = NULL;
00336 }
00337
00338 if (FiltMan)
00339 {
00340 delete FiltMan;
00341 FiltMan = NULL;
00342 }
00343
00344 if (videoFilters)
00345 {
00346 delete videoFilters;
00347 videoFilters = NULL;
00348 }
00349
00350 if (videosync)
00351 {
00352 delete videosync;
00353 videosync = NULL;
00354 }
00355
00356 if (videoOutput)
00357 {
00358 delete videoOutput;
00359 videoOutput = NULL;
00360 }
00361
00362 if (argb_buf)
00363 {
00364 delete [] argb_buf;
00365 argb_buf = NULL;
00366 }
00367
00368 if (output_jmeter)
00369 {
00370 delete output_jmeter;
00371 output_jmeter = NULL;
00372 }
00373
00374 ShutdownYUVResize();
00375 }
00376
00377 void NuppelVideoPlayer::SetWatchingRecording(bool mode)
00378 {
00379 QMutexLocker locker(&decoder_change_lock);
00380
00381 watchingrecording = mode;
00382 if (GetDecoder())
00383 GetDecoder()->setWatchingRecording(mode);
00384 }
00385
00386 void NuppelVideoPlayer::SetRecorder(RemoteEncoder *recorder)
00387 {
00388 nvr_enc = recorder;
00389 if (GetDecoder())
00390 GetDecoder()->setRecorder(recorder);
00391 }
00392
00393 void NuppelVideoPlayer::SetAudioInfo(const QString &main_device,
00394 const QString &passthru_device,
00395 uint samplerate)
00396 {
00397 audio_main_device = audio_passthru_device = QString::null;
00398
00399 if (!main_device.isEmpty())
00400 audio_main_device = QDeepCopy<QString>(main_device);
00401
00402 if (!passthru_device.isEmpty())
00403 audio_passthru_device = QDeepCopy<QString>(passthru_device);
00404
00405 audio_samplerate = (int)samplerate;
00406 }
00407
00408 void NuppelVideoPlayer::PauseDecoder(void)
00409 {
00410 decoder_lock.lock();
00411 next_play_speed = 0.0;
00412 next_normal_speed = false;
00413 decoder_lock.unlock();
00414
00415 if (!actuallypaused)
00416 {
00417 while (!decoderThreadPaused.wait(4000))
00418 {
00419 if (eof)
00420 return;
00421 VERBOSE(VB_IMPORTANT, "Waited too long for decoder to pause");
00422 }
00423 }
00424 }
00425
00426 void NuppelVideoPlayer::Pause(bool waitvideo)
00427 {
00428 PauseDecoder();
00429
00430
00431 internalPauseLock.lock();
00432 PauseVideo(waitvideo);
00433 internalPauseLock.unlock();
00434
00435 if (audioOutput)
00436 {
00437 audio_paused = true;
00438 audioOutput->Pause(true);
00439 }
00440 if (ringBuffer)
00441 ringBuffer->Pause();
00442
00443 QMutexLocker locker(&decoder_change_lock);
00444
00445 if (GetDecoder() && videoOutput)
00446 {
00447
00448 if (using_null_videoout || IsIVTVDecoder())
00449 GetDecoder()->UpdateFramesPlayed();
00450 else
00451 framesPlayed = videoOutput->GetFramesPlayed();
00452 }
00453 }
00454
00455 bool NuppelVideoPlayer::Play(float speed, bool normal, bool unpauseaudio)
00456 {
00457 VERBOSE(VB_PLAYBACK, LOC +
00458 QString("Play(%1, normal %2, unpause audio %3)")
00459 .arg(speed,5,'f',1).arg(normal).arg(unpauseaudio));
00460
00461 internalPauseLock.lock();
00462 if (editmode)
00463 {
00464 internalPauseLock.unlock();
00465 VERBOSE(VB_IMPORTANT, LOC + "Ignoring Play(), in edit mode.");
00466 return false;
00467 }
00468 UnpauseVideo();
00469 internalPauseLock.unlock();
00470
00471 if (audioOutput && unpauseaudio)
00472 audio_paused = false;
00473 if (ringBuffer)
00474 ringBuffer->Unpause();
00475
00476 decoder_lock.lock();
00477 next_play_speed = speed;
00478 next_normal_speed = normal;
00479 decoder_lock.unlock();
00480 return true;
00481 }
00482
00483 bool NuppelVideoPlayer::IsPaused(bool *is_pause_still_possible) const
00484 {
00485 bool rbf_playing = (ringBuffer != NULL) && !ringBuffer->isPaused();
00486 bool aud_playing = (audioOutput != NULL) && !audioOutput->GetPause();
00487 if (is_pause_still_possible)
00488 {
00489 bool decoder_pausing = (0.0f == next_play_speed) && !next_normal_speed;
00490 bool video_pausing = pausevideo;
00491 bool rbuf_paused = !rbf_playing;
00492 *is_pause_still_possible =
00493 decoder_pausing && video_pausing && rbuf_paused;
00494 }
00495
00496 return (actuallypaused && !rbf_playing && !aud_playing &&
00497 IsVideoActuallyPaused());
00498 }
00499
00500 void NuppelVideoPlayer::PauseVideo(bool wait)
00501 {
00502 QMutexLocker locker(&pauseUnpauseLock);
00503 video_actually_paused = false;
00504 pausevideo = true;
00505
00506 for (uint i = 0; wait && !video_actually_paused; i++)
00507 {
00508 videoThreadPaused.wait(&pauseUnpauseLock, 250);
00509
00510 if (video_actually_paused || eof)
00511 break;
00512
00513 if ((i % 10) == 9)
00514 VERBOSE(VB_IMPORTANT, "Waited too long for video out to pause");
00515 }
00516 }
00517
00518 void NuppelVideoPlayer::UnpauseVideo(bool wait)
00519 {
00520 QMutexLocker locker(&pauseUnpauseLock);
00521 pausevideo = false;
00522
00523 for (uint i = 0; wait && video_actually_paused; i++)
00524 {
00525 videoThreadUnpaused.wait(&pauseUnpauseLock, 250);
00526
00527 if (!video_actually_paused || eof)
00528 break;
00529
00530 if ((i % 10) == 9)
00531 VERBOSE(VB_IMPORTANT, "Waited too long for video out to unpause");
00532 }
00533 }
00534
00535 void NuppelVideoPlayer::SetVideoActuallyPaused(bool val)
00536 {
00537 QMutexLocker locker(&pauseUnpauseLock);
00538 video_actually_paused = val;
00539
00540 if (val)
00541 videoThreadPaused.wakeAll();
00542 else
00543 videoThreadUnpaused.wakeAll();
00544 }
00545
00546 bool NuppelVideoPlayer::IsVideoActuallyPaused(void) const
00547 {
00548 QMutexLocker locker(&pauseUnpauseLock);
00549 return video_actually_paused;
00550 }
00551
00552 void NuppelVideoPlayer::SetPlaybackInfo(ProgramInfo *pginfo)
00553 {
00554 if (m_playbackinfo)
00555 {
00556 m_playbackinfo->MarkAsInUse(false);
00557 delete m_playbackinfo;
00558 videoFiltersForProgram = QString::null;
00559 }
00560
00561 m_playbackinfo = pginfo;
00562
00563 if (m_playbackinfo)
00564 {
00565 m_playbackinfo->MarkAsInUse(true, m_recusage);
00566 videoFiltersForProgram =
00567 QDeepCopy<QString>(m_playbackinfo->chanOutputFilters);
00568 }
00569 }
00570
00571 void NuppelVideoPlayer::SetPrebuffering(bool prebuffer)
00572 {
00573 prebuffering_lock.lock();
00574
00575 if (prebuffer != prebuffering)
00576 {
00577 prebuffering = prebuffer;
00578 if (audioOutput && !paused)
00579 {
00580 if (prebuffering)
00581 audioOutput->Pause(prebuffering);
00582 audio_paused = prebuffering;
00583 }
00584 }
00585
00586 if (!prebuffering)
00587 prebuffering_wait.wakeAll();
00588
00589 prebuffering_lock.unlock();
00590 }
00591
00592 bool NuppelVideoPlayer::InitVideo(void)
00593 {
00594 if (using_null_videoout)
00595 {
00596 videoOutput = new VideoOutputNull();
00597 if (!videoOutput->Init(video_disp_dim.width(), video_disp_dim.height(),
00598 video_aspect, 0, 0, 0, 0, 0, 0))
00599 {
00600 errored = true;
00601 return false;
00602 }
00603 }
00604 else
00605 {
00606 QWidget *widget = parentWidget;
00607
00608 if (!widget)
00609 {
00610 MythMainWindow *window = gContext->GetMainWindow();
00611 assert(window);
00612
00613 QObject *playbackwin = window->child("video playback window");
00614
00615 QWidget *widget = (QWidget *)playbackwin;
00616
00617 if (!widget)
00618 {
00619 VERBOSE(VB_IMPORTANT, "Couldn't find 'tv playback' widget");
00620 widget = window->currentWidget();
00621 assert(widget);
00622 }
00623 }
00624
00625 if (!widget)
00626 {
00627 errored = true;
00628 return false;
00629 }
00630
00631 const QRect display_rect(0, 0, widget->width(), widget->height());
00632
00633 videoOutput = VideoOutput::Create(
00634 GetDecoder()->GetCodecDecoderName(),
00635 GetDecoder()->GetVideoCodecID(),
00636 GetDecoder()->GetVideoCodecPrivate(),
00637 video_disp_dim, video_aspect,
00638 widget->winId(), display_rect, 0 );
00639
00640 if (!videoOutput)
00641 {
00642 errored = true;
00643 return false;
00644 }
00645
00646 bool db_scale = true;
00647 if (ringBuffer->isDVD())
00648 db_scale = false;
00649
00650 videoOutput->SetVideoScalingAllowed(db_scale);
00651
00652
00653 videoOutput->SetVideoFrameRate(video_frame_rate * play_speed);
00654
00655 if (videoOutput->hasMCAcceleration() && !decode_extra_audio)
00656 {
00657 VERBOSE(VB_IMPORTANT, LOC +
00658 "Forcing decode extra audio option on. "
00659 "\n\t\t\tXvMC playback requires it.");
00660 decode_extra_audio = true;
00661 if (GetDecoder())
00662 GetDecoder()->SetLowBuffers(decode_extra_audio);
00663 }
00664 }
00665
00666 if (embedid > 0)
00667 {
00668 videoOutput->EmbedInWidget(embedid, embx, emby, embw, embh);
00669 }
00670
00671 SetCaptionsEnabled(gContext->GetNumSetting("DefaultCCMode"), false);
00672
00673 InitFilters();
00674
00675 return true;
00676 }
00677
00678 void NuppelVideoPlayer::ReinitOSD(void)
00679 {
00680 if (videoOutput && !using_null_videoout)
00681 {
00682 QRect visible, total;
00683 float aspect, scaling;
00684 if (osd)
00685 {
00686 videoOutput->GetOSDBounds(total, visible, aspect, scaling, osd->GetThemeAspect());
00687 osd->Reinit(total, frame_interval, visible, aspect, scaling);
00688 }
00689
00690 if (GetInteractiveTV())
00691 {
00692 GetInteractiveTV()->Reinit(total);
00693 itvVisible = false;
00694 }
00695 }
00696 }
00697
00698 void NuppelVideoPlayer::ReinitVideo(void)
00699 {
00700 vidExitLock.lock();
00701 videofiltersLock.lock();
00702
00703 float aspect = (forced_video_aspect > 0) ? forced_video_aspect : video_aspect;
00704
00705 videoOutput->InputChanged(video_disp_dim, aspect,
00706 GetDecoder()->GetVideoCodecID(),
00707 GetDecoder()->GetVideoCodecPrivate());
00708
00709
00710 videoOutput->SetVideoFrameRate(video_frame_rate * play_speed);
00711
00712 if (videoOutput->IsErrored())
00713 {
00714 VERBOSE(VB_IMPORTANT, "ReinitVideo(): videoOutput->IsErrored()");
00715 if (!using_null_videoout)
00716 {
00717 qApp->lock();
00718 DialogBox *dlg = new DialogBox(
00719 gContext->GetMainWindow(),
00720 QObject::tr("Failed to Reinit Video."));
00721
00722 dlg->AddButton(QObject::tr("Return to menu."));
00723 dlg->exec();
00724 dlg->deleteLater();
00725 qApp->unlock();
00726 }
00727 errored = true;
00728 }
00729 else
00730 {
00731 ReinitOSD();
00732 }
00733
00734 videofiltersLock.unlock();
00735 vidExitLock.unlock();
00736
00737 ClearAfterSeek();
00738
00739 if (textDisplayMode)
00740 {
00741 DisableCaptions(textDisplayMode, false);
00742 SetCaptionsEnabled(true, false);
00743 }
00744
00745 InitFilters();
00746
00747 if (ringBuffer->InDVDMenuOrStillFrame())
00748 ringBuffer->DVD()->SetRunSeekCellStart(true);
00749 }
00750
00751 QString NuppelVideoPlayer::ReinitAudio(void)
00752 {
00753 QString errMsg = QString::null;
00754
00755 if ((audio_bits <= 0) || (audio_channels <= 0) || (audio_samplerate <= 0))
00756 {
00757 VERBOSE(VB_IMPORTANT, LOC +
00758 QString("Disabling Audio, params(%1,%2,%3)")
00759 .arg(audio_bits).arg(audio_channels).arg(audio_samplerate));
00760
00761 no_audio_in = no_audio_out = true;
00762 if (audioOutput)
00763 {
00764 delete audioOutput;
00765 audioOutput = NULL;
00766 }
00767 return errMsg;
00768 }
00769
00770 no_audio_in = false;
00771
00772 if (!audioOutput && !using_null_videoout)
00773 {
00774 bool setVolume = gContext->GetNumSetting("MythControlsVolume", 1);
00775 audioOutput = AudioOutput::OpenAudio(audio_main_device,
00776 audio_passthru_device,
00777 audio_bits, audio_channels,
00778 audio_samplerate,
00779 AUDIOOUTPUT_VIDEO,
00780 setVolume, audio_passthru);
00781 if (!audioOutput)
00782 errMsg = QObject::tr("Unable to create AudioOutput.");
00783 else
00784 errMsg = audioOutput->GetError();
00785
00786 if (!errMsg.isEmpty())
00787 {
00788 VERBOSE(VB_IMPORTANT, LOC + "Disabling Audio" +
00789 QString(", reason is: %1").arg(errMsg));
00790 if (audioOutput)
00791 {
00792 delete audioOutput;
00793 audioOutput = NULL;
00794 }
00795 no_audio_out = true;
00796 }
00797 else if (no_audio_out)
00798 {
00799 VERBOSE(VB_IMPORTANT, LOC + "Enabling Audio");
00800 no_audio_out = false;
00801 }
00802 }
00803
00804 if (audioOutput)
00805 {
00806 audioOutput->Reconfigure(audio_bits, audio_channels,
00807 audio_samplerate, audio_passthru,
00808 audio_codec);
00809 errMsg = audioOutput->GetError();
00810 if (!errMsg.isEmpty())
00811 audioOutput->SetStretchFactor(audio_stretchfactor);
00812 }
00813
00814 return errMsg;
00815 }
00816
00817 static inline QString toQString(FrameScanType scan) {
00818 switch (scan) {
00819 case kScan_Ignore: return QString("Ignore Scan");
00820 case kScan_Detect: return QString("Detect Scan");
00821 case kScan_Interlaced: return QString("Interlaced Scan");
00822 case kScan_Progressive: return QString("Progressive Scan");
00823 default: return QString("Unknown Scan");
00824 }
00825 }
00826
00827 FrameScanType NuppelVideoPlayer::detectInterlace(FrameScanType newScan,
00828 FrameScanType scan,
00829 float fps, int video_height)
00830 {
00831 QString dbg = QString("detectInterlace(") + toQString(newScan) +
00832 QString(", ") + toQString(scan) + QString(", ") + QString("%1").arg(fps) +
00833 QString(", ") + QString("%1").arg(video_height) + QString(") ->");
00834
00835 if (kScan_Ignore != newScan || kScan_Detect == scan)
00836 {
00837
00838
00839
00840 scan = kScan_Interlaced;
00841 if (720 == video_height)
00842 scan = kScan_Progressive;
00843 else if (fps > 45)
00844 scan = kScan_Progressive;
00845
00846 if (kScan_Detect != newScan)
00847 scan = newScan;
00848 };
00849
00850 VERBOSE(VB_PLAYBACK, dbg+toQString(scan));
00851
00852 return scan;
00853 }
00854
00855 void NuppelVideoPlayer::SetKeyframeDistance(int keyframedistance)
00856 {
00857 keyframedist = (keyframedistance > 0) ? keyframedistance : keyframedist;
00858 }
00859
00863 void NuppelVideoPlayer::FallbackDeint(void)
00864 {
00865 m_double_framerate = false;
00866 m_double_process = false;
00867
00868 if (videosync)
00869 videosync->SetFrameInterval(frame_interval, false);
00870
00871 if (osd && !IsIVTVDecoder())
00872 osd->SetFrameInterval(frame_interval);
00873
00874 if (videoOutput)
00875 videoOutput->FallbackDeint();
00876 }
00877
00878 void NuppelVideoPlayer::AutoDeint(VideoFrame *frame)
00879 {
00880 if (!frame || m_scan_locked)
00881 return;
00882
00883 if (frame->interlaced_frame)
00884 {
00885 if (m_scan_tracker < 0)
00886 {
00887 VERBOSE(VB_PLAYBACK, LOC + "interlaced frame seen after "
00888 << abs(m_scan_tracker) << " progressive frames");
00889 m_scan_tracker = 2;
00890 }
00891 m_scan_tracker++;
00892 }
00893 else
00894 {
00895 if (m_scan_tracker > 0)
00896 {
00897 VERBOSE(VB_PLAYBACK, LOC + "progressive frame seen after "
00898 << m_scan_tracker << " interlaced frames");
00899 m_scan_tracker = 0;
00900 }
00901 m_scan_tracker--;
00902 }
00903
00904 if ((m_scan_tracker % 400) == 0)
00905 {
00906 QString type = (m_scan_tracker < 0) ? "progressive" : "interlaced";
00907 VERBOSE(VB_PLAYBACK, LOC + QString("%1 %2 frames seen.")
00908 .arg(abs(m_scan_tracker)).arg(type));
00909 }
00910
00911 int min_count = (ringBuffer->isDVD()) ? 0 : 2;
00912 if (abs(m_scan_tracker) <= min_count)
00913 return;
00914
00915 SetScanType((m_scan_tracker > min_count) ? kScan_Interlaced : kScan_Progressive);
00916 m_scan_locked = false;
00917 }
00918
00919 void NuppelVideoPlayer::SetScanType(FrameScanType scan)
00920 {
00921 QMutexLocker locker(&videofiltersLock);
00922
00923 if (!videoOutput || !videosync)
00924 return;
00925
00926 m_scan_locked = (scan != kScan_Detect);
00927
00928 if (scan == m_scan)
00929 return;
00930
00931 bool interlaced = is_interlaced(scan);
00932 if (interlaced && !m_deint_possible)
00933 {
00934 m_scan = scan;
00935 return;
00936 }
00937
00938 m_double_process = videoOutput->IsExtraProcessingRequired();
00939
00940 if (interlaced || m_double_process)
00941 {
00942 m_deint_possible = videoOutput->SetDeinterlacingEnabled(true);
00943 if (!m_deint_possible)
00944 {
00945 VERBOSE(VB_IMPORTANT, "Failed to enable deinterlacing");
00946 m_scan = scan;
00947 return;
00948 }
00949 if (videoOutput->NeedsDoubleFramerate())
00950 {
00951 m_double_framerate = true;
00952 videosync->SetFrameInterval(frame_interval, true);
00953
00954 m_can_double = videosync->UsesFieldInterval();
00955 if (!m_can_double)
00956 {
00957 VERBOSE(VB_IMPORTANT, "Video sync method can't support double "
00958 "framerate (refresh rate too low for bob deint)");
00959 FallbackDeint();
00960 }
00961 }
00962 VERBOSE(VB_PLAYBACK, "Enabled deinterlacing");
00963 }
00964 else
00965 {
00966 if (kScan_Progressive == scan)
00967 {
00968 if (m_double_framerate)
00969 {
00970 m_double_framerate = false;
00971 videosync->SetFrameInterval(frame_interval, false);
00972 }
00973 videoOutput->SetDeinterlacingEnabled(false);
00974 VERBOSE(VB_PLAYBACK, "Disabled deinterlacing");
00975 }
00976 }
00977
00978
00979 if (osd && !IsIVTVDecoder())
00980 {
00981 osd->SetFrameInterval(
00982 (m_double_framerate && m_double_process) ?
00983 (frame_interval>>1) : frame_interval);
00984 }
00985
00986 m_scan = scan;
00987 }
00988
00989 void NuppelVideoPlayer::SetVideoParams(int width, int height, double fps,
00990 int keyframedistance, float aspect,
00991 FrameScanType scan, bool video_codec_changed)
00992 {
00993 if (width == 0 || height == 0 || isnan(aspect) || isnan(fps))
00994 return;
00995
00996 if ((video_disp_dim == QSize(width, height)) &&
00997 (video_aspect == aspect) && (video_frame_rate == fps ) &&
00998 ((keyframedistance <= 0) || (keyframedistance == keyframedist)) &&
00999 !video_codec_changed)
01000 {
01001 return;
01002 }
01003
01004 if ((width > 0) && (height > 0))
01005 {
01006 video_dim = QSize((width + 15) & ~0xf, (height + 15) & ~0xf);
01007 video_disp_dim = QSize(width, height);
01008 }
01009 video_aspect = (aspect > 0.0f) ? aspect : video_aspect;
01010 keyframedist = (keyframedistance > 0) ? keyframedistance : keyframedist;
01011
01012 if (fps > 0.0f && fps < 121.0f)
01013 {
01014 video_frame_rate = fps;
01015 float temp_speed = (play_speed == 0.0f) ?
01016 audio_stretchfactor : play_speed;
01017 frame_interval = (int)(1000000.0f / video_frame_rate / temp_speed);
01018 }
01019
01020 if (videoOutput)
01021 ReinitVideo();
01022
01023 if (IsErrored())
01024 return;
01025
01026 SetScanType(detectInterlace(scan, m_scan, video_frame_rate,
01027 video_disp_dim.height()));
01028 m_scan_locked = false;
01029 m_scan_tracker = (m_scan == kScan_Interlaced) ? 2 : 0;
01030 }
01031
01032 void NuppelVideoPlayer::SetFileLength(int total, int frames)
01033 {
01034 totalLength = total;
01035 totalFrames = frames;
01036 }
01037
01038 void NuppelVideoPlayer::OpenDummy(void)
01039 {
01040 isDummy = true;
01041
01042 if (!videoOutput)
01043 {
01044 SetVideoParams(720, 576, 25.00, 15);
01045 }
01046
01047 SetDecoder(new DummyDecoder(this, m_playbackinfo));
01048 }
01049
01050 int NuppelVideoPlayer::OpenFile(bool skipDsp, uint retries,
01051 bool allow_libmpeg2)
01052 {
01053 isDummy = false;
01054
01055 if (livetvchain)
01056 {
01057 if (livetvchain->GetCardType(livetvchain->GetCurPos()) == "DUMMY")
01058 {
01059 OpenDummy();
01060 return 0;
01061 }
01062 }
01063
01064 if (!skipDsp)
01065 {
01066 if (!ringBuffer)
01067 {
01068 QString msg("");
01069
01070 if (m_playbackinfo)
01071 {
01072 msg = QString("\n\t\t\tm_playbackinfo filename is %1")
01073 .arg(m_playbackinfo->GetRecordBasename());
01074 }
01075
01076 VERBOSE(VB_IMPORTANT, LOC + "OpenFile() Warning, "
01077 "old player exited before new ring buffer created. " +
01078 QString("\n\t\t\tRingBuffer will use filename '%1'.")
01079 .arg(filename) + msg);
01080
01081 ringBuffer = new RingBuffer(filename, false, true, retries);
01082 weMadeBuffer = true;
01083 livetv = false;
01084 }
01085 else
01086 livetv = ringBuffer->LiveMode();
01087
01088 if (!ringBuffer->IsOpen())
01089 {
01090 VERBOSE(VB_IMPORTANT,
01091 QString("NVP::OpenFile(): Error, file not found: %1")
01092 .arg(ringBuffer->GetFilename().ascii()));
01093 return -1;
01094 }
01095 }
01096
01097 if (!ringBuffer)
01098 return -1;
01099
01100 ringBuffer->Start();
01101 char testbuf[kDecoderProbeBufferSize];
01102 ringBuffer->Unpause();
01103
01104 int readsize = 2048;
01105 if (ringBuffer->Peek(testbuf, readsize) != readsize)
01106 {
01107 VERBOSE(VB_IMPORTANT,
01108 QString("NVP::OpenFile(): Error, couldn't read file: %1")
01109 .arg(ringBuffer->GetFilename()));
01110 return -1;
01111 }
01112
01113
01114 SetDecoder(NULL);
01115
01116 if (NuppelDecoder::CanHandle(testbuf, readsize))
01117 SetDecoder(new NuppelDecoder(this, m_playbackinfo));
01118 #ifdef USING_IVTV
01119 else if (!using_null_videoout && IvtvDecoder::CanHandle(
01120 testbuf, ringBuffer->GetFilename(), readsize))
01121 {
01122 SetDecoder(new IvtvDecoder(this, m_playbackinfo));
01123 no_audio_out = true;
01124 audio_bits = 16;
01125 audio_samplerate = 44100;
01126 audio_channels = 2;
01127 }
01128 else if (IsIVTVDecoder())
01129 {
01130 VERBOSE(VB_IMPORTANT,
01131 QString("NVP: Couldn't open '%1' with ivtv decoder")
01132 .arg(ringBuffer->GetFilename()));
01133 return -1;
01134 }
01135 #endif
01136 else if (AvFormatDecoder::CanHandle(testbuf, ringBuffer->GetFilename(),
01137 readsize))
01138 SetDecoder(new AvFormatDecoder(this, m_playbackinfo,
01139 using_null_videoout, allow_libmpeg2));
01140
01141 if (!GetDecoder())
01142 {
01143 VERBOSE(VB_IMPORTANT,
01144 QString("NVP: Couldn't find a matching decoder for: %1").
01145 arg(ringBuffer->GetFilename()));
01146 return -1;
01147 }
01148 else if (GetDecoder()->IsErrored())
01149 {
01150 VERBOSE(VB_IMPORTANT,
01151 "NVP: NuppelDecoder encountered error during creation.");
01152 SetDecoder(NULL);
01153 return -1;
01154 }
01155
01156 GetDecoder()->setExactSeeks(exactseeks);
01157 GetDecoder()->setLiveTVMode(livetv);
01158 GetDecoder()->setRecorder(nvr_enc);
01159 GetDecoder()->setWatchingRecording(watchingrecording);
01160 GetDecoder()->setTranscoding(transcoding);
01161 GetDecoder()->SetLowBuffers(decode_extra_audio && !using_null_videoout);
01162
01163 eof = false;
01164
01165
01166 bool no_video_decode = false;
01167
01168
01169
01170 int ret = GetDecoder()->OpenFile(ringBuffer, no_video_decode, testbuf,
01171 readsize);
01172
01173 if (ret < 0)
01174 {
01175 VERBOSE(VB_IMPORTANT, QString("Couldn't open decoder for: %1")
01176 .arg(ringBuffer->GetFilename()));
01177 return -1;
01178 }
01179
01180 if (audio_bits == -1)
01181 no_audio_in = no_audio_out = true;
01182
01183 if (ret > 0)
01184 {
01185 hasFullPositionMap = true;
01186
01187 LoadCutList();
01188
01189 if (!deleteMap.isEmpty())
01190 {
01191 hasdeletetable = true;
01192 deleteIter = deleteMap.begin();
01193 }
01194 }
01195
01196
01197 if (ringBuffer->isDVD())
01198 ringBuffer->DVD()->JumpToTitle(true);
01199
01200 bookmarkseek = GetBookmark();
01201
01202 return IsErrored() ? -1 : 0;
01203 }
01204
01205 void NuppelVideoPlayer::InitFilters(void)
01206 {
01207 QString filters = "";
01208 if (videoOutput)
01209 filters = videoOutput->GetFilters();
01210
01211 #if 0
01212 VERBOSE(VB_PLAYBACK, LOC +
01213 QString("InitFilters() vo '%1' prog '%2' over '%3'")
01214 .arg(filters).arg(videoFiltersForProgram)
01215 .arg(videoFiltersOverride));
01216 #endif
01217
01218 if (!videoFiltersForProgram.isEmpty())
01219 {
01220 if (videoFiltersForProgram[0] != '+')
01221 {
01222 filters = QDeepCopy<QString>(videoFiltersForProgram);
01223 }
01224 else
01225 {
01226 if ((filters.length() > 1) && (filters.right(1) != ","))
01227 filters += ",";
01228 filters += QDeepCopy<QString>(videoFiltersForProgram.mid(1));
01229 }
01230 }
01231
01232 if (!videoFiltersOverride.isEmpty())
01233 filters = QDeepCopy<QString>(videoFiltersOverride);
01234
01235 videofiltersLock.lock();
01236
01237 if (videoFilters)
01238 {
01239 delete videoFilters;
01240 videoFilters = NULL;
01241 }
01242
01243 if (!filters.isEmpty())
01244 {
01245 VideoFrameType itmp = FMT_YV12;
01246 VideoFrameType otmp = FMT_YV12;
01247 int btmp;
01248 postfilt_width = video_dim.width();
01249 postfilt_height = video_dim.height();
01250
01251 videoFilters = FiltMan->LoadFilters(
01252 filters, itmp, otmp, postfilt_width, postfilt_height, btmp);
01253 }
01254
01255 videofiltersLock.unlock();
01256
01257 VERBOSE(VB_PLAYBACK, LOC + QString("LoadFilters('%1'..) -> ")
01258 .arg(filters)<<videoFilters);
01259 }
01260
01261 int NuppelVideoPlayer::tbuffer_numvalid(void)
01262 {
01263
01264 int ret;
01265 text_buflock.lock();
01266
01267 if (wtxt >= rtxt)
01268 ret = wtxt - rtxt;
01269 else
01270 ret = MAXTBUFFER - (rtxt - wtxt);
01271
01272 text_buflock.unlock();
01273 return ret;
01274 }
01275
01276 int NuppelVideoPlayer::tbuffer_numfree(void)
01277 {
01278 return MAXTBUFFER - tbuffer_numvalid() - 1;
01279
01280
01281
01282 }
01283
01297 VideoFrame *NuppelVideoPlayer::GetNextVideoFrame(bool allow_unsafe)
01298 {
01299 return videoOutput->GetNextFreeFrame(false, allow_unsafe);
01300 }
01301
01305 void NuppelVideoPlayer::ReleaseNextVideoFrame(VideoFrame *buffer,
01306 long long timecode)
01307 {
01308 if (!ringBuffer->InDVDMenuOrStillFrame())
01309 WrapTimecode(timecode, TC_VIDEO);
01310 buffer->timecode = timecode;
01311
01312 videoOutput->ReleaseFrame(buffer);
01313 }
01314
01318 void NuppelVideoPlayer::DiscardVideoFrame(VideoFrame *buffer)
01319 {
01320 if (videoOutput)
01321 videoOutput->DiscardFrame(buffer);
01322 }
01323
01335 void NuppelVideoPlayer::DiscardVideoFrames(bool next_frame_keyframe)
01336 {
01337 if (videoOutput)
01338 videoOutput->DiscardFrames(next_frame_keyframe);
01339 }
01340
01341 void NuppelVideoPlayer::DrawSlice(VideoFrame *frame, int x, int y, int w, int h)
01342 {
01343 videoOutput->DrawSlice(frame, x, y, w, h);
01344 }
01345
01346 void NuppelVideoPlayer::AddTextData(unsigned char *buffer, int len,
01347 long long timecode, char type)
01348 {
01349 WrapTimecode(timecode, TC_CC);
01350
01351 if (!(textDisplayMode & kDisplayNUVCaptions))
01352 return;
01353
01354 if (!tbuffer_numfree())
01355 {
01356 VERBOSE(VB_IMPORTANT, "NVP::AddTextData(): Text buffer overflow");
01357 return;
01358 }
01359
01360 if (len > text_size)
01361 len = text_size;
01362
01363 txtbuffers[wtxt].timecode = timecode;
01364 txtbuffers[wtxt].type = type;
01365 txtbuffers[wtxt].len = len;
01366 memset(txtbuffers[wtxt].buffer, 0, text_size);
01367 memcpy(txtbuffers[wtxt].buffer, buffer, len);
01368
01369 text_buflock.lock();
01370 wtxt = (wtxt+1) % MAXTBUFFER;
01371 text_buflock.unlock();
01372 }
01373
01374 void NuppelVideoPlayer::CheckPrebuffering(void)
01375 {
01376 if (IsIVTVDecoder())
01377 return;
01378
01379 if ((videoOutput->hasMCAcceleration() ||
01380 videoOutput->hasIDCTAcceleration() ||
01381 videoOutput->hasVLDAcceleration()) &&
01382 (videoOutput->EnoughPrebufferedFrames()))
01383 {
01384 SetPrebuffering(false);
01385 }
01386
01387 #if FAST_RESTART
01388 if (videoOutput->EnoughPrebufferedFrames())
01389 SetPrebuffering(false);
01390 #else
01391 if (videoOutput->EnoughDecodedFrames())
01392 SetPrebuffering(false);
01393 #endif
01394 }
01395
01396 bool NuppelVideoPlayer::GetFrameNormal(int onlyvideo)
01397 {
01398 if (!GetDecoder()->GetFrame(onlyvideo))
01399 return false;
01400
01401 CheckPrebuffering();
01402
01403 if ((play_speed > 1.01f) && (audio_stretchfactor > 1.01f) &&
01404 livetv && IsNearEnd())
01405 {
01406 VERBOSE(VB_PLAYBACK, LOC + "Near end, Slowing down playback.");
01407 Play(1.0f, true, true);
01408 }
01409
01410 return true;
01411 }
01412
01413 bool NuppelVideoPlayer::GetFrameFFREW(void)
01414 {
01415 bool stopFFREW = false;
01416
01417 if (ringBuffer->isDVD() && GetDecoder())
01418 GetDecoder()->UpdateDVDFramesPlayed();
01419
01420 if (ffrew_skip > 0)
01421 {
01422 long long delta = GetDecoder()->GetFramesRead() - framesPlayed;
01423 long long real_skip = CalcMaxFFTime(ffrew_skip + delta) - delta;
01424 if (real_skip >= 0)
01425 {
01426 long long frame = GetDecoder()->GetFramesRead() + real_skip;
01427 GetDecoder()->DoFastForward(frame, false);
01428 }
01429 stopFFREW = (CalcMaxFFTime(100, false) < 100);
01430 }
01431 else if (CalcRWTime(-ffrew_skip) >= 0)
01432 {
01433 long long curFrame = GetDecoder()->GetFramesRead();
01434 bool toBegin = -curFrame > ffrew_skip;
01435 long long real_skip = (toBegin) ? -curFrame : ffrew_skip;
01436 GetDecoder()->DoRewind(curFrame + real_skip, false);
01437 if (ringBuffer->isDVD())
01438 stopFFREW = (ringBuffer->DVD()->GetCurrentTime() < 2);
01439 else
01440 stopFFREW = framesPlayed <= keyframedist;
01441 }
01442
01443 if (stopFFREW)
01444 {
01445 float stretch = (ffrew_skip > 0) ? 1.0f : audio_stretchfactor;
01446 Play(stretch, true, true);
01447 }
01448
01449 bool ret = GetDecoder()->GetFrame(1);
01450 CheckPrebuffering();
01451 return ret;
01452 }
01453
01454 bool NuppelVideoPlayer::GetFrame(int onlyvideo, bool unsafe)
01455 {
01456 bool ret = false;
01457
01458
01459 if ((!IsIVTVDecoder()) &&
01460 !videoOutput->EnoughFreeFrames() &&
01461 !unsafe)
01462 {
01463
01464 SetPrebuffering(false);
01465 if (!videoOutput->WaitForAvailable(10) &&
01466 !videoOutput->EnoughFreeFrames())
01467 {
01468 if (++videobuf_retries >= 200)
01469 {
01470 VERBOSE(VB_IMPORTANT, LOC +
01471 "Timed out waiting for free video buffers.");
01472 videobuf_retries = 0;
01473 }
01474 return false;
01475 }
01476 videobuf_retries = 0;
01477 }
01478
01479
01480 if (!GetDecoder())
01481 VERBOSE(VB_IMPORTANT, LOC + "GetFrame() called with NULL decoder.");
01482 else if (ffrew_skip == 1)
01483 ret = GetFrameNormal(onlyvideo);
01484 else
01485 ret = GetFrameFFREW();
01486
01487 return ret;
01488 }
01489
01490 VideoFrame *NuppelVideoPlayer::GetCurrentFrame(int &w, int &h)
01491 {
01492 w = video_dim.width();
01493 h = video_dim.height();
01494
01495 VideoFrame *retval = NULL;
01496
01497 vidExitLock.lock();
01498 if (videoOutput)
01499 retval = videoOutput->GetLastShownFrame();
01500
01501 if (!retval)
01502 vidExitLock.unlock();
01503
01504 return retval;
01505 }
01506
01507 void NuppelVideoPlayer::ReleaseCurrentFrame(VideoFrame *frame)
01508 {
01509 if (frame)
01510 vidExitLock.unlock();
01511 }
01512
01513 void NuppelVideoPlayer::ShutdownYUVResize(void)
01514 {
01515 if (yuv_frame_scaled)
01516 {
01517 delete [] yuv_frame_scaled;
01518 yuv_frame_scaled = NULL;
01519 }
01520
01521 if (yuv_scaler)
01522 {
01523 img_resample_close(yuv_scaler);
01524 yuv_scaler = NULL;
01525 }
01526
01527 yuv_scaler_in_size = QSize(0,0);
01528 yuv_scaler_out_size = QSize(0,0);
01529 }
01530
01542 const unsigned char *NuppelVideoPlayer::GetScaledFrame(QSize &size)
01543 {
01544 QMutexLocker locker(&yuv_lock);
01545 yuv_desired_size = size = QSize(size.width() & ~0x7, size.height() & ~0x7);
01546
01547 if ((size.width() > 0) && (size.height() > 0))
01548 {
01549 yuv_need_copy = true;
01550 while (yuv_wait.wait(locker.mutex(), 50) && yuv_need_copy);
01551 return yuv_frame_scaled;
01552 }
01553 return NULL;
01554 }
01555
01567 const QImage &NuppelVideoPlayer::GetARGBFrame(QSize &size)
01568 {
01569 unsigned char *yuv_buf = (unsigned char*) GetScaledFrame(size);
01570 if (!yuv_buf)
01571 return argb_scaled_img;
01572
01573 if (argb_size != size)
01574 {
01575 if (argb_buf)
01576 delete [] argb_buf;
01577 argb_buf = new unsigned char[(size.width() * size.height() * 4) + 128];
01578 argb_size = QSize(size.width(), size.height());
01579 }
01580
01581 uint w = argb_size.width(), h = argb_size.height();
01582 yuv2argb_conv(argb_buf,
01583 yuv_buf, yuv_buf + (w * h), yuv_buf + (w * h * 5 / 4),
01584 w, h, w * 4, w, w / 2, 0);
01585
01586 argb_scaled_img = QImage(argb_buf, argb_size.width(), argb_size.height(),
01587 32, NULL, 65536 * 65536, QImage::LittleEndian);
01588
01589 return argb_scaled_img;
01590 }
01591
01592 void NuppelVideoPlayer::EmbedInWidget(WId wid, int x, int y, int w, int h)
01593 {
01594 if (videoOutput)
01595 {
01596
01597
01598 if ((int)embed_saved_scan_type <= kScan_Ignore)
01599 {
01600 embed_saved_scan_type = m_scan;
01601 embed_saved_scan_lock = m_scan_locked;
01602 SetScanType(kScan_Progressive);
01603 }
01604
01605
01606 videoOutput->EmbedInWidget(wid, x, y, w, h);
01607 }
01608 else
01609 {
01610 embedid = wid;
01611 embx = x;
01612 emby = y;
01613 embw = w;
01614 embh = h;
01615 }
01616 }
01617
01618 void NuppelVideoPlayer::StopEmbedding(void)
01619 {
01620 if (videoOutput)
01621 {
01622 videoOutput->StopEmbedding();
01623
01624
01625
01626 if ((int)embed_saved_scan_type >= kScan_Ignore)
01627 {
01628 SetScanType(embed_saved_scan_type);
01629 m_scan_locked = embed_saved_scan_lock;
01630 embed_saved_scan_type = (FrameScanType) -2;
01631 }
01632
01633
01634 ReinitOSD();
01635 }
01636 }
01637
01638 void NuppelVideoPlayer::DrawUnusedRects(bool sync)
01639 {
01640 if (videoOutput)
01641 videoOutput->DrawUnusedRects(sync);
01642 }
01643
01644 void NuppelVideoPlayer::ResetCaptions(uint mode_override)
01645 {
01646 uint origMode = textDisplayMode;
01647 uint mode = (mode_override) ? mode_override : origMode;
01648 textDisplayMode = kDisplayNone;
01649
01650
01651 if (mode & kDisplayNUVCaptions)
01652 ResetCC();
01653
01654
01655 uint i = (mode & kDisplayCC708) ? 1 : 64;
01656 for (; i < 64; i++)
01657 DeleteWindows(i, 0xff);
01658
01659 textDisplayMode = origMode;
01660 }
01661
01662
01663 void NuppelVideoPlayer::DisableCaptions(uint mode, bool osd_msg)
01664 {
01665 textDisplayMode &= ~mode;
01666
01667 ResetCaptions(mode);
01668
01669 if (!osd || !osd_msg)
01670 return;
01671
01672 QString msg = "";
01673 if (kDisplayNUVTeletextCaptions & mode)
01674 msg += QObject::tr("TXT CAP");
01675 if (kDisplayTeletextCaptions & mode)
01676 {
01677 msg += decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
01678 GetTrack(kTrackTypeTeletextCaptions));
01679
01680 DisableTeletext();
01681 }
01682 if (kDisplayAVSubtitle & mode)
01683 {
01684 msg += decoder->GetTrackDesc(kTrackTypeSubtitle,
01685 GetTrack(kTrackTypeSubtitle));
01686 if (ringBuffer->isDVD())
01687 ringBuffer->DVD()->SetTrack(kTrackTypeSubtitle, -1);
01688 }
01689 if (kDisplayTextSubtitle & mode)
01690 {
01691 msg += QObject::tr("Text subtitles");
01692 }
01693 if (kDisplayCC608 & mode)
01694 {
01695 msg += decoder->GetTrackDesc(kTrackTypeCC608,
01696 GetTrack(kTrackTypeCC608));
01697 }
01698 if (kDisplayCC708 & mode)
01699 {
01700 msg += decoder->GetTrackDesc(kTrackTypeCC708,
01701 GetTrack(kTrackTypeCC708));
01702 }
01703
01704 if (! msg.isEmpty())
01705 {
01706 msg += " " + QObject::tr("Off");
01707 osd->SetSettingsText(msg, 3 );
01708 }
01709 }
01710
01711
01712 void NuppelVideoPlayer::EnableCaptions(uint mode, bool osd_msg)
01713 {
01714 QString msg = "";
01715 if (kDisplayAVSubtitle & mode)
01716 {
01717 msg += decoder->GetTrackDesc(kTrackTypeSubtitle,
01718 GetTrack(kTrackTypeSubtitle));
01719
01720 if (ringBuffer->isDVD() && osd_msg)
01721 ringBuffer->DVD()->SetTrack(kTrackTypeSubtitle,
01722 GetTrack(kTrackTypeSubtitle));
01723 }
01724 if (kDisplayTextSubtitle & mode)
01725 {
01726 msg += QObject::tr("Text Subtitles");
01727 }
01728 if (kDisplayNUVTeletextCaptions & mode)
01729 msg += QObject::tr("TXT") + QString(" %1").arg(ttPageNum, 3, 16);
01730 if (kDisplayCC608 & mode)
01731 {
01732 msg += decoder->GetTrackDesc(kTrackTypeCC608,
01733 GetTrack(kTrackTypeCC608));
01734 }
01735 if (kDisplayCC708 & mode)
01736 {
01737 msg += decoder->GetTrackDesc(kTrackTypeCC708,
01738 GetTrack(kTrackTypeCC708));
01739 }
01740 if (kDisplayTeletextCaptions & mode)
01741 {
01742 msg += decoder->GetTrackDesc(kTrackTypeTeletextCaptions,
01743 GetTrack(kTrackTypeTeletextCaptions));
01744
01745 int page = decoder->GetTrackLanguageIndex(
01746 kTrackTypeTeletextCaptions,
01747 GetTrack(kTrackTypeTeletextCaptions));
01748
01749 TeletextViewer *tt_view = NULL;
01750 if (osd && (tt_view = osd->GetTeletextViewer()) && (page > 0))
01751 {
01752 EnableTeletext();
01753 tt_view->SetPage(page, -1);
01754 textDisplayMode = kDisplayTeletextCaptions;
01755 }
01756 }
01757
01758 msg += " " + QObject::tr("On");
01759
01760 textDisplayMode = mode;
01761 if (osd && osd_msg)
01762 osd->SetSettingsText(msg, 3 );
01763
01764 }
01765
01766 void NuppelVideoPlayer::EnableTeletext(void)
01767 {
01768 if (!GetOSD())
01769 return;
01770
01771 OSDSet *oset = GetOSD()->GetSet("teletext");
01772 TeletextViewer *tt_view = GetOSD()->GetTeletextViewer();
01773 if (oset && tt_view)
01774 {
01775 decoder->SetTeletextDecoderViewer(tt_view);
01776 tt_view->SetDisplaying(true);
01777 tt_view->SetPage(0x100, -1);
01778 oset->Display();
01779 osd->SetVisible(oset, 0);
01780 prevTextDisplayMode = textDisplayMode;
01781 textDisplayMode = kDisplayTeletextMenu;
01782 }
01783 }
01784
01785 void NuppelVideoPlayer::DisableTeletext(void)
01786 {
01787 if (!GetOSD())
01788 return;
01789
01790 TeletextViewer *tt_view = GetOSD()->GetTeletextViewer();
01791 if (tt_view)
01792 tt_view->SetDisplaying(false);
01793 GetOSD()->HideSet("teletext");
01794
01795 textDisplayMode = kDisplayNone;
01796
01797
01798
01799 if (prevTextDisplayMode & kDisplayAllCaptions)
01800 EnableCaptions(prevTextDisplayMode, false);
01801 }
01802
01803 void NuppelVideoPlayer::ResetTeletext(void)
01804 {
01805 if (!GetOSD())
01806 return;
01807
01808 TeletextViewer *tt_view = GetOSD()->GetTeletextViewer();
01809 if (tt_view)
01810 tt_view->Reset();
01811 }
01812
01813 bool NuppelVideoPlayer::ToggleCaptions(void)
01814 {
01815 SetCaptionsEnabled(!((bool)textDisplayMode));
01816 return textDisplayMode;
01817 }
01818
01819 bool NuppelVideoPlayer::ToggleCaptions(uint type)
01820 {
01821 uint mode = track_type_to_display_mode[type];
01822 uint origMode = textDisplayMode;
01823
01824 QMutexLocker locker(&decoder_change_lock);
01825
01826 if (textDisplayMode)
01827 DisableCaptions(textDisplayMode, origMode & mode);
01828
01829 if (origMode & mode)
01830 return textDisplayMode;
01831
01832 if (kDisplayNUVTeletextCaptions & mode)
01833 EnableCaptions(kDisplayNUVTeletextCaptions);
01834
01835 if (kDisplayCC608 & mode)
01836 EnableCaptions(kDisplayCC608);
01837
01838 if (kDisplayCC708 & mode)
01839 EnableCaptions(kDisplayCC708);
01840
01841 if (kDisplayAVSubtitle & mode)
01842 EnableCaptions(kDisplayAVSubtitle);
01843
01844 if (kDisplayTextSubtitle & mode)
01845 EnableCaptions(kDisplayTextSubtitle);
01846
01847 if (kDisplayTeletextCaptions & mode)
01848 EnableCaptions(kDisplayTeletextCaptions);
01849
01850 return textDisplayMode;
01851 }
01852
01853 void NuppelVideoPlayer::SetCaptionsEnabled(bool enable, bool osd_msg)
01854 {
01855 uint origMode = textDisplayMode;
01856
01857 textDesired = enable;
01858
01859 QMutexLocker locker(&decoder_change_lock);
01860
01861 if (!enable)
01862 {
01863 DisableCaptions(origMode, osd_msg);
01864 return;
01865 }
01866
01867
01868 bool captions_found = true;
01869 if (decoder->GetTrackCount(kTrackTypeSubtitle))
01870 EnableCaptions(kDisplayAVSubtitle, osd_msg);
01871 else if (textSubtitles.GetSubtitleCount() > 0)
01872 EnableCaptions(kDisplayTextSubtitle, osd_msg);
01873 else if (db_prefer708 && decoder->GetTrackCount(kTrackTypeCC708))
01874 EnableCaptions(kDisplayCC708, osd_msg);
01875 else if (decoder->GetTrackCount(kTrackTypeTeletextCaptions))
01876 EnableCaptions(kDisplayTeletextCaptions, osd_msg);
01877 else if (vbimode == VBIMode::PAL_TT)
01878 EnableCaptions(kDisplayNUVTeletextCaptions, osd_msg);
01879 else if (vbimode == VBIMode::NTSC_CC)
01880 {
01881 if (decoder->GetTrackCount(kTrackTypeCC608))
01882 EnableCaptions(kDisplayCC608, osd_msg);
01883 else
01884 captions_found = false;
01885 }
01886 else if (!db_prefer708 && decoder->GetTrackCount(kTrackTypeCC708))
01887 EnableCaptions(kDisplayCC708, osd_msg);
01888 else
01889 captions_found = false;
01890
01891 if (!captions_found && osd && osd_msg)
01892 {
01893 QString msg = QObject::tr(
01894 "No captions", "CC/Teletext/Subtitle text not available");
01895 osd->SetSettingsText(msg, 3 );
01896 }
01897
01898
01899
01900 ResetCaptions(origMode);
01901 if (origMode != textDisplayMode)
01902 DisableCaptions(origMode, false);
01903 }
01904
01908 void NuppelVideoPlayer::SetTeletextPage(uint page)
01909 {
01910 QMutexLocker locker(&decoder_change_lock);
01911
01912 DisableCaptions(textDisplayMode);
01913 ttPageNum = page;
01914 textDisplayMode &= ~kDisplayAllCaptions;
01915 textDisplayMode |= kDisplayNUVTeletextCaptions;
01916 }
01917
01918 bool NuppelVideoPlayer::HandleTeletextAction(const QString &action)
01919 {
01920 if (!(textDisplayMode & kDisplayTeletextMenu) || !GetOSD())
01921 return false;
01922
01923 bool handled = true;
01924
01925 TeletextViewer *tt = GetOSD()->GetTeletextViewer();
01926 if (!tt)
01927 return false;
01928
01929 if (action == "NEXTPAGE")
01930 tt->KeyPress(TTKey::kNextPage);
01931 else if (action == "PREVPAGE")
01932 tt->KeyPress(TTKey::kPrevPage);
01933 else if (action == "NEXTSUBPAGE")
01934 tt->KeyPress(TTKey::kNextSubPage);
01935 else if (action == "PREVSUBPAGE")
01936 tt->KeyPress(TTKey::kPrevSubPage);
01937 else if (action == "TOGGLEBACKGROUND")
01938 tt->KeyPress(TTKey::kTransparent);
01939 else if (action == "MENURED")
01940 tt->KeyPress(TTKey::kFlofRed);
01941 else if (action == "MENUGREEN")
01942 tt->KeyPress(TTKey::kFlofGreen);
01943 else if (action == "MENUYELLOW")
01944 tt->KeyPress(TTKey::kFlofYellow);
01945 else if (action == "MENUBLUE")
01946 tt->KeyPress(TTKey::kFlofBlue);
01947 else if (action == "MENUWHITE")
01948 tt->KeyPress(TTKey::kFlofWhite);
01949 else if (action == "REVEAL")
01950 tt->KeyPress(TTKey::kRevealHidden);
01951 else if (action == "0" || action == "1" || action == "2" ||
01952 action == "3" || action == "4" || action == "5" ||
01953 action == "6" || action == "7" || action == "8" ||
01954 action == "9")
01955 tt->KeyPress(action.toInt());
01956 else if (action == "MENU" || action == "TOGGLETT" ||
01957 action == "ESCAPE")
01958 DisableTeletext();
01959 else
01960 handled = false;
01961
01962 return handled;
01963 }
01964
01968 void NuppelVideoPlayer::ShowText(void)
01969 {
01970 VideoFrame *last = videoOutput->GetLastShownFrame();
01971
01972
01973 if (osd && tbuffer_numvalid() && txtbuffers[rtxt].timecode &&
01974 (last && txtbuffers[rtxt].timecode <= last->timecode))
01975 {
01976 if (txtbuffers[rtxt].type == 'T')
01977 {
01978
01979
01980
01981
01982
01983
01984
01985 unsigned char *inpos = txtbuffers[rtxt].buffer;
01986 int pagenr;
01987 memcpy(&pagenr, inpos, sizeof(int));
01988 inpos += sizeof(int);
01989
01990 if (pagenr == (ttPageNum<<16))
01991 {
01992
01993 osd->ClearAllCCText();
01994 (*inpos)++;
01995 while (*inpos)
01996 {
01997 struct teletextsubtitle st;
01998 memcpy(&st, inpos, sizeof(st));
01999 inpos += sizeof(st);
02000 QString s((const char*) inpos);
02001 osd->AddCCText(s, st.row, st.col, st.fg, true);
02002 inpos += st.len;
02003 }
02004 }
02005 }
02006 else if (txtbuffers[rtxt].type == 'C')
02007 {
02008 UpdateCC(txtbuffers[rtxt].buffer);
02009 }
02010
02011 text_buflock.lock();
02012 if (rtxt != wtxt)
02013
02014 rtxt = (rtxt + 1) % MAXTBUFFER;
02015 text_buflock.unlock();
02016 }
02017 }
02018
02022 void NuppelVideoPlayer::ResetCC(void)
02023 {
02024 ccline = "";
02025 cccol = 0;
02026 ccrow = 0;
02027 if (osd)
02028 osd->ClearAllCCText();
02029 }
02030
02034 void NuppelVideoPlayer::UpdateCC(unsigned char *inpos)
02035 {
02036 struct ccsubtitle subtitle;
02037
02038 memcpy(&subtitle, inpos, sizeof(subtitle));
02039 inpos += sizeof(ccsubtitle);
02040
02041
02042 if ((subtitle.resumetext & CC_MODE_MASK) != ccmode)
02043 return;
02044
02045 if (subtitle.row == 0)
02046 subtitle.row = 1;
02047
02048 if (subtitle.clr)
02049 {
02050
02051 ResetCC();
02052 if (!subtitle.len)
02053 return;
02054 }
02055
02056
02057 {
02058 unsigned char *end = inpos + subtitle.len;
02059 int row = 0;
02060 int linecont = (subtitle.resumetext & CC_LINE_CONT);
02061
02062 vector<ccText*> *ccbuf = new vector<ccText*>;
02063 vector<ccText*>::iterator ccp;
02064 ccText *tmpcc = NULL;
02065 int replace = linecont;
02066 int scroll = 0;
02067 bool scroll_prsv = false;
02068 int scroll_yoff = 0;
02069 int scroll_ymax = 15;
02070
02071 do
02072 {
02073 if (linecont)
02074 {
02075
02076 replace = 1;
02077
02078 int bscnt = 0;
02079 while ((inpos < end) && *inpos != 0 && (char)*inpos == '\b')
02080 {
02081 bscnt++;
02082 inpos++;
02083 }
02084 if (bscnt)
02085 ccline.remove(ccline.length() - bscnt, bscnt);
02086 }
02087 else
02088 {
02089
02090 row++;
02091 cccol = 0;
02092 ccline = "";
02093 while ((inpos < end) && *inpos != 0 && (char)*inpos == ' ')
02094 {
02095 inpos++;
02096 cccol++;
02097 }
02098 }
02099
02100 ccrow = subtitle.row;
02101 unsigned char *cur = inpos;
02102
02103
02104 while (cur < end && *cur != '\n' && *cur != 0)
02105 cur++;
02106 *cur = 0;
02107
02108 if (*inpos != 0 || linecont)
02109 {
02110 if (linecont)
02111 ccline += QString::fromUtf8((const char *)inpos, -1);
02112 else
02113 ccline = QString::fromUtf8((const char *)inpos, -1);
02114 tmpcc = new ccText();
02115 tmpcc->text = ccline;
02116 tmpcc->x = cccol;
02117 tmpcc->y = ccrow;
02118 tmpcc->color = 0;
02119 tmpcc->teletextmode = false;
02120 ccbuf->push_back(tmpcc);
02121 #if 0
02122 if (ccbuf->size() > 4)
02123 {
02124 printf("CC overflow: ");
02125 printf("%d %d %s\n", cccol, ccrow, ccline.ascii());
02126 }
02127 #endif
02128 }
02129 subtitle.row++;
02130 inpos = cur + 1;
02131 linecont = 0;
02132 } while (inpos < end);
02133
02134
02135 if (subtitle.resumetext & CC_TXT_MASK)
02136 {
02137
02138
02139
02140 if (ccrow > 15)
02141 {
02142 if (row)
02143 scroll = ccrow - 15;
02144 if (tmpcc)
02145 tmpcc->y = 15;
02146 }
02147 }
02148 else if (subtitle.rowcount == 0 || row > 1)
02149 {
02150
02151
02152 if (ccrow > 15)
02153 {
02154 ccp = ccbuf->begin();
02155 for (; ccp != ccbuf->end(); ccp++)
02156 {
02157 tmpcc = *ccp;
02158 tmpcc->y -= (ccrow - 15);
02159 }
02160 }
02161 }
02162 else
02163 {
02164
02165
02166
02167
02168
02169 if (subtitle.rowcount > 4)
02170 subtitle.rowcount = 4;
02171 if (ccrow < subtitle.rowcount)
02172 {
02173 ccrow = subtitle.rowcount;
02174 if (tmpcc)
02175 tmpcc->y = ccrow;
02176 }
02177 if (row)
02178 {
02179 scroll = row;
02180 scroll_prsv = true;
02181 scroll_yoff = ccrow - subtitle.rowcount;
02182 scroll_ymax = ccrow;
02183 }
02184 }
02185
02186 if (osd)
02187 osd->UpdateCCText(ccbuf, replace, scroll,
02188 scroll_prsv, scroll_yoff, scroll_ymax);
02189 delete ccbuf;
02190 }
02191 }
02192
02194 #define MAXWARPDIFF 0.0005f
02196 #define WARPMULTIPLIER 1000000000
02198 #define WARPAVLEN (video_frame_rate * 600)
02199
02200 #define WARPCLIP 0.1f
02201
02202 #define MAXDIVERGE 3.0f
02203
02205 #define DIVERGELIMIT 30.0f
02206
02207 float NuppelVideoPlayer::WarpFactor(void)
02208 {
02209
02210 float divergence;
02211 float rate;
02212 float newwarp = 1;
02213 float warpdiff;
02214
02215
02216 divergence = (float)avsync_avg / (float)frame_interval;
02217
02218 rate = (float)(avsync_avg - avsync_oldavg) / (float)frame_interval;
02219 avsync_oldavg = avsync_avg;
02220 newwarp = warpfactor_avg * (1 + ((divergence + rate) / 125));
02221
02222
02223 warpdiff = newwarp / warpfactor;
02224 if (warpdiff > (1 + MAXWARPDIFF))
02225 newwarp = warpfactor * (1 + MAXWARPDIFF);
02226 else if (warpdiff < (1 - MAXWARPDIFF))
02227 newwarp = warpfactor * (1 - MAXWARPDIFF);
02228
02229 warpfactor = newwarp;
02230
02231
02232 if (warpfactor < (1 - WARPCLIP))
02233 warpfactor = 1 - WARPCLIP;
02234 else if (warpfactor > (1 + (WARPCLIP * 2)))
02235 warpfactor = 1 + (WARPCLIP * 2);
02236
02237
02238 warpfactor_avg = (warpfactor + (warpfactor_avg * (WARPAVLEN - 1))) /
02239 WARPAVLEN;
02240
02241 VERBOSE(VB_PLAYBACK|VB_TIMESTAMP,
02242 LOC + QString("A/V Divergence: %1, Rate: %2, Warpfactor: %3, "
02243 "warpfactor_avg: %4")
02244 .arg(divergence).arg(rate).arg(warpfactor).arg(warpfactor_avg));
02245
02246 return divergence;
02247 }
02248
02249 void NuppelVideoPlayer::InitAVSync(void)
02250 {
02251 videosync->Start();
02252
02253 avsync_adjustment = 0;
02254
02255 if (usevideotimebase)
02256 {
02257 warpfactor_avg = gContext->GetNumSetting("WarpFactor", 0);
02258 if (warpfactor_avg)
02259 warpfactor_avg /= WARPMULTIPLIER;
02260 else
02261 warpfactor_avg = 1;
02262
02263 if (warpfactor_avg < (1 - WARPCLIP))
02264 warpfactor_avg = 1;
02265 if (warpfactor_avg > (1 + (WARPCLIP * 2)) )
02266 warpfactor_avg = 1;
02267
02268 warpfactor = warpfactor_avg;
02269 }
02270
02271 refreshrate = videoOutput->GetRefreshRate();
02272 if (refreshrate <= 0)
02273 refreshrate = frame_interval;
02274 vsynctol = refreshrate / 4;
02275
02276 if (!using_null_videoout)
02277 {
02278 if (usevideotimebase)
02279 VERBOSE(VB_PLAYBACK, "Using video as timebase");
02280 else
02281 VERBOSE(VB_PLAYBACK, "Using audio as timebase");
02282
02283 QString timing_type = videosync->getName();
02284
02285 QString msg = QString("Video timing method: %1").arg(timing_type);
02286 VERBOSE(VB_GENERAL, msg);
02287 msg = QString("Refresh rate: %1, frame interval: %2")
02288 .arg(refreshrate).arg(frame_interval);
02289 VERBOSE(VB_PLAYBACK, msg);
02290 nice(-19);
02291 }
02292 }
02293
02294 void NuppelVideoPlayer::AVSync(void)
02295 {
02296 float diverge = 0.0f;
02297
02298 VideoFrame *buffer = videoOutput->GetLastShownFrame();
02299 if (!buffer)
02300 {
02301 VERBOSE(VB_IMPORTANT, LOC_ERR + "AVSync: No video buffer");
02302 return;
02303 }
02304 if (videoOutput->IsErrored())
02305 {
02306 VERBOSE(VB_IMPORTANT, LOC_ERR + "AVSync: "
02307 "Unknown error in videoOutput, aborting playback.");
02308 errored = true;
02309 return;
02310 }
02311
02312
02313 if (normal_speed)
02314 {
02315 diverge = WarpFactor();
02316
02317
02318 diverge = max(diverge, -DIVERGELIMIT);
02319 diverge = min(diverge, +DIVERGELIMIT);
02320 }
02321
02322 FrameScanType ps = m_scan;
02323 if (kScan_Detect == m_scan || kScan_Ignore == m_scan)
02324 ps = kScan_Progressive;
02325
02326 if (diverge < -MAXDIVERGE)
02327 {
02328
02329 QString dbg = QString("Video is %1 frames behind audio (too slow), ")
02330 .arg(-diverge);
02331
02332
02333 lastsync = true;
02334
02335 if (buffer && !using_null_videoout &&
02336 (videoOutput->hasMCAcceleration() ||
02337 videoOutput->hasIDCTAcceleration() ||
02338 videoOutput->hasVLDAcceleration()))
02339 {
02340
02341
02342 videoOutput->PrepareFrame(buffer, kScan_Intr2ndField);
02343 videoOutput->Show(kScan_Intr2ndField);
02344 VERBOSE(VB_PLAYBACK, LOC + dbg + "skipping A/V wait.");
02345 }
02346 else
02347 {
02348
02349 VERBOSE(VB_PLAYBACK, LOC + dbg + "dropping frame to catch up.");
02350 }
02351 }
02352 else if (!using_null_videoout)
02353 {
02354
02355 if (buffer)
02356 videoOutput->PrepareFrame(buffer, ps);
02357
02358 videosync->WaitForFrame(avsync_adjustment);
02359 if (!resetvideo)
02360 videoOutput->Show(ps);
02361
02362 if (videoOutput->IsErrored())
02363 {
02364 VERBOSE(VB_IMPORTANT, "NVP: Error condition detected "
02365 "in videoOutput after Show(), aborting playback.");
02366 errored = true;
02367 return;
02368 }
02369
02370 if (m_double_framerate)
02371 {
02372
02373 if (m_double_process && ps != kScan_Progressive)
02374 {
02375 videofiltersLock.lock();
02376 if (ringBuffer->isDVD() &&
02377 ringBuffer->DVD()->InStillFrame() &&
02378 videoOutput->ValidVideoFrames() < 3)
02379 {
02380 videoOutput->ProcessFrame(buffer, NULL, NULL, pipplayer);
02381 }
02382 else
02383 {
02384 videoOutput->ProcessFrame(
02385 buffer, osd, videoFilters, pipplayer);
02386 }
02387 videofiltersLock.unlock();
02388 }
02389
02390 ps = (kScan_Intr2ndField == ps) ?
02391 kScan_Interlaced : kScan_Intr2ndField;
02392
02393 if (buffer)
02394 videoOutput->PrepareFrame(buffer, ps);
02395
02396
02397 videosync->AdvanceTrigger();
02398 videosync->WaitForFrame(0);
02399 if (!resetvideo)
02400 {
02401 videoOutput->Show(ps);
02402 }
02403 }
02404 }
02405 else
02406 {
02407 videosync->WaitForFrame(0);
02408 }
02409
02410 if (output_jmeter && output_jmeter->RecordCycleTime())
02411 {
02412 VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString("A/V avsync_delay: %1, "
02413 "avsync_avg: %2, warpfactor: %3, warpfactor_avg: %4")
02414 .arg(avsync_delay / 1000).arg(avsync_avg / 1000)
02415 .arg(warpfactor).arg(warpfactor_avg));
02416 }
02417
02418 videosync->AdvanceTrigger();
02419 avsync_adjustment = 0;
02420
02421 if (diverge > MAXDIVERGE)
02422 {
02423
02424
02425
02426 avsync_adjustment = frame_interval;
02427 lastsync = true;
02428 VERBOSE(VB_PLAYBACK, LOC +
02429 QString("Video is %1 frames ahead of audio,\n"
02430 "\t\t\tdoubling video frame interval to slow down.").arg(diverge));
02431 }
02432
02433 if (audioOutput && normal_speed)
02434 {
02435 long long currentaudiotime = audioOutput->GetAudiotime();
02436 #if 0
02437 VERBOSE(VB_PLAYBACK|VB_TIMESTAMP, QString(
02438 "A/V timecodes audio %1 video %2 frameinterval %3 "
02439 "avdel %4 avg %5 tcoffset %6")
02440 .arg(currentaudiotime)
02441 .arg(buffer->timecode)
02442 .arg(frame_interval)
02443 .arg(buffer->timecode - currentaudiotime)
02444 .arg(avsync_avg)
02445 .arg(tc_wrap[TC_AUDIO])
02446 );
02447 #endif
02448 if (currentaudiotime != 0 && buffer->timecode != 0)
02449 {
02450
02451
02452 int delta = (int)((buffer->timecode - prevtc)/play_speed) - (frame_interval / 1000);
02453 prevtc = buffer->timecode;
02454
02455
02456
02457 if (delta > (int) frame_interval / 1200 &&
02458 delta < (int) frame_interval / 1000 * 3)
02459 {
02460
02461 videosync->AdvanceTrigger();
02462 if (m_double_framerate)
02463 videosync->AdvanceTrigger();
02464 }
02465
02466 avsync_delay = (buffer->timecode - currentaudiotime) * 1000;
02467
02468 if (avsync_delay > 2000000 && ringBuffer->isDVD())
02469 avsync_delay = 90000;
02470 avsync_avg = (avsync_delay + (avsync_avg * 3)) / 4;
02471 if (!usevideotimebase)
02472 {
02473
02474
02475
02476 if (!lastsync)
02477 {
02478 if (avsync_avg > frame_interval * 3 / 2)
02479 {
02480 avsync_adjustment = refreshrate;
02481 lastsync = true;
02482 }
02483 else if (avsync_avg < 0 - frame_interval * 3 / 2)
02484 {
02485 avsync_adjustment = -refreshrate;
02486 lastsync = true;
02487 }
02488 }
02489 else
02490 lastsync = false;
02491 }
02492 }
02493 else
02494 {
02495 avsync_avg = 0;
02496 avsync_oldavg = 0;
02497 }
02498 }
02499 }
02500
02501 void NuppelVideoPlayer::ShutdownAVSync(void)
02502 {
02503 if (usevideotimebase)
02504 {
02505 gContext->SaveSetting("WarpFactor",
02506 (int)(warpfactor_avg * WARPMULTIPLIER));
02507
02508 if (warplbuff)
02509 {
02510 free(warplbuff);
02511 warplbuff = NULL;
02512 }
02513
02514 if (warprbuff)
02515 {
02516 free(warprbuff);
02517 warprbuff = NULL;
02518 }
02519 warpbuffsize = 0;
02520 }
02521 }
02522
02523 void NuppelVideoPlayer::DisplayPauseFrame(void)
02524 {
02525 if (!video_actually_paused)
02526 videoOutput->UpdatePauseFrame();
02527
02528 if (resetvideo)
02529 {
02530 videoOutput->UpdatePauseFrame();
02531 resetvideo = false;
02532 }
02533
02534 SetVideoActuallyPaused(true);
02535
02536 if (videoOutput->IsErrored())
02537 {
02538 errored = true;
02539 return;
02540 }
02541
02542 DisplayDVDButton();
02543
02544 videofiltersLock.lock();
02545 videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
02546 videofiltersLock.unlock();
02547
02548 videoOutput->PrepareFrame(NULL, kScan_Ignore);
02549 videoOutput->Show(kScan_Ignore);
02550 videosync->Start();
02551 }
02552
02553 bool NuppelVideoPlayer::PrebufferEnoughFrames(void)
02554 {
02555 prebuffering_lock.lock();
02556 if (prebuffering)
02557 {
02558 if (ringBuffer->InDVDMenuOrStillFrame() &&
02559 prebuffer_tries > 3)
02560 {
02561 prebuffering = false;
02562 prebuffer_tries = 0;
02563 prebuffering_lock.unlock();
02564 return true;
02565 }
02566
02567 if (!ringBuffer->InDVDMenuOrStillFrame() &&
02568 !audio_paused && audioOutput)
02569 {
02570 if (prebuffering)
02571 audioOutput->Pause(prebuffering);
02572 audio_paused = prebuffering;
02573 }
02574
02575 VERBOSE(VB_PLAYBACK, LOC + QString("Waiting for prebuffer.. %1 %2")
02576 .arg(prebuffer_tries).arg(videoOutput->GetFrameStatus()));
02577 if (!prebuffering_wait.wait(&prebuffering_lock,
02578 frame_interval * 4 / 1000))
02579 {
02580
02581 }
02582 ++prebuffer_tries;
02583 if (prebuffering && (prebuffer_tries >= 10))
02584 {
02585 VERBOSE(VB_IMPORTANT, LOC + "Prebuffer wait timed out 10 times.");
02586 if (!videoOutput->EnoughFreeFrames())
02587 {
02588 VERBOSE(VB_IMPORTANT, LOC + "Prebuffer wait timed out, and"
02589 "\n\t\t\tthere are not enough free frames. "
02590 "Discarding buffered frames.");
02591
02592
02593 DiscardVideoFrames(true);
02594 }
02595 prebuffer_tries = 0;
02596 }
02597 prebuffering_lock.unlock();
02598 videosync->Start();
02599
02600 return false;
02601 }
02602 prebuffering_lock.unlock();
02603
02604
02605 if (!videoOutput->EnoughPrebufferedFrames())
02606 {
02607 VERBOSE(VB_GENERAL, LOC + "prebuffering pause");
02608 if (videoOutput)
02609 videoOutput->CheckFrameStates();
02610
02611 SetPrebuffering(true);
02612 #if FAST_RESTART
02613 if (!m_playing_slower && audio_channels <= 2)
02614 {
02615 m_stored_audio_stretchfactor = GetAudioStretchFactor();
02616 Play(m_stored_audio_stretchfactor * 0.8, true);
02617 m_playing_slower = true;
02618 VERBOSE(VB_GENERAL, "playing slower due to falling behind...");
02619 }
02620 #endif
02621 return false;
02622 }
02623
02624 #if FAST_RESTART
02625 if (m_playing_slower && videoOutput->EnoughDecodedFrames())
02626 {
02627 Play(m_stored_audio_stretchfactor, true);
02628 m_playing_slower = false;
02629 VERBOSE(VB_GENERAL, "playing at normal speed from falling behind...");
02630 }
02631 #endif
02632
02633 prebuffering_lock.lock();
02634 prebuffer_tries = 0;
02635 prebuffering_lock.unlock();
02636
02637 return true;
02638 }
02639
02640 void NuppelVideoPlayer::DisplayNormalFrame(void)
02641 {
02642 SetVideoActuallyPaused(false);
02643 resetvideo = false;
02644
02645 if (!ringBuffer->InDVDMenuOrStillFrame() ||
02646 (ringBuffer->DVD()->NumMenuButtons() > 0 &&
02647 ringBuffer->DVD()->GetChapterLength() > 3))
02648 {
02649 if (!PrebufferEnoughFrames())
02650 {
02651
02652 if (paused)
02653 {
02654 usleep(frame_interval);
02655 DisplayPauseFrame();
02656 }
02657 return;
02658 }
02659 }
02660
02661 videoOutput->StartDisplayingFrame();
02662
02663 VideoFrame *frame = videoOutput->GetLastShownFrame();
02664
02665 if (yuv_need_copy)
02666 {
02667
02668 QMutexLocker locker(&yuv_lock);
02669 QSize vsize = video_dim;
02670 if ((vsize != yuv_scaler_in_size) ||
02671 (yuv_desired_size != yuv_scaler_out_size))
02672 {
02673 ShutdownYUVResize();
02674
02675 uint sz = yuv_desired_size.width() * yuv_desired_size.height();
02676 yuv_frame_scaled = new unsigned char[(sz * 3 / 2) + 128];
02677
02678 yuv_scaler_in_size = vsize;
02679 yuv_scaler_out_size = yuv_desired_size;
02680
02681 yuv_scaler = img_resample_init(
02682 yuv_scaler_out_size.width(), yuv_scaler_out_size.height(),
02683 yuv_scaler_in_size.width(), yuv_scaler_in_size.height());
02684 }
02685
02686 AVPicture img_out, img_in;
02687 avpicture_fill(&img_out, yuv_frame_scaled, PIX_FMT_YUV420P,
02688 yuv_scaler_out_size.width(),
02689 yuv_scaler_out_size.height());
02690 avpicture_fill(&img_in, frame->buf, PIX_FMT_YUV420P,
02691 yuv_scaler_in_size.width(),
02692 yuv_scaler_in_size.height());
02693
02694 img_resample(yuv_scaler, &img_out, &img_in);
02695 yuv_need_copy = false;
02696 yuv_wait.wakeAll();
02697 }
02698
02699 DisplayDVDButton();
02700
02701
02702 if (GetInteractiveTV() && GetDecoder())
02703 {
02704 QMutexLocker locker(&itvLock);
02705
02706 OSD *osd = GetOSD();
02707 if (osd)
02708 {
02709 OSDSet *itvosd = osd->GetSet("interactive");
02710
02711 if (itvosd)
02712 {
02713 bool visible = false;
02714 if (interactiveTV->ImageHasChanged() || !itvVisible)
02715 {
02716 interactiveTV->UpdateOSD(itvosd);
02717 visible = true;
02718 itvVisible = true;
02719 }
02720
02721 if (visible)
02722 osd->SetVisible(itvosd, 0);
02723 }
02724 }
02725 }
02726
02727
02728 if (textDisplayMode & kDisplayNUVCaptions)
02729 ShowText();
02730
02731
02732 if (ffrew_skip == 1)
02733 {
02734 if (textDisplayMode & kDisplayAVSubtitle)
02735 DisplayAVSubtitles();
02736 else if (textDisplayMode & kDisplayTextSubtitle)
02737 DisplayTextSubtitles();
02738 else if (osdHasSubtitles)
02739 ClearSubtitles();
02740 else
02741 ExpireSubtitles();
02742 }
02743
02744
02745 AutoDeint(frame);
02746
02747 videofiltersLock.lock();
02748 if (ringBuffer->isDVD() &&
02749 ringBuffer->DVD()->InStillFrame() &&
02750 videoOutput->ValidVideoFrames() < 3)
02751 {
02752 videoOutput->ProcessFrame(frame, NULL, NULL, pipplayer);
02753 }
02754 else
02755 videoOutput->ProcessFrame(frame, osd, videoFilters, pipplayer);
02756 videofiltersLock.unlock();
02757
02758 if (audioOutput && !audio_paused && audioOutput->GetPause())
02759 audioOutput->Pause(false);
02760
02761 AVSync();
02762
02763 videoOutput->DoneDisplayingFrame();
02764 }
02765
02766 void NuppelVideoPlayer::OutputVideoLoop(void)
02767 {
02768 delay = 0;
02769 avsync_delay = 0;
02770 avsync_avg = 0;
02771 avsync_oldavg = 0;
02772 refreshrate = 0;
02773 lastsync = false;
02774
02775 usevideotimebase = gContext->GetNumSetting("UseVideoTimebase", 0);
02776
02777 if ((print_verbose_messages & VB_PLAYBACK) != 0)
02778 output_jmeter = new Jitterometer("video_output", 100);
02779 else
02780 output_jmeter = NULL;
02781
02782 refreshrate = frame_interval;
02783
02784 float temp_speed = (play_speed == 0.0) ? audio_stretchfactor : play_speed;
02785 uint fr_int = (int)(1000000.0 / video_frame_rate / temp_speed);
02786 uint rf_int = 0;
02787 if (videoOutput)
02788 rf_int = videoOutput->GetRefreshRate();
02789
02790
02791
02792
02793
02794 m_scan = kScan_Interlaced;
02795 m_scan_locked = false;
02796 m_double_framerate = false;
02797 m_can_double = false;
02798 m_scan_tracker = 2;
02799
02800 if (using_null_videoout)
02801 {
02802 videosync = new USleepVideoSync(videoOutput, (int)fr_int, 0, false);
02803 }
02804 else if (videoOutput)
02805 {
02806
02807 m_double_framerate =
02808 (videoOutput->SetupDeinterlace(true) &&
02809 videoOutput->NeedsDoubleFramerate());
02810
02811 m_double_process = videoOutput->IsExtraProcessingRequired();
02812
02813 videosync = VideoSync::BestMethod(
02814 videoOutput, fr_int, rf_int, m_double_framerate);
02815
02816
02817 if (videosync != NULL && m_double_framerate)
02818 {
02819 videosync->SetFrameInterval(frame_interval, m_double_framerate);
02820 m_can_double = videosync->UsesFieldInterval();
02821 if (!m_can_double)
02822 {
02823 VERBOSE(VB_IMPORTANT, "Video sync method can't support double "
02824 "framerate (refresh rate too low for bob deint)");
02825 FallbackDeint();
02826 }
02827
02828 if (osd && !IsIVTVDecoder())
02829 {
02830 osd->SetFrameInterval(
02831 (m_double_framerate && m_double_process) ?
02832 (frame_interval>>1) : frame_interval);
02833 }
02834 }
02835 }
02836 if (!videosync)
02837 {
02838 videosync = new BusyWaitVideoSync(
02839 videoOutput, (int)fr_int, (int)rf_int, m_double_framerate);
02840 }
02841
02842 InitAVSync();
02843
02844 videosync->Start();
02845
02846 while (!killvideo)
02847 {
02848 if (needsetpipplayer)
02849 {
02850 pipplayer = setpipplayer;
02851 needsetpipplayer = false;
02852 }
02853
02854 if (ringBuffer->isDVD())
02855 {
02856 int nbframes = videoOutput->ValidVideoFrames();
02857
02858 if (nbframes < 2)
02859 {
02860 bool isWaiting = ringBuffer->DVD()->IsWaiting();
02861
02862 if (isWaiting)
02863 {
02864 ringBuffer->DVD()->WaitSkip();
02865 continue;
02866 }
02867
02868 if (ringBuffer->InDVDMenuOrStillFrame())
02869 {
02870 if (nbframes == 0)
02871 {
02872 VERBOSE(VB_PLAYBACK, LOC_ERR +
02873 "In DVD Menu: No video frames in queue");
02874 if (pausevideo)
02875 UnpauseVideo();
02876 usleep(10000);
02877 continue;
02878 }
02879
02880 if (!pausevideo && nbframes == 1)
02881 {
02882 dvd_stillframe_showing = true;
02883 PauseVideo(false);
02884 }
02885 }
02886 }
02887
02888 if (dvd_stillframe_showing && nbframes > 1)
02889 {
02890 UnpauseVideo();
02891 dvd_stillframe_showing = false;
02892 continue;
02893 }
02894 }
02895
02896 if (pausevideo || isDummy)
02897 {
02898 usleep(frame_interval);
02899 DisplayPauseFrame();
02900 }
02901 else
02902 DisplayNormalFrame();
02903 }
02904
02905 {
02906 QMutexLocker locker(&vidExitLock);
02907 delete videosync;
02908 videosync = NULL;
02909
02910 delete videoOutput;
02911 videoOutput = NULL;
02912 }
02913
02914 ShutdownAVSync();
02915 }
02916
02917 #ifdef USING_IVTV
02918
02925 void NuppelVideoPlayer::IvtvVideoLoop(void)
02926 {
02927 refreshrate = frame_interval;
02928 int delay = frame_interval;
02929
02930 VideoOutputIvtv *vidout = (VideoOutputIvtv *)videoOutput;
02931 vidout->SetFPS(GetFrameRate());
02932
02933 while (!killvideo)
02934 {
02935 if (needsetpipplayer)
02936 {
02937 pipplayer = setpipplayer;
02938 needsetpipplayer = false;
02939 }
02940
02941 resetvideo = false;
02942 SetVideoActuallyPaused(pausevideo);
02943
02944 if (pausevideo)
02945 {
02946 videofiltersLock.lock();
02947 videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
02948 videofiltersLock.unlock();
02949 }
02950 else
02951 {
02952
02953 if (textDisplayMode & kDisplayNUVCaptions)
02954 ShowText();
02955
02956 videofiltersLock.lock();
02957 videoOutput->ProcessFrame(NULL, osd, videoFilters, pipplayer);
02958 videofiltersLock.unlock();
02959 }
02960
02961 usleep(delay);
02962 }
02963
02964
02965 delete videoOutput;
02966 videoOutput = NULL;
02967 }
02968 #endif
02969
02970 void *NuppelVideoPlayer::kickoffOutputVideoLoop(void *player)
02971 {
02972 NuppelVideoPlayer *nvp = (NuppelVideoPlayer *)player;
02973
02974 #ifdef USING_IVTV
02975 if (nvp->IsIVTVDecoder())
02976 {
02977 nvp->IvtvVideoLoop();
02978 return NULL;
02979 }
02980 #endif
02981
02982
02983 void *video_thread_pool = CreateOSXCocoaPool();
02984 nvp->OutputVideoLoop();
02985 DeleteOSXCocoaPool(video_thread_pool);
02986
02987 return NULL;
02988 }
02989
02990 bool NuppelVideoPlayer::FastForward(float seconds)
02991 {
02992 if (!videoOutput)
02993 return false;
02994
02995 if (ringBuffer->isDVD() && GetDecoder())
02996 GetDecoder()->UpdateDVDFramesPlayed();
02997
02998 if (fftime <= 0)
02999 fftime = (int)(seconds * video_frame_rate);
03000
03001 if (osdHasSubtitles || !nonDisplayedAVSubtitles.empty())
03002 ClearSubtitles();
03003
03004 return fftime > CalcMaxFFTime(fftime, false);
03005 }
03006
03007 bool NuppelVideoPlayer::Rewind(float seconds)
03008 {
03009 if (!videoOutput)
03010 return false;
03011
03012 if (ringBuffer->isDVD() && GetDecoder())
03013 GetDecoder()->UpdateDVDFramesPlayed();
03014
03015 if (rewindtime <= 0)
03016 rewindtime = (int)(seconds * video_frame_rate);
03017
03018 if (osdHasSubtitles || !nonDisplayedAVSubtitles.empty())
03019 ClearSubtitles();
03020
03021 return rewindtime >= framesPlayed;
03022 }
03023
03024 void NuppelVideoPlayer::SkipCommercials(int direction)
03025 {
03026 if (skipcommercials == 0)
03027 skipcommercials = direction;
03028 }
03029
03030 void NuppelVideoPlayer::ResetPlaying(void)
03031 {
03032 ClearAfterSeek();
03033
03034 ffrew_skip = 1;
03035
03036 if (!ringBuffer->isDVD())
03037 framesPlayed = 0;
03038
03039 GetDecoder()->Reset();
03040 errored |= GetDecoder()->IsErrored();
03041 }
03042
03043 void NuppelVideoPlayer::CheckTVChain(void)
03044 {
03045 bool last = !(livetvchain->HasNext());
03046 SetWatchingRecording(last);
03047 }
03048
03049 void NuppelVideoPlayer::SwitchToProgram(void)
03050 {
03051 if (!IsReallyNearEnd())
03052 return;
03053 VERBOSE(VB_PLAYBACK, "SwitchToProgram(void)");
03054
03055 bool discontinuity = false, newtype = false;
03056 int newid = -1;
03057 ProgramInfo *pginfo = livetvchain->GetSwitchProgram(discontinuity, newtype,
03058 newid);
03059 if (!pginfo)
03060 return;
03061
03062 bool newIsDummy = livetvchain->GetCardType(newid) == "DUMMY";
03063
03064 SetPlaybackInfo(pginfo);
03065
03066 ringBuffer->Pause();
03067 ringBuffer->WaitForPause();
03068
03069 if (newIsDummy)
03070 {
03071 OpenDummy();
03072 ResetPlaying();
03073 DoPause();
03074 eof = false;
03075 return;
03076 }
03077
03078 ringBuffer->OpenFile(pginfo->GetPlaybackURL(),
03079 10 );
03080 if (!ringBuffer->IsOpen())
03081 {
03082 VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram's OpenFile failed.");
03083 eof = true;
03084 errored = true;
03085 return;
03086 }
03087
03088 if (eof)
03089 {
03090 discontinuity = true;
03091 ClearSubtitles();
03092 }
03093
03094 livetvchain->SetProgram(pginfo);
03095
03096 if (discontinuity || newtype)
03097 {
03098 GetDecoder()->SetProgramInfo(pginfo);
03099
03100 ringBuffer->Reset(true);
03101 if (newtype)
03102 errored = (OpenFile() >= 0) ? errored : true;
03103 else
03104 ResetPlaying();
03105 }
03106 else
03107 {
03108 GetDecoder()->SetReadAdjust(ringBuffer->SetAdjustFilesize());
03109 GetDecoder()->SetWaitForChange();
03110 if (m_tv)
03111 m_tv->SetIgnoreKeys(true);
03112 }
03113 if (IsErrored())
03114 {
03115 VERBOSE(VB_IMPORTANT, LOC_ERR + "SwitchToProgram failed.");
03116 eof = true;
03117 return;
03118 }
03119
03120
03121 ringBuffer->UpdateRawBitrate(GetDecoder()->GetRawBitrate());
03122
03123 ringBuffer->Unpause();
03124
03125 if (discontinuity || newtype)
03126 {
03127 if (m_tv)
03128 m_tv->SetCurrentlyPlaying(pginfo);
03129
03130 CheckTVChain();
03131 GetDecoder()->SyncPositionMap();
03132 }
03133
03134 eof = false;
03135 }
03136
03137 void NuppelVideoPlayer::FileChangedCallback(void)
03138 {
03139 VERBOSE(VB_PLAYBACK, "FileChangedCallback");
03140
03141 ringBuffer->Pause();
03142 ringBuffer->WaitForPause();
03143
03144 if (dynamic_cast<AvFormatDecoder *>(GetDecoder()))
03145 ringBuffer->Reset(false, true);
03146 else
03147 ringBuffer->Reset(false, true, true);
03148
03149 ringBuffer->Unpause();
03150
03151 if (m_tv)
03152 m_tv->SetIgnoreKeys(false);
03153
03154 livetvchain->SetProgram(m_playbackinfo);
03155 GetDecoder()->SetProgramInfo(m_playbackinfo);
03156 if (m_tv)
03157 m_tv->SetCurrentlyPlaying(m_playbackinfo);
03158
03159 CheckTVChain();
03160 GetDecoder()->SyncPositionMap();
03161 }
03162
03163 void NuppelVideoPlayer::JumpToProgram(void)
03164 {
03165 VERBOSE(VB_PLAYBACK, "JumpToProgram(void)");
03166 bool discontinuity = false, newtype = false;
03167 int newid = -1;
03168 ProgramInfo *pginfo = livetvchain->GetSwitchProgram(discontinuity, newtype,
03169 newid);
03170 if (!pginfo)
03171 return;
03172
03173 long long nextpos = livetvchain->GetJumpPos();
03174 bool newIsDummy = livetvchain->GetCardType(newid) == "DUMMY";
03175
03176 SetPlaybackInfo(pginfo);
03177
03178 ringBuffer->Pause();
03179 ringBuffer->WaitForPause();
03180
03181 ClearSubtitles();
03182
03183 livetvchain->SetProgram(pginfo);
03184
03185 ringBuffer->Reset(true);
03186
03187 if (newIsDummy)
03188 {
03189 OpenDummy();
03190 ResetPlaying();
03191 DoPause();
03192 eof = false;
03193 return;
03194 }
03195
03196 ringBuffer->OpenFile(pginfo->GetPlaybackURL());
03197 if (!ringBuffer->IsOpen())
03198 {
03199 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram's OpenFile failed.");
03200 eof = true;
03201 errored = true;
03202 return;
03203 }
03204
03205 bool wasDummy = isDummy;
03206 if (newtype || wasDummy)
03207 errored = (OpenFile() >= 0) ? errored : true;
03208 else
03209 ResetPlaying();
03210
03211 if (wasDummy)
03212 DoPlay();
03213
03214 if (errored || !GetDecoder())
03215 {
03216 VERBOSE(VB_IMPORTANT, LOC_ERR + "JumpToProgram failed.");
03217 errored = true;
03218 return;
03219 }
03220
03221
03222 ringBuffer->UpdateRawBitrate(GetDecoder()->GetRawBitrate());
03223
03224 ringBuffer->Unpause();
03225 ringBuffer->IgnoreLiveEOF(false);
03226
03227 GetDecoder()->SetProgramInfo(pginfo);
03228 if (m_tv)
03229 m_tv->SetCurrentlyPlaying(pginfo);
03230
03231 CheckTVChain();
03232 GetDecoder()->SyncPositionMap();
03233
03234 if (nextpos < 0)
03235 nextpos += totalFrames;
03236 if (nextpos < 0)
03237 nextpos = 0;
03238
03239 if (nextpos > 10)
03240 {
03241 bool seeks = exactseeks;
03242 GetDecoder()->setExactSeeks(false);
03243 fftime = nextpos;
03244 DoFastForward();
03245 fftime = 0;
03246 GetDecoder()->setExactSeeks(seeks);
03247 }
03248
03249 eof = false;
03250 }
03251
03252 void NuppelVideoPlayer::StartPlaying(void)
03253 {
03254 killplayer = false;
03255 framesPlayed = 0;
03256
03257 if (OpenFile() < 0)
03258 return;
03259
03260 if (ringBuffer->isDVD())
03261 ringBuffer->DVD()->SetParent(this);
03262
03263 if (!no_audio_out ||
03264 (IsIVTVDecoder() &&
03265 !gContext->GetNumSetting("PVR350InternalAudioOnly")))
03266 {
03267 QString errMsg = ReinitAudio();
03268 DialogCode ret = kDialogCodeButton0;
03269 if ((errMsg != QString::null) && !using_null_videoout &&
03270 gContext->GetNumSetting("AudioNag", 1))
03271 {
03272 DialogBox *dlg = new DialogBox(gContext->GetMainWindow(), errMsg);
03273
03274 QString noaudio = QObject::tr("Continue WITHOUT AUDIO!");
03275 QString dontask = noaudio + " " +
03276 QObject::tr("And, never ask again.");
03277 QString neverask = noaudio + " " +
03278 QObject::tr("And, don't ask again in this session.");
03279 QString quit = QObject::tr("Return to menu.");
03280
03281 dlg->AddButton(noaudio);
03282 dlg->AddButton(dontask);
03283 dlg->AddButton(neverask);
03284 dlg->AddButton(quit);
03285
03286 qApp->lock();
03287 ret = dlg->exec();
03288 dlg->deleteLater();
03289 qApp->unlock();
03290 }
03291
03292 if (kDialogCodeButton1 == ret)
03293 gContext->SaveSetting("AudioNag", 0);
03294 if (kDialogCodeButton2 == ret)
03295 gContext->SetSetting("AudioNag", 0);
03296 else if ((kDialogCodeButton3 == ret) || (kDialogCodeRejected == ret))
03297 return;
03298 }
03299
03300 if (audioOutput)
03301 {
03302 audio_paused = true;
03303 audioOutput->Pause(true);
03304 audioOutput->SetStretchFactor(audio_stretchfactor);
03305 }
03306
03307 next_play_speed = audio_stretchfactor;
03308
03309 if (!InitVideo())
03310 {
03311 VERBOSE(VB_IMPORTANT, "Unable to initialize video.");
03312 if (!using_null_videoout)
03313 {
03314 qApp->lock();
03315 DialogBox *dialog = new DialogBox(
03316 gContext->GetMainWindow(),
03317 QObject::tr("Unable to initialize video."));
03318 dialog->AddButton(QObject::tr("Return to menu."));
03319 dialog->exec();
03320 dialog->deleteLater();
03321 qApp->unlock();
03322 }
03323
03324 if (audioOutput)
03325 {
03326 delete audioOutput;
03327 audioOutput = NULL;
03328 }
03329 no_audio_out = true;
03330 return;
03331 }
03332
03333 if (!using_null_videoout)
03334 {
03335 QRect visible, total;
03336 float aspect, scaling;
03337
03338 osd = new OSD();
03339
03340 videoOutput->GetOSDBounds(total, visible, aspect, scaling, osd->GetThemeAspect());
03341 osd->Init(total, frame_interval, visible, aspect, scaling);
03342
03343 videoOutput->InitOSD(osd);
03344
03345 osd->SetCC708Service(&CC708services[1]);
03346
03347 TeletextViewer *tt_view = GetOSD()->GetTeletextViewer();
03348 if (tt_view)
03349 {
03350 decoder->SetTeletextDecoderViewer(tt_view);
03351 tt_view->SetDisplaying(false);
03352 }
03353 GetOSD()->HideSet("teletext");
03354
03355 if (GetInteractiveTV())
03356 GetInteractiveTV()->Reinit(total);
03357 }
03358
03359 playing = true;
03360
03361 rewindtime = fftime = 0;
03362 skipcommercials = 0;
03363
03364 ClearAfterSeek();
03365
03366
03367
03368
03369
03370
03371 pthread_t output_video, decoder_thread;
03372
03373 decoder_thread = pthread_self();
03374 pthread_create(&output_video, NULL, kickoffOutputVideoLoop, this);
03375
03376
03377 if (!using_null_videoout && !ringBuffer->isDVD())
03378 {
03379
03380
03381 #ifndef CONFIG_DARWIN
03382 gContext->addPrivRequest(MythPrivRequest::MythRealtime, &output_video);
03383 #endif
03384
03385
03386
03387 }
03388
03389 if (bookmarkseek > 30)
03390 {
03391 GetFrame(audioOutput == NULL || !normal_speed);
03392
03393 bool seeks = exactseeks;
03394
03395 GetDecoder()->setExactSeeks(false);
03396
03397 fftime = bookmarkseek;
03398 if (ringBuffer->isDVD())
03399 GetDVDBookmark();
03400 DoFastForward();
03401 fftime = 0;
03402
03403 GetDecoder()->setExactSeeks(seeks);
03404
03405 if (gContext->GetNumSetting("ClearSavedPosition", 1))
03406 {
03407 if (ringBuffer->isDVD())
03408 SetDVDBookmark(0);
03409 else
03410 m_playbackinfo->SetBookmark(0);
03411 }
03412 }
03413
03414 commBreakMapLock.lock();
03415 LoadCommBreakList();
03416 if (!commBreakMap.isEmpty())
03417 {
03418 hascommbreaktable = true;
03419 SetCommBreakIter();
03420 }
03421 commBreakMapLock.unlock();
03422
03423 if (isDummy)
03424 {
03425 DoPause();
03426 }
03427
03428 while (!killplayer && !errored)
03429 {
03430 if (m_playbackinfo)
03431 m_playbackinfo->UpdateInUseMark();
03432
03433 if (isDummy && livetvchain && livetvchain->HasNext())
03434 {
03435 livetvchain->JumpToNext(true, 1);
03436 JumpToProgram();
03437 }
03438 else if ((!paused || eof) && livetvchain && !GetDecoder()->GetWaitForChange())
03439 {
03440 if (livetvchain->NeedsToSwitch())
03441 SwitchToProgram();
03442 }
03443
03444 if (livetvchain && livetvchain->NeedsToJump() &&
03445 !GetDecoder()->GetWaitForChange())
03446 {
03447 JumpToProgram();
03448 }
03449
03450 if (forcePositionMapSync)
03451 {
03452 forcePositionMapSync = false;
03453 GetDecoder()->SyncPositionMap();
03454 }
03455
03456 if (IsErrored() || (nvr_enc && nvr_enc->GetErrorStatus()))
03457 {
03458 VERBOSE(VB_IMPORTANT, LOC_ERR + "Unknown error, exiting decoder");
03459 errored = killplayer = true;
03460 break;
03461 }
03462
03463 if (play_speed != next_play_speed &&
03464 (!livetvchain || (livetvchain && !livetvchain->NeedsToJump())))
03465 {
03466 decoder_lock.lock();
03467
03468 play_speed = next_play_speed;
03469 normal_speed = next_normal_speed;
03470 VERBOSE(VB_PLAYBACK, LOC + "Changing speed to " << play_speed);
03471
03472 if (play_speed == 0.0)
03473 {
03474 DoPause();
03475 decoderThreadPaused.wakeAll();
03476 }
03477 else
03478 {
03479 ringBuffer->UpdatePlaySpeed(play_speed);
03480 DoPlay();
03481 }
03482
03483 decoder_lock.unlock();
03484 continue;
03485 }
03486
03487 if (eof)
03488 {
03489 if (livetvchain)
03490 {
03491 if (!paused && livetvchain->HasNext())
03492 {
03493 VERBOSE(VB_IMPORTANT, "LiveTV forcing JumpTo 1");
03494 livetvchain->JumpToNext(true, 1);
03495 continue;
03496 }
03497 if (!paused)
03498 VERBOSE(VB_PLAYBACK, "Ignoring livetv eof in decoder loop");
03499 usleep(50000);
03500 }
03501 else
03502 break;
03503 }
03504
03505 if (isDummy)
03506 {
03507 decoderThreadPaused.wakeAll();
03508 usleep(500);
03509 continue;
03510 }
03511
03512 if (rewindtime < 0)
03513 rewindtime = 0;
03514 if (fftime < 0)
03515 fftime = 0;
03516
03517 if (paused)
03518 {
03519 decoderThreadPaused.wakeAll();
03520
03521 if (rewindtime > 0)
03522 {
03523 rewindtime = CalcRWTime(rewindtime);
03524 if (rewindtime > 0)
03525 {
03526 DoRewind();
03527
03528 GetFrame(audioOutput == NULL || !normal_speed);
03529 resetvideo = true;
03530 while (resetvideo)
03531 usleep(1000);
03532 }
03533 rewindtime = 0;
03534 }
03535 else if (fftime > 0)
03536 {
03537 fftime = CalcMaxFFTime(fftime);
03538 if (fftime > 0)
03539 {
03540 DoFastForward();
03541
03542 GetFrame(audioOutput == NULL || !normal_speed);
03543 resetvideo = true;
03544 while (resetvideo)
03545 usleep(1000);
03546 }
03547 fftime = 0;
03548 }
03549 else if (need_change_dvd_track)
03550 {
03551 DoChangeDVDTrack();
03552 GetFrame(audioOutput == NULL || !normal_speed);
03553 resetvideo = true;
03554 while (resetvideo)
03555 usleep(1000);
03556 need_change_dvd_track = 0;
03557 }
03558 else if (livetvchain && livetvchain->NeedsToJump())
03559 {
03560 JumpToProgram();
03561
03562 GetFrame(audioOutput == NULL || !normal_speed);
03563 resetvideo = true;
03564 while (resetvideo)
03565 usleep(1000);
03566 }
03567 else
03568 {
03569
03570 usleep(500);
03571 }
03572 continue;
03573 }
03574
03575 if (rewindtime > 0 && ffrew_skip == 1)
03576 {
03577 rewindtime = CalcRWTime(rewindtime);
03578
03579 if (rewindtime >= 1)
03580 {
03581 QMutexLocker locker(&internalPauseLock);
03582
03583 PauseVideo(true);
03584 DoRewind();
03585 UnpauseVideo(true);
03586 }
03587 rewindtime = 0;
03588 }
03589
03590 if (fftime > 0 && ffrew_skip == 1)
03591 {
03592 fftime = CalcMaxFFTime(fftime);
03593
03594 if (fftime >= 5)
03595 {
03596 QMutexLocker locker(&internalPauseLock);
03597
03598 PauseVideo(true);
03599
03600 if (fftime >= 5)
03601 DoFastForward();
03602
03603 if (eof)
03604 continue;
03605
03606 UnpauseVideo(true);
03607 }
03608
03609 fftime = 0;
03610 }
03611
03612 if (need_change_dvd_track)
03613 {
03614 QMutexLocker locker(&internalPauseLock);
03615
03616 PauseVideo(true);
03617 DoChangeDVDTrack();
03618 UnpauseVideo(true);
03619
03620 need_change_dvd_track = 0;
03621 }
03622
03623 if (skipcommercials != 0 && ffrew_skip == 1)
03624 {
03625 QMutexLocker locker(&internalPauseLock);
03626
03627 PauseVideo(true);
03628 DoSkipCommercials(skipcommercials);
03629 UnpauseVideo(true);
03630
03631 skipcommercials = 0;
03632 continue;
03633 }
03634
03635 GetFrame(audioOutput == NULL || !normal_speed);
03636
03637 if (using_null_videoout || IsIVTVDecoder())
03638 GetDecoder()->UpdateFramesPlayed();
03639 else
03640 framesPlayed = videoOutput->GetFramesPlayed();
03641
03642 if (ffrew_skip != 1)
03643 continue;
03644
03645 if (!hasdeletetable && autocommercialskip)
03646 AutoCommercialSkip();
03647
03648 if (hasdeletetable && deleteIter.data() == 1 &&
03649 framesPlayed >= deleteIter.key())
03650