Ticket #9287: 9287-v1.patch
File 9287-v1.patch, 165.7 KB (added by , 10 years ago) |
---|
-
libs/libmythtv/mythiowrapper.cpp
130 130 else 131 131 { 132 132 if (flags & O_WRONLY) 133 rb = new RingBuffer(pathname, true, false, -1); // Writeable 133 rb = RingBuffer::Create( 134 pathname, true, false, 135 RingBuffer::kDefaultOpenTimeout, true); // Writeable 134 136 else 135 rb = new RingBuffer(pathname, false, true, -1); // Read-Only 137 rb = RingBuffer::Create( 138 pathname, false, true, 139 RingBuffer::kDefaultOpenTimeout, true); // Read-Only 136 140 137 141 if (!rb) 138 142 return -1; 139 143 140 rb->SetStreamOnly(true);141 rb->OpenFile(pathname);142 144 rb->Start(); 143 145 } 144 146 -
libs/libmythtv/NuppelVideoRecorder.cpp
731 731 if (!ringBuffer) 732 732 { 733 733 VERBOSE(VB_IMPORTANT, LOC + "Warning, old RingBuffer creation"); 734 ringBuffer = new RingBuffer("output.nuv", true);734 ringBuffer = RingBuffer::Create("output.nuv", true); 735 735 weMadeBuffer = true; 736 736 livetv = false; 737 737 if (!ringBuffer->IsOpen()) -
libs/libmythtv/importrecorder.cpp
103 103 if (_import_fd && _request_recording && !_error) 104 104 { 105 105 MythCommFlagPlayer *cfp = new MythCommFlagPlayer(); 106 RingBuffer *rb = new RingBuffer(106 RingBuffer *rb = RingBuffer::Create( 107 107 ringBuffer->GetFilename(), false, true, 6000); 108 108 109 109 PlayerContext *ctx = new PlayerContext(kImportRecorderInUseID); -
libs/libmythtv/avformatdecoder.cpp
652 652 void AvFormatDecoder::SeekReset(long long newKey, uint skipFrames, 653 653 bool doflush, bool discardFrames) 654 654 { 655 if (ringBuffer->isDVD()) 656 { 657 if (ringBuffer->InDiscMenuOrStillFrame() || 658 newKey == 0) 659 return; 660 } 655 if (ringBuffer->IsInDiscMenuOrStillFrame() || newKey == 0) 656 return; 661 657 662 658 VERBOSE(VB_PLAYBACK, LOC + 663 659 QString("SeekReset(%1, %2, %3 flush, %4 discard)") … … 717 713 718 714 prevgoppos = 0; 719 715 gopset = false; 720 if (!ringBuffer-> isDVD())716 if (!ringBuffer->IsDVD()) 721 717 { 722 718 if (!no_dts_hack) 723 719 { … … 759 755 { 760 756 DecoderBase::Reset(); 761 757 762 if (ringBuffer-> isDVD())758 if (ringBuffer->IsDVD()) 763 759 SyncPositionMap(); 764 760 } 765 761 … … 800 796 int streamed = 0; 801 797 int buffer_size = 32768; 802 798 803 if (ringBuffer->isDVD()) { 799 if (ringBuffer->IsDVD()) 800 { 804 801 streamed = 1; 805 802 buffer_size = 2048; 806 803 } … … 920 917 QMutexLocker locker(avcodeclock); 921 918 ret = av_find_stream_info(ic); 922 919 } 923 if (ringBuffer-> isDVD())920 if (ringBuffer->IsDVD()) 924 921 { 925 922 if (!ringBuffer->DVD()->StartFromBeginning()) 926 923 return -1; … … 935 932 return -1; 936 933 } 937 934 ic->streams_changed = HandleStreamChange; 938 if (ringBuffer-> isDVD())935 if (ringBuffer->IsDVD()) 939 936 ic->streams_changed = HandleDVDStreamChange; 940 937 ic->stream_change_data = this; 941 938 942 939 fmt->flags &= ~AVFMT_NOFILE; 943 940 944 if (!ringBuffer-> isDVD() && !livetv)941 if (!ringBuffer->IsDVD() && !livetv) 945 942 av_estimate_timings(ic, 0); 946 943 947 944 // Scan for the initial A/V streams … … 1219 1216 <<") type ("<<ff_codec_type_string(enc->codec_type) 1220 1217 <<")."); 1221 1218 1222 if (ringBuffer && ringBuffer-> isDVD())1219 if (ringBuffer && ringBuffer->IsDVD()) 1223 1220 directrendering = false; 1224 1221 1225 1222 enc->opaque = (void *)this; … … 1721 1718 map<int,uint> lang_aud_cnt; 1722 1719 uint audioStreamCount = 0; 1723 1720 1724 if (ringBuffer && ringBuffer-> isDVD() &&1721 if (ringBuffer && ringBuffer->IsDVD() && 1725 1722 ringBuffer->DVD()->AudioStreamsChanged()) 1726 1723 { 1727 1724 ringBuffer->DVD()->AudioStreamsChanged(false); … … 1817 1814 #ifdef USING_XVMC 1818 1815 1819 1816 bool force_xv = no_hardware_decoders; 1820 if (ringBuffer && ringBuffer-> isDVD())1817 if (ringBuffer && ringBuffer->IsDVD()) 1821 1818 { 1822 1819 if (dec.left(4) == "xvmc") 1823 1820 dvd_xvmc_enabled = true; 1824 1821 1825 if (ringBuffer->I nDiscMenuOrStillFrame() &&1822 if (ringBuffer->IsInDiscMenuOrStillFrame() && 1826 1823 dvd_xvmc_enabled) 1827 1824 { 1828 1825 force_xv = true; … … 1845 1842 enc->codec_id = (CodecID) 1846 1843 myth2av_codecid(mcid, vcd, idct, mc, vdpau); 1847 1844 1848 if (ringBuffer && ringBuffer-> isDVD() &&1845 if (ringBuffer && ringBuffer->IsDVD() && 1849 1846 (mcid == video_codec_id) && 1850 1847 dvd_video_codec_changed) 1851 1848 { … … 2071 2068 if (enc->codec_type == CODEC_TYPE_SUBTITLE) 2072 2069 { 2073 2070 int lang; 2074 if (ringBuffer && ringBuffer->isBD()) 2075 lang = ringBuffer->BD()->GetSubtitleLanguage(subtitleStreamCount); 2071 if (ringBuffer && ringBuffer->IsBD()) 2072 { 2073 lang = ringBuffer->BD()-> 2074 GetSubtitleLanguage(subtitleStreamCount); 2075 } 2076 2076 else 2077 2077 { 2078 2078 AVMetadataTag *metatag = av_metadata_get(ic->streams[i]->metadata, … … 2096 2096 if (enc->codec_type == CODEC_TYPE_AUDIO) 2097 2097 { 2098 2098 int lang; 2099 if (ringBuffer && ringBuffer->isDVD()) 2099 if (ringBuffer && ringBuffer->IsDVD()) 2100 { 2100 2101 lang = ringBuffer->DVD()->GetAudioLanguage( 2101 2102 ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id)); 2102 else if (ringBuffer && ringBuffer->isBD()) 2103 } 2104 else if (ringBuffer && ringBuffer->IsBD()) 2105 { 2103 2106 lang = ringBuffer->BD()->GetAudioLanguage(audioStreamCount); 2107 } 2104 2108 else 2105 2109 { 2106 AVMetadataTag *metatag = av_metadata_get(ic->streams[i]->metadata, 2107 "language", NULL, 0); 2108 lang = metatag ? get_canonical_lang(metatag->value) : iso639_str3_to_key("und"); 2110 AVMetadataTag *metatag = av_metadata_get( 2111 ic->streams[i]->metadata, 2112 "language", NULL, 0); 2113 lang = metatag ? get_canonical_lang(metatag->value) : 2114 iso639_str3_to_key("und"); 2109 2115 } 2110 2116 2111 2117 int channels = ic->streams[i]->codec->channels; … … 2123 2129 else 2124 2130 { 2125 2131 int logical_stream_id; 2126 if (ringBuffer && ringBuffer->isDVD()) 2127 logical_stream_id = ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id); 2132 if (ringBuffer && ringBuffer->IsDVD()) 2133 logical_stream_id = 2134 ringBuffer->DVD()->GetAudioTrackNum(ic->streams[i]->id); 2128 2135 else 2129 2136 logical_stream_id = ic->streams[i]->id; 2130 2137 … … 2148 2155 ringBuffer->UpdateRawBitrate(bitrate); 2149 2156 } 2150 2157 2151 if (ringBuffer && ringBuffer-> isDVD())2158 if (ringBuffer && ringBuffer->IsDVD()) 2152 2159 { 2153 2160 if (tracks[kTrackTypeAudio].size() > 1) 2154 2161 { … … 2191 2198 m_parent->EnableSubtitles(false); 2192 2199 } 2193 2200 else if (trackNo >= 0 && trackNo < trackcount && 2194 !ringBuffer->I nDiscMenuOrStillFrame())2201 !ringBuffer->IsInDiscMenuOrStillFrame()) 2195 2202 { 2196 2203 SetTrack(kTrackTypeSubtitle, trackNo); 2197 2204 m_parent->EnableSubtitles(true); … … 2208 2215 { 2209 2216 m_audio->SetAudioParams(FORMAT_NONE, -1, -1, CODEC_ID_NONE, -1, false); 2210 2217 m_audio->ReinitAudio(); 2211 if (ringBuffer && ringBuffer-> isDVD())2218 if (ringBuffer && ringBuffer->IsDVD()) 2212 2219 audioIn = AudioInfo(); 2213 2220 } 2214 2221 … … 2754 2761 { 2755 2762 bufptr = ff_find_start_code(bufptr, bufend, &start_code_state); 2756 2763 2757 if (ringBuffer-> isDVD() && (start_code_state == SEQ_END_CODE))2764 if (ringBuffer->IsDVD() && (start_code_state == SEQ_END_CODE)) 2758 2765 ringBuffer->DVD()->NewSequence(true); 2759 2766 2760 2767 if (start_code_state >= SLICE_MIN && start_code_state <= SLICE_MAX) … … 2998 3005 context->reordered_opaque = pkt->pts; 2999 3006 ret = avcodec_decode_video2(context, &mpa_pic, &gotpicture, pkt); 3000 3007 // Reparse it to not drop the DVD still frame 3001 if (ringBuffer-> isDVD() && ringBuffer->DVD()->NeedsStillFrame())3008 if (ringBuffer->IsDVD() && ringBuffer->DVD()->NeedsStillFrame()) 3002 3009 ret = avcodec_decode_video2(context, &mpa_pic, &gotpicture, pkt); 3003 3010 } 3004 3011 avcodeclock->unlock(); … … 3033 3040 // the DTS timestamp is missing. Also use fixups for missing PTS instead of 3034 3041 // DTS to avoid oscillating between PTS and DTS. Only select DTS if PTS is 3035 3042 // more faulty or never detected. 3036 if (ringBuffer-> isDVD())3043 if (ringBuffer->IsDVD()) 3037 3044 { 3038 3045 if (pkt->dts != (int64_t)AV_NOPTS_VALUE) 3039 3046 pts = pkt->dts; … … 3135 3142 // Validate the video pts against the last pts. If it's 3136 3143 // a little bit smaller, equal or missing, compute 3137 3144 // it from the last. Otherwise assume a wraparound. 3138 if (!ringBuffer-> isDVD() &&3145 if (!ringBuffer->IsDVD() && 3139 3146 temppts <= lastvpts && 3140 3147 (temppts + 10000 > lastvpts || temppts <= 0)) 3141 3148 { … … 3349 3356 AVSubtitle subtitle; 3350 3357 memset(&subtitle, 0, sizeof(AVSubtitle)); 3351 3358 3352 if (ringBuffer-> isDVD())3359 if (ringBuffer->IsDVD()) 3353 3360 { 3354 3361 if (ringBuffer->DVD()->NumMenuButtons() > 0) 3355 3362 { … … 3460 3467 int lang_key = tracks[type][trackNo].language; 3461 3468 if (kTrackTypeAudio == type) 3462 3469 { 3463 if (ringBuffer-> isDVD())3470 if (ringBuffer->IsDVD()) 3464 3471 lang_key = ringBuffer->DVD()->GetAudioLanguage(trackNo); 3465 3472 3466 3473 QString msg = iso639_key_toName(lang_key); … … 3477 3484 msg += QString(" %1").arg(s->codec->codec->name).toUpper(); 3478 3485 3479 3486 int channels = 0; 3480 if (ringBuffer-> isDVD())3487 if (ringBuffer->IsDVD()) 3481 3488 channels = ringBuffer->DVD()->GetNumAudioChannels(trackNo); 3482 3489 else if (s->codec->channels) 3483 3490 channels = tracks[kTrackTypeAudio][trackNo].orig_num_channels; … … 3493 3500 } 3494 3501 else if (kTrackTypeSubtitle == type) 3495 3502 { 3496 if (ringBuffer-> isDVD())3503 if (ringBuffer->IsDVD()) 3497 3504 lang_key = ringBuffer->DVD()->GetSubtitleLanguage(trackNo); 3498 3505 3499 3506 return QObject::tr("Subtitle") + QString(" %1: %2") … … 3561 3568 if (kTrackTypeAudio == type) 3562 3569 return AutoSelectAudioTrack(); 3563 3570 3564 if (ringBuffer->I nDiscMenuOrStillFrame())3571 if (ringBuffer->IsInDiscMenuOrStillFrame()) 3565 3572 return -1; 3566 3573 3567 3574 return DecoderBase::AutoSelectTrack(type); … … 4016 4023 4017 4024 total_decoded_audio += data_size; 4018 4025 4019 allowedquit |= ringBuffer->I nDiscMenuOrStillFrame();4026 allowedquit |= ringBuffer->IsInDiscMenuOrStillFrame(); 4020 4027 // Audio can expand by a factor of 6 in audiooutputbase's audiobuffer 4021 4028 allowedquit |= !(decodetype & kDecodeVideo) && 4022 4029 ((ofill + total_decoded_audio * 6) > othresh); … … 4109 4116 allowedquit = true; 4110 4117 } 4111 4118 4112 if (ringBuffer-> isDVD())4119 if (ringBuffer->IsDVD()) 4113 4120 { 4114 4121 // Update the title length 4115 if (m_parent->AtNormalSpeed() && ringBuffer->DVD()->PGCLengthChanged()) 4122 if (m_parent->AtNormalSpeed() && 4123 ringBuffer->DVD()->PGCLengthChanged()) 4116 4124 { 4117 4125 ResetPosMap(); 4118 4126 SyncPositionMap(); … … 4139 4147 else if (lowbuffers && ((decodetype & kDecodeAV) == kDecodeAV) && 4140 4148 storedPackets.count() < max_video_queue_size && 4141 4149 lastapts < lastvpts + 100 && 4142 !ringBuffer->I nDiscMenuOrStillFrame())4150 !ringBuffer->IsInDiscMenuOrStillFrame()) 4143 4151 { 4144 4152 storevideoframes = true; 4145 4153 } … … 4208 4216 continue; 4209 4217 } 4210 4218 4211 if (ringBuffer-> isDVD() &&4219 if (ringBuffer->IsDVD() && 4212 4220 curstream->codec->codec_type == CODEC_TYPE_VIDEO) 4213 4221 { 4214 4222 #ifdef USING_XVMC … … 4224 4232 dvd_xvmc_active = true; 4225 4233 } 4226 4234 4227 bool indiscmenu = ringBuffer->I nDiscMenuOrStillFrame();4235 bool indiscmenu = ringBuffer->IsInDiscMenuOrStillFrame(); 4228 4236 if ((indiscmenu && dvd_xvmc_active) || 4229 4237 ((!indiscmenu && !dvd_xvmc_active))) 4230 4238 { … … 4237 4245 4238 4246 if ((video_width > 0) && dvd_video_codec_changed) 4239 4247 { 4240 VERBOSE(VB_PLAYBACK, LOC + QString("DVD Stream/Codec Change " 4241 "video_width %1 current_width %2 " 4242 "dvd_video_codec_changed %3") 4248 VERBOSE(VB_PLAYBACK, LOC + 4249 QString("DVD Stream/Codec Change " 4250 "video_width %1 current_width %2 " 4251 "dvd_video_codec_changed %3") 4243 4252 .arg(video_width).arg(current_width) 4244 4253 .arg(dvd_video_codec_changed)); 4245 4254 av_free_packet(pkt); -
libs/libmythtv/DVDRingBuffer.cpp
33 33 "Part", 34 34 }; 35 35 36 DVDRingBufferPriv::DVDRingBufferPriv() 37 : m_dvdnav(NULL), m_dvdBlockReadBuf(NULL), 38 m_dvdFilename(QString::null), 39 m_dvdBlockRPos(0), m_dvdBlockWPos(0), 40 m_pgLength(0), m_pgcLength(0), 41 m_cellStart(0), m_cellChanged(false), 42 m_pgcLengthChanged(false), m_pgStart(0), 43 m_currentpos(0), 44 m_lastNav(NULL), m_part(0), m_lastPart(0), 45 m_title(0), m_lastTitle(0), m_playerWait(false), 46 m_titleParts(0), m_gotStop(false), m_currentAngle(0), 47 m_currentTitleAngleCount(0), m_newSequence(false), 48 m_still(0), m_lastStill(0), 49 m_audioStreamsChanged(false), 50 m_dvdWaiting(false), 51 m_titleLength(0), 36 DVDRingBuffer::DVDRingBuffer(const QString &lfilename) : 37 m_dvdnav(NULL), m_dvdBlockReadBuf(NULL), 38 m_dvdBlockRPos(0), m_dvdBlockWPos(0), 39 m_pgLength(0), m_pgcLength(0), 40 m_cellStart(0), m_cellChanged(false), 41 m_pgcLengthChanged(false), m_pgStart(0), 42 m_currentpos(0), 43 m_lastNav(NULL), m_part(0), m_lastPart(0), 44 m_title(0), m_lastTitle(0), m_playerWait(false), 45 m_titleParts(0), m_gotStop(false), m_currentAngle(0), 46 m_currentTitleAngleCount(0), m_newSequence(false), 47 m_still(0), m_lastStill(0), 48 m_audioStreamsChanged(false), 49 m_dvdWaiting(false), 50 m_titleLength(0), 52 51 53 54 55 56 57 52 m_skipstillorwait(true), 53 m_cellstartPos(0), m_buttonSelected(false), 54 m_buttonExists(false), m_cellid(0), 55 m_lastcellid(0), m_vobid(0), 56 m_lastvobid(0), m_cellRepeated(false), 58 57 59 60 61 62 63 64 65 58 m_curAudioTrack(0), 59 m_curSubtitleTrack(0), 60 m_autoselectsubtitle(true), 61 m_dvdname(NULL), m_serialnumber(NULL), 62 m_seeking(false), m_seektime(0), 63 m_currentTime(0), 64 m_parent(NULL), 66 65 67 68 69 66 // Menu/buttons 67 m_inMenu(false), m_buttonVersion(1), m_buttonStreamID(0), 68 m_hl_button(0, 0, 0, 0), m_menuSpuPkt(0), m_menuBuflength(0) 70 69 { 71 70 memset(&m_dvdMenuButton, 0, sizeof(AVSubtitle)); 72 71 memset(m_dvdBlockWriteBuf, 0, sizeof(char) * DVD_BLOCK_SIZE); … … 78 77 79 78 for (uint i = 0; i < 8; i++) 80 79 m_seekSpeedMap.insert(def[i], seekValues[i]); 80 81 OpenFile(filename); 81 82 } 82 83 83 DVDRingBuffer Priv::~DVDRingBufferPriv()84 DVDRingBuffer::~DVDRingBuffer() 84 85 { 85 86 CloseDVD(); 86 87 ClearMenuSPUParameters(); 87 88 } 88 89 89 void DVDRingBuffer Priv::CloseDVD(void)90 void DVDRingBuffer::CloseDVD(void) 90 91 { 91 92 if (m_dvdnav) 92 93 { … … 96 97 } 97 98 } 98 99 99 long long DVDRingBuffer Priv::NormalSeek(long long time)100 long long DVDRingBuffer::Seek(long long pos, int whence, bool has_lock) 100 101 { 102 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)") 103 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET": 104 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END")) 105 .arg(has_lock?"locked":"unlocked")); 106 107 long long ret = -1; 108 109 // lockForWrite takes priority over lockForRead, so this will 110 // take priority over the lockForRead in the read ahead thread. 111 if (!has_lock) 112 rwlock.lockForWrite(); 113 114 poslock.lockForWrite(); 115 116 // Optimize no-op seeks 117 if (readaheadrunning && 118 ((whence == SEEK_SET && pos == readpos) || 119 (whence == SEEK_CUR && pos == 0))) 120 { 121 ret = readpos; 122 123 poslock.unlock(); 124 if (!has_lock) 125 rwlock.unlock(); 126 127 return ret; 128 } 129 130 // only valid for SEEK_SET & SEEK_CUR 131 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; 132 133 // Here we perform a normal seek. When successful we 134 // need to call ResetReadAhead(). A reset means we will 135 // need to refill the buffer, which takes some time. 136 if ((SEEK_END == whence) || 137 ((SEEK_CUR == whence) && new_pos != 0)) 138 { 139 errno = EINVAL; 140 ret = -1; 141 } 142 else 143 { 144 NormalSeek(new_pos); 145 ret = new_pos; 146 } 147 148 if (ret >= 0) 149 { 150 readpos = ret; 151 152 ignorereadpos = -1; 153 154 if (readaheadrunning) 155 ResetReadAhead(readpos); 156 157 readAdjust = 0; 158 } 159 else 160 { 161 QString cmd = QString("Seek(%1, %2)").arg(pos) 162 .arg((SEEK_SET == whence) ? "SEEK_SET" : 163 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 164 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 165 } 166 167 poslock.unlock(); 168 169 generalWait.wakeAll(); 170 171 if (!has_lock) 172 rwlock.unlock(); 173 174 return ret; 175 } 176 177 long long DVDRingBuffer::NormalSeek(long long time) 178 { 101 179 QMutexLocker lock(&m_seekLock); 102 180 return Seek(time); 103 181 } 104 182 105 long long DVDRingBuffer Priv::Seek(long long time)183 long long DVDRingBuffer::Seek(long long time) 106 184 { 107 185 dvdnav_status_t dvdRet = DVDNAV_STATUS_OK; 108 186 … … 148 226 return m_currentpos; 149 227 } 150 228 151 void DVDRingBuffer Priv::GetDescForPos(QString &desc)229 void DVDRingBuffer::GetDescForPos(QString &desc) 152 230 { 153 231 if (m_inMenu) 154 232 { … … 163 241 } 164 242 } 165 243 166 bool DVDRingBuffer Priv::OpenFile(const QString &filename)244 bool DVDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) 167 245 { 168 m_dvdFilename = filename; 169 m_dvdFilename.detach(); 170 QByteArray fname = m_dvdFilename.toLocal8Bit(); 246 rwlock.lockForWrite(); 171 247 248 if (m_dvdnav) 249 { 250 dvdnav_close(m_dvdnav); 251 m_dvdnav = NULL; 252 } 253 254 filename = lfilename; 255 QByteArray fname = filename.toLocal8Bit(); 256 172 257 dvdnav_status_t res = dvdnav_open(&m_dvdnav, fname.constData()); 173 258 if (res == DVDNAV_STATUS_ERR) 174 259 { 175 260 VERBOSE(VB_IMPORTANT, QString("Failed to open DVD device at %1") 176 261 .arg(fname.constData())); 262 rwlock.unlock(); 177 263 return false; 178 264 } 179 else180 {181 VERBOSE(VB_IMPORTANT, QString("Opened DVD device at %1")182 .arg(fname.constData()));183 dvdnav_set_readahead_flag(m_dvdnav, 0);184 dvdnav_set_PGC_positioning_flag(m_dvdnav, 1);185 265 186 int32_t num_titles = 0;187 int32_t num_parts = 0;266 VERBOSE(VB_IMPORTANT, QString("Opened DVD device at %1") 267 .arg(fname.constData())); 188 268 269 dvdnav_set_readahead_flag(m_dvdnav, 0); 270 dvdnav_set_PGC_positioning_flag(m_dvdnav, 1); 271 272 int32_t num_titles = 0; 273 int32_t num_parts = 0; 274 275 res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles); 276 if (num_titles == 0 || res == DVDNAV_STATUS_ERR) 277 { 278 char buf[DVD_BLOCK_SIZE * 5]; 279 VERBOSE(VB_IMPORTANT, QString("Reading %1 bytes from the drive") 280 .arg(DVD_BLOCK_SIZE * 5)); 281 safe_read(buf, DVD_BLOCK_SIZE * 5); 189 282 res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles); 190 if (num_titles == 0 || res == DVDNAV_STATUS_ERR) 191 { 192 char buf[DVD_BLOCK_SIZE * 5]; 193 VERBOSE(VB_IMPORTANT, QString("Reading %1 bytes from the drive") 194 .arg(DVD_BLOCK_SIZE * 5)); 195 safe_read(buf, DVD_BLOCK_SIZE * 5); 196 res = dvdnav_get_number_of_titles(m_dvdnav, &num_titles); 197 } 283 } 198 284 199 if (res == DVDNAV_STATUS_ERR) 285 if (res == DVDNAV_STATUS_ERR) 286 { 287 VERBOSE(VB_IMPORTANT, 288 QString("Failed to get the number of titles on the DVD" )); 289 } 290 else 291 { 292 VERBOSE(VB_IMPORTANT, QString("There are %1 titles on the disk") 293 .arg(num_titles)); 294 295 for (int i = 1; i < num_titles + 1; i++) 200 296 { 201 VERBOSE(VB_IMPORTANT, 202 QString("Failed to get the number of titles on the DVD" )); 203 } 204 else 205 { 206 VERBOSE(VB_IMPORTANT, QString("There are %1 titles on the disk") 207 .arg(num_titles)); 208 209 for(int i = 1; i < num_titles + 1; i++) 297 res = dvdnav_get_number_of_parts(m_dvdnav, i, &num_parts); 298 if (res != DVDNAV_STATUS_ERR) 210 299 { 211 res = dvdnav_get_number_of_parts(m_dvdnav, i, &num_parts); 212 if (res != DVDNAV_STATUS_ERR) 213 { 214 VERBOSE(VB_IMPORTANT, LOC + QString("Title %1 has %2 parts.") 300 VERBOSE(VB_IMPORTANT, LOC + QString("Title %1 has %2 parts.") 215 301 .arg(i).arg(num_parts)); 216 217 218 219 302 } 303 else 304 { 305 VERBOSE(VB_IMPORTANT, LOC_ERR + 220 306 QString("Failed to get number of parts for title %1") 221 307 .arg(i)); 222 }223 308 } 224 309 } 310 } 225 311 226 dvdnav_title_play(m_dvdnav, 1); 227 dvdnav_current_title_info(m_dvdnav, &m_title, &m_part); 228 dvdnav_get_title_string(m_dvdnav, &m_dvdname); 229 dvdnav_get_serial_string(m_dvdnav, &m_serialnumber); 230 dvdnav_get_angle_info(m_dvdnav, &m_currentAngle, &m_currentTitleAngleCount); 231 SetDVDSpeed(); 232 VERBOSE(VB_PLAYBACK, QString("DVD Serial Number %1").arg(m_serialnumber)); 233 return true; 234 } 312 dvdnav_title_play(m_dvdnav, 1); 313 dvdnav_current_title_info(m_dvdnav, &m_title, &m_part); 314 dvdnav_get_title_string(m_dvdnav, &m_dvdname); 315 dvdnav_get_serial_string(m_dvdnav, &m_serialnumber); 316 dvdnav_get_angle_info(m_dvdnav, &m_currentAngle, &m_currentTitleAngleCount); 317 SetDVDSpeed(); 318 319 VERBOSE(VB_PLAYBACK, QString("DVD Serial Number %1").arg(m_serialnumber)); 320 321 readblocksize = DVD_BLOCK_SIZE * 62; 322 setswitchtonext = false; 323 ateof = false; 324 commserror = false; 325 numfailures = 0; 326 rawbitrate = 8000; 327 328 CalcReadAheadThresh(); 329 330 rwlock.unlock(); 331 332 return true; 235 333 } 236 334 237 bool DVDRingBuffer Priv::StartFromBeginning(void)335 bool DVDRingBuffer::StartFromBeginning(void) 238 336 { 239 337 if (!m_dvdnav) 240 338 return false; … … 249 347 "DVD errored after initial scan - trying again"); 250 348 CloseDVD(); 251 349 m_gotStop = false; 252 OpenFile( m_dvdFilename);350 OpenFile(filename); 253 351 if (!m_dvdnav) 254 352 { 255 353 VERBOSE(VB_IMPORTANT, LOC + "Failed to re-open DVD."); … … 266 364 267 365 /** \brief returns current position in the PGC. 268 366 */ 269 long long DVDRingBuffer Priv::GetReadPosition(void)367 long long DVDRingBuffer::GetReadPosition(void) const 270 368 { 271 369 uint32_t pos = 0; 272 370 uint32_t length = 1; … … 281 379 return pos * DVD_BLOCK_SIZE; 282 380 } 283 381 284 void DVDRingBuffer Priv::WaitForPlayer(void)382 void DVDRingBuffer::WaitForPlayer(void) 285 383 { 286 384 if (!m_skipstillorwait) 287 385 { … … 299 397 } 300 398 } 301 399 302 int DVDRingBuffer Priv::safe_read(void *data, unsignedsz)400 int DVDRingBuffer::safe_read(void *data, uint sz) 303 401 { 304 402 dvdnav_status_t dvdStat; 305 403 unsigned char *blockBuf = NULL; … … 313 411 if (m_gotStop) 314 412 { 315 413 VERBOSE(VB_IMPORTANT, LOC + "safe_read: called after DVDNAV_STOP"); 414 errno = EBADF; 316 415 return -1; 317 416 } 318 417 … … 327 426 { 328 427 VERBOSE(VB_IMPORTANT, QString("Error reading block from DVD: %1") 329 428 .arg(dvdnav_err_to_string(m_dvdnav))); 429 errno = EIO; 330 430 return -1; 331 431 } 332 432 … … 386 486 387 487 // debug 388 488 VERBOSE(VB_PLAYBACK, LOC + 389 QString("---- DVDNAV_CELL_CHANGE - Cell #%1 Menu %2 Length %3") 489 QString("---- DVDNAV_CELL_CHANGE - Cell " 490 "#%1 Menu %2 Length %3") 390 491 .arg(cell_event->cellN).arg(m_inMenu ? "Yes" : "No") 391 492 .arg((float)cell_event->cell_length / 90000.0f, 0, 'f', 1)); 392 493 QString still = m_still ? ((m_still < 0xff) ? … … 401 502 } 402 503 else 403 504 { 404 VERBOSE(VB_PLAYBACK, LOC + QString("Title #%1: %2 Part %3 of %4") 505 VERBOSE(VB_PLAYBACK, LOC + 506 QString("Title #%1: %2 Part %3 of %4") 405 507 .arg(m_title).arg(still).arg(m_part).arg(m_titleParts)); 406 508 } 407 509 408 510 // wait unless it is a transition from one normal video cell to 409 511 // another or the same menu id 410 512 if (((m_still != m_lastStill) || (m_title != m_lastTitle)) && 411 !((m_title == 0 && m_lastTitle == 0) && (m_part == m_lastPart))) 513 !((m_title == 0 && m_lastTitle == 0) && 514 (m_part == m_lastPart))) 412 515 { 413 516 WaitForPlayer(); 414 517 } … … 492 595 QString(LOC + "DVDNAV_SPU_STREAM_CHANGE: " 493 596 "physicalwide %1, physicalletterbox %2, " 494 597 "physicalpanscan %3, currenttrack %4") 495 496 598 .arg(spu->physical_wide).arg(spu->physical_letterbox) 599 .arg(spu->physical_pan_scan).arg(m_curSubtitleTrack)); 497 600 498 601 // release buffer 499 602 if (blockBuf != m_dvdBlockWriteBuf) … … 557 660 if (m_seeking) 558 661 { 559 662 560 int relativetime = (int)((m_seektime - m_currentTime)/ 90000); 663 int relativetime = 664 (int)((m_seektime - m_currentTime)/ 90000); 561 665 if (relativetime <= 1) 562 666 { 563 667 m_seeking = false; … … 737 841 return tot; 738 842 } 739 843 740 bool DVDRingBuffer Priv::nextTrack(void)844 bool DVDRingBuffer::nextTrack(void) 741 845 { 742 846 int newPart = m_part + 1; 743 847 … … 751 855 return false; 752 856 } 753 857 754 void DVDRingBuffer Priv::prevTrack(void)858 void DVDRingBuffer::prevTrack(void) 755 859 { 756 860 int newPart = m_part - 1; 757 861 … … 766 870 /** \brief get the total time of the title in seconds 767 871 * 90000 ticks = 1 sec 768 872 */ 769 uint DVDRingBuffer Priv::GetTotalTimeOfTitle(void)873 uint DVDRingBuffer::GetTotalTimeOfTitle(void) 770 874 { 771 875 return m_pgcLength / 90000; 772 876 } 773 877 774 878 /** \brief get the start of the cell in seconds 775 879 */ 776 uint DVDRingBuffer Priv::GetCellStart(void)880 uint DVDRingBuffer::GetCellStart(void) 777 881 { 778 882 return m_cellStart / 90000; 779 883 } 780 884 781 885 /** \brief check if dvd cell has changed 782 886 */ 783 bool DVDRingBuffer Priv::CellChanged(void)887 bool DVDRingBuffer::CellChanged(void) 784 888 { 785 889 bool ret = m_cellChanged; 786 890 m_cellChanged = false; … … 789 893 790 894 /** \brief check if pgc length has changed 791 895 */ 792 bool DVDRingBuffer Priv::PGCLengthChanged(void)896 bool DVDRingBuffer::PGCLengthChanged(void) 793 897 { 794 898 bool ret = m_pgcLengthChanged; 795 899 m_pgcLengthChanged = false; 796 900 return ret; 797 901 } 798 902 799 void DVDRingBuffer Priv::SkipStillFrame(void)903 void DVDRingBuffer::SkipStillFrame(void) 800 904 { 801 905 QMutexLocker locker(&m_seekLock); 802 906 VERBOSE(VB_PLAYBACK, LOC + "Skipping still frame."); 803 907 dvdnav_still_skip(m_dvdnav); 804 908 } 805 909 806 void DVDRingBuffer Priv::WaitSkip(void)910 void DVDRingBuffer::WaitSkip(void) 807 911 { 808 912 QMutexLocker locker(&m_seekLock); 809 913 dvdnav_wait_skip(m_dvdnav); … … 813 917 814 918 /** \brief jump to a dvd root or chapter menu 815 919 */ 816 bool DVDRingBuffer Priv::GoToMenu(const QString str)920 bool DVDRingBuffer::GoToMenu(const QString str) 817 921 { 818 922 DVDMenuID_t menuid; 819 923 QMutexLocker locker(&m_seekLock); … … 839 943 return false; 840 944 } 841 945 842 void DVDRingBuffer Priv::GoToNextProgram(void)946 void DVDRingBuffer::GoToNextProgram(void) 843 947 { 844 948 QMutexLocker locker(&m_seekLock); 845 949 if (!dvdnav_is_domain_vts(m_dvdnav)) 846 950 dvdnav_next_pg_search(m_dvdnav); 847 951 } 848 952 849 void DVDRingBuffer Priv::GoToPreviousProgram(void)953 void DVDRingBuffer::GoToPreviousProgram(void) 850 954 { 851 955 QMutexLocker locker(&m_seekLock); 852 956 if (!dvdnav_is_domain_vts(m_dvdnav)) 853 957 dvdnav_prev_pg_search(m_dvdnav); 854 958 } 855 959 856 void DVDRingBuffer Priv::MoveButtonLeft(void)960 void DVDRingBuffer::MoveButtonLeft(void) 857 961 { 858 962 if (NumMenuButtons() > 1) 859 963 { … … 862 966 } 863 967 } 864 968 865 void DVDRingBuffer Priv::MoveButtonRight(void)969 void DVDRingBuffer::MoveButtonRight(void) 866 970 { 867 971 if (NumMenuButtons() > 1) 868 972 { … … 871 975 } 872 976 } 873 977 874 void DVDRingBuffer Priv::MoveButtonUp(void)978 void DVDRingBuffer::MoveButtonUp(void) 875 979 { 876 980 if (NumMenuButtons() > 1) 877 981 { … … 880 984 } 881 985 } 882 986 883 void DVDRingBuffer Priv::MoveButtonDown(void)987 void DVDRingBuffer::MoveButtonDown(void) 884 988 { 885 989 if (NumMenuButtons() > 1) 886 990 { … … 891 995 892 996 /** \brief action taken when a dvd menu button is selected 893 997 */ 894 void DVDRingBuffer Priv::ActivateButton(void)998 void DVDRingBuffer::ActivateButton(void) 895 999 { 896 1000 if (NumMenuButtons() > 0) 897 1001 { … … 903 1007 904 1008 /** \brief get SPU pkt from dvd menu subtitle stream 905 1009 */ 906 void DVDRingBuffer Priv::GetMenuSPUPkt(uint8_t *buf, int buf_size, int stream_id)1010 void DVDRingBuffer::GetMenuSPUPkt(uint8_t *buf, int buf_size, int stream_id) 907 1011 { 908 1012 if (buf_size < 4) 909 1013 return; … … 936 1040 /** \brief returns dvd menu button information if available. 937 1041 * used by NVP::DisplayDVDButton 938 1042 */ 939 AVSubtitle *DVDRingBuffer Priv::GetMenuSubtitle(uint &version)1043 AVSubtitle *DVDRingBuffer::GetMenuSubtitle(uint &version) 940 1044 { 941 1045 // this is unlocked by ReleaseMenuButton 942 1046 m_menuBtnLock.lock(); … … 953 1057 } 954 1058 955 1059 956 void DVDRingBuffer Priv::ReleaseMenuButton(void)1060 void DVDRingBuffer::ReleaseMenuButton(void) 957 1061 { 958 1062 m_menuBtnLock.unlock(); 959 1063 } 960 1064 961 1065 /** \brief get coordinates of highlighted button 962 1066 */ 963 QRect DVDRingBuffer Priv::GetButtonCoords(void)1067 QRect DVDRingBuffer::GetButtonCoords(void) 964 1068 { 965 1069 QRect rect(0,0,0,0); 966 1070 if (!m_buttonExists) … … 982 1086 /** \brief generate dvd subtitle bitmap or dvd menu bitmap. 983 1087 * code obtained from ffmpeg project 984 1088 */ 985 bool DVDRingBuffer Priv::DecodeSubtitles(AVSubtitle *sub, int *gotSubtitles,1089 bool DVDRingBuffer::DecodeSubtitles(AVSubtitle *sub, int *gotSubtitles, 986 1090 const uint8_t *spu_pkt, int buf_size) 987 1091 { 988 1092 #define GETBE16(p) (((p)[0] << 8) | (p)[1]) … … 1152 1256 /** \brief update the dvd menu button parameters 1153 1257 * when a user changes the dvd menu button position 1154 1258 */ 1155 bool DVDRingBuffer Priv::DVDButtonUpdate(bool b_mode)1259 bool DVDRingBuffer::DVDButtonUpdate(bool b_mode) 1156 1260 { 1157 1261 if (!m_parent) 1158 1262 return false; … … 1189 1293 1190 1294 /** \brief clears the dvd menu button structures 1191 1295 */ 1192 void DVDRingBuffer Priv::ClearMenuButton(void)1296 void DVDRingBuffer::ClearMenuButton(void) 1193 1297 { 1194 1298 if (m_buttonExists || m_dvdMenuButton.rects) 1195 1299 { … … 1210 1314 /** \brief clears the menu SPU pkt and parameters. 1211 1315 * necessary action during dvd menu changes 1212 1316 */ 1213 void DVDRingBuffer Priv::ClearMenuSPUParameters(void)1317 void DVDRingBuffer::ClearMenuSPUParameters(void) 1214 1318 { 1215 1319 if (m_menuBuflength == 0) 1216 1320 return; … … 1224 1328 m_hl_button.setRect(0, 0, 0, 0); 1225 1329 } 1226 1330 1227 int DVDRingBuffer Priv::NumMenuButtons(void) const1331 int DVDRingBuffer::NumMenuButtons(void) const 1228 1332 { 1229 1333 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav); 1230 1334 int numButtons = pci->hli.hl_gi.btn_ns; … … 1236 1340 1237 1341 /** \brief get the audio language from the dvd 1238 1342 */ 1239 uint DVDRingBuffer Priv::GetAudioLanguage(int id)1343 uint DVDRingBuffer::GetAudioLanguage(int id) 1240 1344 { 1241 1345 uint16_t lang = dvdnav_audio_stream_to_lang(m_dvdnav, id); 1242 1346 VERBOSE(VB_PLAYBACK, LOC + QString("StreamID: %1; lang: %2").arg(id).arg(lang)); … … 1246 1350 /** \brief get real dvd track audio number 1247 1351 * \param key stream_id 1248 1352 */ 1249 int DVDRingBuffer Priv::GetAudioTrackNum(uint stream_id)1353 int DVDRingBuffer::GetAudioTrackNum(uint stream_id) 1250 1354 { 1251 1355 return dvdnav_get_audio_logical_stream(m_dvdnav, stream_id); 1252 1356 } 1253 1357 1254 1358 /** \brief get the subtitle language from the dvd 1255 1359 */ 1256 uint DVDRingBuffer Priv::GetSubtitleLanguage(int id)1360 uint DVDRingBuffer::GetSubtitleLanguage(int id) 1257 1361 { 1258 1362 uint16_t lang = dvdnav_spu_stream_to_lang(m_dvdnav, id); 1259 1363 VERBOSE(VB_PLAYBACK, LOC + QString("StreamID: %1; lang: %2").arg(id).arg(lang)); … … 1262 1366 1263 1367 /** \brief converts the subtitle/audio lang code to iso639. 1264 1368 */ 1265 uint DVDRingBuffer Priv::ConvertLangCode(uint16_t code)1369 uint DVDRingBuffer::ConvertLangCode(uint16_t code) 1266 1370 { 1267 1371 if (code == 0) 1268 1372 return 0; … … 1282 1386 /** \brief determines the default dvd menu button to 1283 1387 * show when you initially access the dvd menu. 1284 1388 */ 1285 void DVDRingBuffer Priv::SelectDefaultButton(void)1389 void DVDRingBuffer::SelectDefaultButton(void) 1286 1390 { 1287 1391 pci_t *pci = dvdnav_get_current_nav_pci(m_dvdnav); 1288 1392 int32_t button = pci->hli.hl_gi.fosl_btnn; … … 1302 1406 * \param type currently kTrackTypeSubtitle or kTrackTypeAudio 1303 1407 * \param trackNo if -1 then autoselect the track num from the dvd IFO 1304 1408 */ 1305 void DVDRingBuffer Priv::SetTrack(uint type, int trackNo)1409 void DVDRingBuffer::SetTrack(uint type, int trackNo) 1306 1410 { 1307 1411 if (type == kTrackTypeSubtitle) 1308 1412 { … … 1320 1424 } 1321 1425 1322 1426 /** \brief get the track the dvd should be playing. 1323 * can either be set by the user using DVDRingBuffer Priv::SetTrack1427 * can either be set by the user using DVDRingBuffer::SetTrack 1324 1428 * or determined from the dvd IFO. 1325 1429 * \param type: use either kTrackTypeSubtitle or kTrackTypeAudio 1326 1430 */ 1327 int DVDRingBuffer Priv::GetTrack(uint type)1431 int DVDRingBuffer::GetTrack(uint type) 1328 1432 { 1329 1433 if (type == kTrackTypeSubtitle) 1330 1434 return m_curSubtitleTrack; … … 1334 1438 return 0; 1335 1439 } 1336 1440 1337 uint8_t DVDRingBuffer Priv::GetNumAudioChannels(int id)1441 uint8_t DVDRingBuffer::GetNumAudioChannels(int id) 1338 1442 { 1339 1443 unsigned char channels = dvdnav_audio_stream_channels(m_dvdnav, id); 1340 1444 if (channels == 0xff) … … 1344 1448 1345 1449 /** \brief Get the dvd title and serial num 1346 1450 */ 1347 bool DVDRingBuffer Priv::GetNameAndSerialNum(QString& _name, QString& _serial)1451 bool DVDRingBuffer::GetNameAndSerialNum(QString& _name, QString& _serial) 1348 1452 { 1349 1453 _name = QString(m_dvdname); 1350 1454 _serial = QString(m_serialnumber); … … 1358 1462 * FPS for a dvd is determined by AFD::normalized_fps 1359 1463 * * dvdnav_get_video_format: 0 - NTSC, 1 - PAL 1360 1464 */ 1361 double DVDRingBuffer Priv::GetFrameRate(void)1465 double DVDRingBuffer::GetFrameRate(void) 1362 1466 { 1363 1467 double dvdfps = 0; 1364 1468 int format = dvdnav_get_video_format(m_dvdnav); … … 1371 1475 /** \brief set dvd speed. uses the DVDDriveSpeed Setting from the settings 1372 1476 * table 1373 1477 */ 1374 void DVDRingBuffer Priv::SetDVDSpeed(void)1478 void DVDRingBuffer::SetDVDSpeed(void) 1375 1479 { 1376 1480 QMutexLocker lock(&m_seekLock); 1377 1481 int dvdDriveSpeed = gCoreContext->GetNumSetting("DVDDriveSpeed", 12); … … 1380 1484 1381 1485 /** \brief set dvd speed. 1382 1486 */ 1383 void DVDRingBuffer Priv::SetDVDSpeed(int speed)1487 void DVDRingBuffer::SetDVDSpeed(int speed) 1384 1488 { 1385 if ( m_dvdFilename.startsWith("/"))1386 MediaMonitor::SetCDSpeed( m_dvdFilename.toLocal8Bit().constData(), speed);1489 if (filename.startsWith("/")) 1490 MediaMonitor::SetCDSpeed(filename.toLocal8Bit().constData(), speed); 1387 1491 } 1388 1492 1389 1493 /**\brief returns seconds left in the title 1390 1494 */ 1391 uint DVDRingBuffer Priv::TitleTimeLeft(void)1495 uint DVDRingBuffer::TitleTimeLeft(void) 1392 1496 { 1393 1497 return (GetTotalTimeOfTitle() - GetCurrentTime()); 1394 1498 } 1395 1499 1396 1500 /** \brief converts palette values from YUV to RGB 1397 1501 */ 1398 void DVDRingBuffer Priv::guess_palette(uint32_t *rgba_palette,uint8_t *palette,1502 void DVDRingBuffer::guess_palette(uint32_t *rgba_palette,uint8_t *palette, 1399 1503 uint8_t *alpha) 1400 1504 { 1401 1505 int i,r,g,b,y,cr,cb; … … 1425 1529 /** \brief decodes the bitmap from the subtitle packet. 1426 1530 * copied from ffmpeg's dvdsubdec.c. 1427 1531 */ 1428 int DVDRingBuffer Priv::decode_rle(uint8_t *bitmap, int linesize, int w, int h,1532 int DVDRingBuffer::decode_rle(uint8_t *bitmap, int linesize, int w, int h, 1429 1533 const uint8_t *buf, int nibble_offset, int buf_size) 1430 1534 { 1431 1535 unsigned int v; … … 1472 1576 1473 1577 /** copied from ffmpeg's dvdsubdec.c 1474 1578 */ 1475 int DVDRingBuffer Priv::get_nibble(const uint8_t *buf, int nibble_offset)1579 int DVDRingBuffer::get_nibble(const uint8_t *buf, int nibble_offset) 1476 1580 { 1477 1581 return (buf[nibble_offset >> 1] >> ((1 - (nibble_offset & 1)) << 2)) & 0xf; 1478 1582 } … … 1481 1585 * \brief obtained from ffmpeg dvdsubdec.c 1482 1586 * used to find smallest bounded rectangle 1483 1587 */ 1484 int DVDRingBuffer Priv::is_transp(const uint8_t *buf, int pitch, int n,1588 int DVDRingBuffer::is_transp(const uint8_t *buf, int pitch, int n, 1485 1589 const uint8_t *transp_color) 1486 1590 { 1487 1591 int i; … … 1499 1603 * used to find smallest bounded rect. 1500 1604 * helps prevent jerky picture during subtitle creation 1501 1605 */ 1502 int DVDRingBuffer Priv::find_smallest_bounding_rectangle(AVSubtitle *s)1606 int DVDRingBuffer::find_smallest_bounding_rectangle(AVSubtitle *s) 1503 1607 { 1504 1608 uint8_t transp_color[256]; 1505 1609 int y1, y2, x1, x2, y, w, h, i; … … 1579 1683 return 1; 1580 1684 } 1581 1685 1582 bool DVDRingBuffer Priv::SwitchAngle(uint angle)1686 bool DVDRingBuffer::SwitchAngle(uint angle) 1583 1687 { 1584 1688 if (!m_dvdnav) 1585 1689 return false; … … 1595 1699 return false; 1596 1700 } 1597 1701 1598 bool DVDRingBuffer Priv::NewSequence(bool new_sequence)1702 bool DVDRingBuffer::NewSequence(bool new_sequence) 1599 1703 { 1600 1704 bool result = false; 1601 1705 if (new_sequence) -
libs/libmythtv/libmythtv.pro
141 141 142 142 # Misc. needed by backend/frontend 143 143 HEADERS += recordinginfo.h 144 HEADERS += RingBuffer.h avfringbuffer.h145 HEADERS += ThreadedFileWriter.h146 144 HEADERS += dbcheck.h 147 145 HEADERS += tvremoteutil.h tv.h 148 146 HEADERS += jobqueue.h … … 163 161 HEADERS += channelgroup.h channelgroupsettings.h 164 162 HEADERS += recordingrule.h programdetail.h 165 163 HEADERS += mythsystemevent.h 164 HEADERS += avfringbuffer.h ThreadedFileWriter.h 165 HEADERS += RingBuffer.h FileRingBuffer.h 166 HEADERS += DVDRingBuffer.h BDRingBuffer.h 166 167 167 168 SOURCES += recordinginfo.cpp 168 SOURCES += RingBuffer.cpp avfringbuffer.cpp169 SOURCES += ThreadedFileWriter.cpp170 169 SOURCES += dbcheck.cpp 171 170 SOURCES += tvremoteutil.cpp tv.cpp 172 171 SOURCES += jobqueue.cpp … … 187 186 SOURCES += myth_imgconvert.cpp 188 187 SOURCES += recordingrule.cpp programdetail.cpp 189 188 SOURCES += mythsystemevent.cpp 189 SOURCES += avfringbuffer.cpp ThreadedFileWriter.cpp 190 SOURCES += RingBuffer.cpp FileRingBuffer.cpp 191 SOURCES += DVDRingBuffer.cpp BDRingBuffer.cpp 190 192 191 193 # DiSEqC 192 194 HEADERS += diseqc.h diseqcsettings.h … … 251 253 # Video playback 252 254 HEADERS += tv_play.h mythplayer.h 253 255 HEADERS += mythdvdplayer.h audioplayer.h 254 HEADERS += DVDRingBuffer.hplayercontext.h256 HEADERS += playercontext.h 255 257 HEADERS += tv_play_win.h deletemap.h 256 258 HEADERS += mythcommflagplayer.h commbreakmap.h 257 HEADERS += BDRingBuffer.hmythbdplayer.h259 HEADERS += mythbdplayer.h 258 260 HEADERS += mythiowrapper.h tvbrowsehelper.h 259 261 SOURCES += tv_play.cpp mythplayer.cpp 260 262 SOURCES += mythdvdplayer.cpp audioplayer.cpp 261 SOURCES += DVDRingBuffer.cppplayercontext.cpp263 SOURCES += playercontext.cpp 262 264 SOURCES += tv_play_win.cpp deletemap.cpp 263 265 SOURCES += mythcommflagplayer.cpp commbreakmap.cpp 264 SOURCES += BDRingBuffer.cppmythbdplayer.cpp266 SOURCES += mythbdplayer.cpp 265 267 SOURCES += mythiowrapper.cpp tvbrowsehelper.cpp 266 268 267 269 # Text subtitle parser -
libs/libmythtv/tv_play.h
617 617 // DVD methods 618 618 void DVDJumpBack(PlayerContext*); 619 619 void DVDJumpForward(PlayerContext*); 620 bool DiscMenuHandleAction(PlayerContext*, 621 const QStringList &actions, 622 bool isDVD, bool isDVDStill, 623 bool isBD = false); 620 bool DiscMenuHandleAction(PlayerContext*, const QStringList &actions); 624 621 625 622 // Program jumping stuff 626 623 void SetLastProgram(const ProgramInfo *rcinfo); -
libs/libmythtv/BDRingBuffer.cpp
15 15 #include "mythdirs.h" 16 16 #include "bluray.h" 17 17 18 #define LOC QString("BDRingBuffer: ") 18 #define LOC QString("BDRingBuf(%1): ").arg(GetFilename()) 19 #define LOC_WARN QString("BDRingBuf(%1) Warning: ").arg(GetFilename()) 20 #define LOC_ERR QString("BDRingBuf(%1) Error: ").arg(GetFilename()) 19 21 20 static void HandleOverlayCallback(void *data, const bd_overlay_s * const overlay) 22 static void HandleOverlayCallback( 23 void *data, const bd_overlay_s * const overlay) 21 24 { 22 BDRingBuffer Priv *bdpriv = (BDRingBufferPriv*) data;25 BDRingBuffer *bdrb = (BDRingBuffer*) data; 23 26 24 if (!bd priv)27 if (!bdrb) 25 28 return; 26 29 27 30 if (!overlay || overlay->plane == 1) 28 bd priv->m_inMenu = false;31 bdrb->m_inMenu = false; 29 32 30 33 if (!overlay || !overlay->img) 31 34 return; 32 35 33 bd priv->m_inMenu = true;36 bdrb->m_inMenu = true; 34 37 35 38 const BD_PG_RLE_ELEM *rlep = overlay->img; 36 39 uint8_t *yuvimg = (uint8_t*)malloc(overlay->w * overlay->h); 37 40 unsigned pixels = overlay->w * overlay->h; 38 41 42 39 43 for (unsigned i = 0; i < pixels; i += rlep->len, rlep++) 40 44 { 41 45 memset(yuvimg + i, rlep->color, rlep->len); … … 49 53 palette.push_back(origpalette[i]); 50 54 51 55 qoverlay.setColorTable(palette); 52 qoverlay.save(QString("bluray.menuimg.%1.%2.png").arg(overlay->w).arg(overlay->h)); 56 qoverlay.save(QString("bluray.menuimg.%1.%2.png") 57 .arg(overlay->w).arg(overlay->h)); 53 58 54 VERBOSE(VB_PLAYBACK|VB_EXTRA, LOC + QString("In Menu Callback, ready to draw " 55 "an overlay of %1x%2 at %3,%4 (%5 pixels).") 56 .arg(overlay->w).arg(overlay->h).arg(overlay->x) 57 .arg(overlay->y).arg(pixels)); 59 VERBOSE(VB_PLAYBACK|VB_EXTRA, 60 QString("BDRingBuf(%1): ").arg(bdrb->GetFilename()) + 61 QString("In Menu Callback, ready to draw " 62 "an overlay of %1x%2 at %3,%4 (%5 pixels).") 63 .arg(overlay->w).arg(overlay->h).arg(overlay->x) 64 .arg(overlay->y).arg(pixels)); 58 65 } 59 66 60 BDRingBufferPriv::BDRingBufferPriv() 61 : bdnav(NULL), 62 m_is_hdmv_navigation(false), 63 m_numTitles(0) 67 BDRingBuffer::BDRingBuffer(const QString &lfilename) : 68 bdnav(NULL), 69 m_is_hdmv_navigation(false), m_numTitles(0) 64 70 { 71 OpenFile(lfilename); 65 72 } 66 73 67 BDRingBuffer Priv::~BDRingBufferPriv()74 BDRingBuffer::~BDRingBuffer() 68 75 { 69 76 close(); 70 77 } 71 78 72 void BDRingBuffer Priv::close(void)79 void BDRingBuffer::close(void) 73 80 { 74 81 if (bdnav) 75 82 { … … 80 87 } 81 88 } 82 89 83 uint64_t BDRingBufferPriv::Seek(uint64_t pos)90 long long BDRingBuffer::Seek(long long pos, int whence, bool has_lock) 84 91 { 92 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)") 93 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET": 94 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END")) 95 .arg(has_lock?"locked":"unlocked")); 96 97 long long ret = -1; 98 99 // lockForWrite takes priority over lockForRead, so this will 100 // take priority over the lockForRead in the read ahead thread. 101 if (!has_lock) 102 rwlock.lockForWrite(); 103 104 poslock.lockForWrite(); 105 106 // Optimize no-op seeks 107 if (readaheadrunning && 108 ((whence == SEEK_SET && pos == readpos) || 109 (whence == SEEK_CUR && pos == 0))) 110 { 111 ret = readpos; 112 113 poslock.unlock(); 114 if (!has_lock) 115 rwlock.unlock(); 116 117 return ret; 118 } 119 120 // only valid for SEEK_SET & SEEK_CUR 121 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; 122 123 // Here we perform a normal seek. When successful we 124 // need to call ResetReadAhead(). A reset means we will 125 // need to refill the buffer, which takes some time. 126 if ((SEEK_END == whence) || 127 ((SEEK_CUR == whence) && new_pos != 0)) 128 { 129 errno = EINVAL; 130 ret = -1; 131 } 132 else 133 { 134 Seek(new_pos); 135 ret = new_pos; 136 } 137 138 if (ret >= 0) 139 { 140 readpos = ret; 141 142 ignorereadpos = -1; 143 144 if (readaheadrunning) 145 ResetReadAhead(readpos); 146 147 readAdjust = 0; 148 } 149 else 150 { 151 QString cmd = QString("Seek(%1, %2)").arg(pos) 152 .arg((SEEK_SET == whence) ? "SEEK_SET" : 153 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 154 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 155 } 156 157 poslock.unlock(); 158 159 generalWait.wakeAll(); 160 161 if (!has_lock) 162 rwlock.unlock(); 163 164 return ret; 165 } 166 167 uint64_t BDRingBuffer::Seek(uint64_t pos) 168 { 85 169 VERBOSE(VB_PLAYBACK|VB_EXTRA, LOC + QString("Seeking to %1.") 86 170 .arg(pos)); 87 171 if (!m_is_hdmv_navigation) … … 90 174 return GetReadPosition(); 91 175 } 92 176 93 void BDRingBuffer Priv::GetDescForPos(QString &desc) const177 void BDRingBuffer::GetDescForPos(QString &desc) const 94 178 { 95 179 desc = QObject::tr("Title %1 chapter %2") 96 180 .arg(m_currentTitleInfo->idx) 97 181 .arg(m_currentTitleInfo->chapters->idx); 98 182 } 99 183 100 bool BDRingBuffer Priv::OpenFile(const QString &filename)184 bool BDRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) 101 185 { 102 186 VERBOSE(VB_IMPORTANT, LOC + QString("Opened BDRingBuffer device at %1") 103 .arg( filename.toLatin1().data()));187 .arg(lfilename.toLatin1().data())); 104 188 189 rwlock.lockForWrite(); 190 191 if (bdnav) 192 { 193 if (m_currentTitleInfo) 194 bd_free_title_info(m_currentTitleInfo); 195 bd_close(bdnav); 196 bdnav = NULL; 197 } 198 199 filename = lfilename; 200 105 201 QString keyfile = QString("%1/KEYDB.cfg").arg(GetConfDir()); 106 202 QByteArray keyarray = keyfile.toAscii(); 107 203 const char *keyfilepath = keyarray.data(); 108 204 109 bdnav = bd_open( filename.toLatin1().data(), keyfilepath);205 bdnav = bd_open(lfilename.toLatin1().data(), keyfilepath); 110 206 111 207 if (!bdnav) 208 { 209 rwlock.unlock(); 112 210 return false; 211 } 113 212 114 213 // Check disc to see encryption status, menu and navigation types. 115 214 const BLURAY_DISC_INFO *discinfo = bd_get_disc_info(bdnav); 116 215 if (discinfo) 117 VERBOSE(VB_PLAYBACK, QString("*** Blu-ray Disc Information ***\n" 118 "First Play Supported: %1\n" 119 "Top Menu Supported: %2\n" 120 "Number of HDMV Titles: %3\n" 121 "Number of BD-J Titles: %4\n" 122 "Number of Unsupported Titles: %5\n" 123 "AACS present on disc: %6\n" 124 "libaacs used: %7\n" 125 "AACS handled: %8\n" 126 "BD+ present on disc: %9\n" 127 "libbdplus used: %10\n" 128 "BD+ handled: %11") 129 .arg(discinfo->first_play_supported ? "yes" : "no") 130 .arg(discinfo->top_menu_supported ? "yes" : "no") 131 .arg(discinfo->num_hdmv_titles) 132 .arg(discinfo->num_bdj_titles) 133 .arg(discinfo->num_unsupported_titles) 134 .arg(discinfo->aacs_detected ? "yes" : "no") 135 .arg(discinfo->libaacs_detected ? "yes" : "no") 136 .arg(discinfo->aacs_handled ? "yes" : "no") 137 .arg(discinfo->bdplus_detected ? "yes" : "no") 138 .arg(discinfo->libbdplus_detected ? "yes" : "no") 139 .arg(discinfo->bdplus_handled ? "yes" : "no")); 216 { 217 VERBOSE(VB_PLAYBACK, QString( 218 "*** Blu-ray Disc Information ***\n" 219 "First Play Supported: %1\n" 220 "Top Menu Supported: %2\n" 221 "Number of HDMV Titles: %3\n" 222 "Number of BD-J Titles: %4\n" 223 "Number of Unsupported Titles: %5\n" 224 "AACS present on disc: %6\n" 225 "libaacs used: %7\n" 226 "AACS handled: %8\n" 227 "BD+ present on disc: %9\n" 228 "libbdplus used: %10\n" 229 "BD+ handled: %11") 230 .arg(discinfo->first_play_supported ? "yes" : "no") 231 .arg(discinfo->top_menu_supported ? "yes" : "no") 232 .arg(discinfo->num_hdmv_titles) 233 .arg(discinfo->num_bdj_titles) 234 .arg(discinfo->num_unsupported_titles) 235 .arg(discinfo->aacs_detected ? "yes" : "no") 236 .arg(discinfo->libaacs_detected ? "yes" : "no") 237 .arg(discinfo->aacs_handled ? "yes" : "no") 238 .arg(discinfo->bdplus_detected ? "yes" : "no") 239 .arg(discinfo->libbdplus_detected ? "yes" : "no") 240 .arg(discinfo->bdplus_handled ? "yes" : "no")); 241 } 140 242 141 // The following settings affect HDMV navigation (default audio track selection, 243 // The following settings affect HDMV navigation 244 // (default audio track selection, 142 245 // parental controls, menu language, etc. They are not yet used. 143 246 144 247 // Set parental level "age" to 99 for now. TODO: Add support for FE level 145 248 bd_set_player_setting(bdnav, BLURAY_PLAYER_SETTING_PARENTAL, 99); 146 249 147 250 // Set preferred language to FE guide language 148 const char *langpref = gCoreContext->GetSetting("ISO639Language0", "eng").toLatin1().data(); 251 const char *langpref = gCoreContext->GetSetting( 252 "ISO639Language0", "eng").toLatin1().data(); 149 253 QString QScountry = gCoreContext->GetLocale()->GetCountryCode().toLower(); 150 254 const char *country = QScountry.toLatin1().data(); 151 bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_AUDIO_LANG, langpref); 255 bd_set_player_setting_str( 256 bdnav, BLURAY_PLAYER_SETTING_AUDIO_LANG, langpref); 152 257 153 258 // Set preferred presentation graphics language to the FE guide language 154 259 bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_PG_LANG, langpref); … … 157 262 bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_MENU_LANG, langpref); 158 263 159 264 // Set player country code via MythLocale. (not a region setting) 160 bd_set_player_setting_str(bdnav, BLURAY_PLAYER_SETTING_COUNTRY_CODE, country); 265 bd_set_player_setting_str( 266 bdnav, BLURAY_PLAYER_SETTING_COUNTRY_CODE, country); 161 267 162 268 VERBOSE(VB_IMPORTANT, LOC + QString("Using %1 as keyfile...") 163 269 .arg(QString(keyfilepath))); … … 227 333 } 228 334 #endif 229 335 336 readblocksize = BD_BLOCK_SIZE * 62; 337 setswitchtonext = false; 338 ateof = false; 339 commserror = false; 340 numfailures = 0; 341 rawbitrate = 8000; 342 CalcReadAheadThresh(); 343 344 rwlock.unlock(); 345 230 346 return true; 231 347 } 232 348 233 uint64_t BDRingBufferPriv::GetReadPosition(void) 349 long long BDRingBuffer::GetReadPosition(void) const 234 350 { 235 351 if (bdnav) 236 352 return bd_tell(bdnav); 237 353 return 0; 238 354 } 239 355 240 uint32_t BDRingBuffer Priv::GetNumChapters(void)356 uint32_t BDRingBuffer::GetNumChapters(void) 241 357 { 242 358 if (m_currentTitleInfo) 243 359 return m_currentTitleInfo->chapter_count; 244 360 return 0; 245 361 } 246 362 247 uint64_t BDRingBuffer Priv::GetChapterStartTime(uint32_t chapter)363 uint64_t BDRingBuffer::GetChapterStartTime(uint32_t chapter) 248 364 { 249 365 if (chapter < 0 || chapter >= GetNumChapters()) 250 366 return 0; … … 252 368 90000.0f); 253 369 } 254 370 255 uint64_t BDRingBuffer Priv::GetChapterStartFrame(uint32_t chapter)371 uint64_t BDRingBuffer::GetChapterStartFrame(uint32_t chapter) 256 372 { 257 373 if (chapter < 0 || chapter >= GetNumChapters()) 258 374 return 0; … … 260 376 GetFrameRate()) / 90000.0f); 261 377 } 262 378 263 int BDRingBuffer Priv::GetCurrentTitle(void) const379 int BDRingBuffer::GetCurrentTitle(void) const 264 380 { 265 381 if (m_currentTitleInfo) 266 382 return m_currentTitleInfo->idx; 267 383 return -1; 268 384 } 269 385 270 int BDRingBuffer Priv::GetTitleDuration(int title) const386 int BDRingBuffer::GetTitleDuration(int title) const 271 387 { 272 388 int numTitles = GetNumTitles(); 273 389 … … 283 399 return duration; 284 400 } 285 401 286 bool BDRingBuffer Priv::SwitchTitle(uint title)402 bool BDRingBuffer::SwitchTitle(uint title) 287 403 { 288 404 if (!bdnav) 289 405 return false; … … 333 449 return true; 334 450 } 335 451 336 bool BDRingBuffer Priv::SwitchAngle(uint angle)452 bool BDRingBuffer::SwitchAngle(uint angle) 337 453 { 338 454 if (!bdnav) 339 455 return false; … … 344 460 return true; 345 461 } 346 462 347 uint64_t BDRingBuffer Priv::GetTotalReadPosition(void)463 uint64_t BDRingBuffer::GetTotalReadPosition(void) 348 464 { 349 465 if (bdnav) 350 466 return bd_get_title_size(bdnav); 351 467 return 0; 352 468 } 353 469 354 int BDRingBuffer Priv::safe_read(void *data, unsignedsz)470 int BDRingBuffer::safe_read(void *data, uint sz) 355 471 { 356 472 if (m_is_hdmv_navigation) 357 473 { … … 368 484 return sz; 369 485 } 370 486 371 double BDRingBuffer Priv::GetFrameRate(void)487 double BDRingBuffer::GetFrameRate(void) 372 488 { 373 489 if (bdnav && m_currentTitleInfo) 374 490 { … … 401 517 return 0; 402 518 } 403 519 404 int BDRingBuffer Priv::GetAudioLanguage(uint streamID)520 int BDRingBuffer::GetAudioLanguage(uint streamID) 405 521 { 406 522 if (!m_currentTitleInfo || 407 523 streamID >= m_currentTitleInfo->clips->audio_stream_count) … … 416 532 return code; 417 533 } 418 534 419 int BDRingBuffer Priv::GetSubtitleLanguage(uint streamID)535 int BDRingBuffer::GetSubtitleLanguage(uint streamID) 420 536 { 421 537 if (!m_currentTitleInfo) 422 538 return iso639_str3_to_key("und"); … … 442 558 return iso639_str3_to_key("und"); 443 559 } 444 560 445 void BDRingBuffer Priv::PressButton(int32_t key, int64_t pts)561 void BDRingBuffer::PressButton(int32_t key, int64_t pts) 446 562 { 447 563 if (!bdnav) 448 564 return; … … 463 579 464 580 /** \brief jump to a Blu-ray root or popup menu 465 581 */ 466 bool BDRingBuffer Priv::GoToMenu(const QString str)582 bool BDRingBuffer::GoToMenu(const QString str) 467 583 { 468 584 if (!m_is_hdmv_navigation) 469 585 return false; … … 489 605 return false; 490 606 } 491 607 492 bool BDRingBuffer Priv::HandleBDEvents()608 bool BDRingBuffer::HandleBDEvents(void) 493 609 { 494 610 BD_EVENT ev; 495 611 while (bd_get_event(bdnav, &ev)) … … 504 620 return true; 505 621 } 506 622 507 void BDRingBuffer Priv::HandleBDEvent(BD_EVENT &ev)623 void BDRingBuffer::HandleBDEvent(BD_EVENT &ev) 508 624 { 509 625 switch (ev.event) { 510 626 case BD_EVENT_NONE: -
libs/libmythtv/FileRingBuffer.cpp
1 #include <cstdlib> 2 #include <cerrno> 3 4 // POSIX C headers 5 #include <sys/types.h> 6 #include <sys/time.h> 7 #include <unistd.h> 8 #include <fcntl.h> 9 10 #include <QFileInfo> 11 #include <QDir> 12 13 #include "ThreadedFileWriter.h" 14 #include "FileRingBuffer.h" 15 #include "mythcontext.h" 16 #include "remotefile.h" 17 #include "util.h" 18 19 #ifndef O_STREAMING 20 #define O_STREAMING 0 21 #endif 22 23 #ifndef O_LARGEFILE 24 #define O_LARGEFILE 0 25 #endif 26 27 #ifndef O_BINARY 28 #define O_BINARY 0 29 #endif 30 31 #define LOC QString("FileRingBuf(%1): ").arg(filename) 32 #define LOC_WARN QString("FileRingBuf(%1) Warning: ").arg(filename) 33 #define LOC_ERR QString("FileRingBuf(%1) Error: ").arg(filename) 34 35 FileRingBuffer::FileRingBuffer(const QString &lfilename, 36 bool write, bool readahead, int timeout_ms) 37 { 38 startreadahead = readahead; 39 40 if (write) 41 { 42 filename = lfilename; 43 if (filename.startsWith("myth://")) 44 { 45 remotefile = new RemoteFile(filename, true); 46 if (!remotefile->isOpen()) 47 { 48 VERBOSE(VB_IMPORTANT, 49 QString("RingBuffer::RingBuffer(): Failed to open " 50 "remote file (%1) for write").arg(filename)); 51 delete remotefile; 52 remotefile = NULL; 53 } 54 else 55 writemode = true; 56 } 57 else 58 { 59 tfw = new ThreadedFileWriter( 60 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644); 61 62 if (!tfw->Open()) 63 { 64 delete tfw; 65 tfw = NULL; 66 } 67 else 68 writemode = true; 69 } 70 } 71 else if (timeout_ms >= 0) 72 { 73 OpenFile(filename, timeout_ms); 74 } 75 } 76 77 FileRingBuffer::~FileRingBuffer() 78 { 79 rwlock.lockForWrite(); 80 81 if (remotefile) 82 { 83 delete remotefile; 84 remotefile = NULL; 85 } 86 87 if (tfw) 88 { 89 delete tfw; 90 tfw = NULL; 91 } 92 93 if (fd2 >= 0) 94 { 95 close(fd2); 96 fd2 = -1; 97 } 98 99 rwlock.unlock(); 100 } 101 102 /** \fn check_permissions(const QString&) 103 * \brief Returns false iff file exists and has incorrect permissions. 104 * \param filename File (including path) that we want to know about 105 */ 106 static bool check_permissions(const QString &filename) 107 { 108 QFileInfo fileInfo(filename); 109 if (fileInfo.exists() && !fileInfo.isReadable()) 110 { 111 VERBOSE(VB_IMPORTANT, LOC_ERR + 112 "File exists but is not readable by MythTV!"); 113 return false; 114 } 115 return true; 116 } 117 118 static bool is_subtitle_possible(const QString &extension) 119 { 120 QMutexLocker locker(&RingBuffer::subExtLock); 121 bool no_subtitle = false; 122 for (uint i = 0; i < (uint)RingBuffer::subExtNoCheck.size(); i++) 123 { 124 if (extension.contains(RingBuffer::subExtNoCheck[i].right(3))) 125 { 126 no_subtitle = true; 127 break; 128 } 129 } 130 return !no_subtitle; 131 } 132 133 static QString local_sub_filename(QFileInfo &fileInfo) 134 { 135 // Subtitle handling 136 QString vidFileName = fileInfo.fileName(); 137 QString dirName = fileInfo.absolutePath(); 138 139 QString baseName = vidFileName; 140 int suffixPos = vidFileName.lastIndexOf(QChar('.')); 141 if (suffixPos > 0) 142 baseName = vidFileName.left(suffixPos); 143 144 QStringList el; 145 { 146 // The dir listing does not work if the filename has the 147 // following chars "[]()" so we convert them to the wildcard '?' 148 const QString findBaseName = baseName 149 .replace("[", "?") 150 .replace("]", "?") 151 .replace("(", "?") 152 .replace(")", "?"); 153 154 QMutexLocker locker(&RingBuffer::subExtLock); 155 QStringList::const_iterator eit = RingBuffer::subExt.begin(); 156 for (; eit != RingBuffer::subExt.end(); eit++) 157 el += findBaseName + *eit; 158 } 159 160 // Some Qt versions do not accept paths in the search string of 161 // entryList() so we have to set the dir first 162 QDir dir; 163 dir.setPath(dirName); 164 165 const QStringList candidates = dir.entryList(el); 166 167 QStringList::const_iterator cit = candidates.begin(); 168 for (; cit != candidates.end(); ++cit) 169 { 170 QFileInfo fi(dirName + "/" + *cit); 171 if (fi.exists() && (fi.size() >= RingBuffer::kReadTestSize)) 172 return fi.absoluteFilePath(); 173 } 174 175 return QString::null; 176 } 177 178 bool FileRingBuffer::OpenFile(const QString &lfilename, uint retry_ms) 179 { 180 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)") 181 .arg(lfilename).arg(retry_ms)); 182 183 rwlock.lockForWrite(); 184 185 filename = lfilename; 186 187 if (remotefile) 188 { 189 delete remotefile; 190 remotefile = NULL; 191 } 192 193 if (fd2 >= 0) 194 { 195 close(fd2); 196 fd2 = -1; 197 } 198 199 bool is_local = 200 (filename.left(4) != "/dev") && 201 ((filename.left(1) == "/") || QFile::exists(filename)); 202 203 if (is_local) 204 { 205 char buf[kReadTestSize]; 206 int lasterror = 0; 207 208 MythTimer openTimer; 209 openTimer.start(); 210 211 uint openAttempts = 0; 212 do 213 { 214 openAttempts++; 215 lasterror = 0; 216 217 fd2 = open(filename.toLocal8Bit().constData(), 218 O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY); 219 220 if (fd2 < 0) 221 { 222 if (!check_permissions(filename)) 223 { 224 lasterror = 3; 225 break; 226 } 227 228 lasterror = 1; 229 usleep(10 * 1000); 230 } 231 else 232 { 233 int ret = read(fd2, buf, kReadTestSize); 234 if (ret != (int)kReadTestSize) 235 { 236 lasterror = 2; 237 close(fd2); 238 fd2 = -1; 239 if (oldfile) 240 break; // if it's an old file it won't grow.. 241 usleep(10 * 1000); 242 } 243 else 244 { 245 if (0 == lseek(fd2, 0, SEEK_SET)) 246 { 247 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL); 248 posix_fadvise(fd2, 0, 1*1024*1024, POSIX_FADV_WILLNEED); 249 lasterror = 0; 250 break; 251 } 252 lasterror = 4; 253 close(fd2); 254 fd2 = -1; 255 } 256 } 257 } 258 while ((uint)openTimer.elapsed() < retry_ms); 259 260 switch (lasterror) 261 { 262 case 0: 263 { 264 QFileInfo fi(filename); 265 oldfile = fi.lastModified() 266 .secsTo(QDateTime::currentDateTime()) > 60; 267 QString extension = fi.completeSuffix().toLower(); 268 if (is_subtitle_possible(extension)) 269 subtitlefilename = local_sub_filename(fi); 270 break; 271 } 272 case 1: 273 VERBOSE(VB_IMPORTANT, LOC_ERR + 274 QString("OpenFile(): Could not open.")); 275 break; 276 case 2: 277 VERBOSE(VB_IMPORTANT, LOC_ERR + 278 QString("OpenFile(): File too small (%1B).") 279 .arg(QFileInfo(filename).size())); 280 break; 281 case 3: 282 VERBOSE(VB_IMPORTANT, LOC_ERR + 283 "OpenFile(): Improper permissions."); 284 break; 285 case 4: 286 VERBOSE(VB_IMPORTANT, LOC_ERR + 287 "OpenFile(): Cannot seek in file."); 288 break; 289 default: 290 break; 291 } 292 VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms") 293 .arg(openAttempts).arg(openTimer.elapsed())); 294 295 } 296 else 297 { 298 QString tmpSubName = filename; 299 QString dirName = "."; 300 301 int dirPos = filename.lastIndexOf(QChar('/')); 302 if (dirPos > 0) 303 { 304 tmpSubName = filename.mid(dirPos + 1); 305 dirName = filename.left(dirPos); 306 } 307 308 QString baseName = tmpSubName; 309 QString extension = tmpSubName; 310 QStringList auxFiles; 311 312 int suffixPos = tmpSubName.lastIndexOf(QChar('.')); 313 if (suffixPos > 0) 314 { 315 baseName = tmpSubName.left(suffixPos); 316 extension = tmpSubName.right(suffixPos-1); 317 if (is_subtitle_possible(extension)) 318 { 319 QMutexLocker locker(&subExtLock); 320 QStringList::const_iterator eit = subExt.begin(); 321 for (; eit != subExt.end(); eit++) 322 auxFiles += baseName + *eit; 323 } 324 } 325 326 remotefile = new RemoteFile(filename, false, true, 327 retry_ms, &auxFiles); 328 if (!remotefile->isOpen()) 329 { 330 VERBOSE(VB_IMPORTANT, LOC_ERR + 331 QString("RingBuffer::RingBuffer(): Failed to open remote " 332 "file (%1)").arg(filename)); 333 delete remotefile; 334 remotefile = NULL; 335 } 336 else 337 { 338 QStringList aux = remotefile->GetAuxiliaryFiles(); 339 if (aux.size()) 340 subtitlefilename = dirName + "/" + aux[0]; 341 } 342 } 343 344 setswitchtonext = false; 345 ateof = false; 346 commserror = false; 347 numfailures = 0; 348 349 rawbitrate = 8000; 350 CalcReadAheadThresh(); 351 352 bool ok = fd2 >= 0 || remotefile; 353 354 rwlock.unlock(); 355 356 return ok; 357 } 358 359 bool FileRingBuffer::IsOpen(void) const 360 { 361 rwlock.lockForRead(); 362 bool ret = tfw || (fd2 > -1) || remotefile; 363 rwlock.unlock(); 364 return ret; 365 } 366 367 /** \fn FileRingBuffer::safe_read(int, void*, uint) 368 * \brief Reads data from the file-descriptor. 369 * 370 * This will re-read the file forever until the 371 * end-of-file is reached or the buffer is full. 372 * 373 * \param fd File descriptor to read from 374 * \param data Pointer to where data will be written 375 * \param sz Number of bytes to read 376 * \return Returns number of bytes read 377 */ 378 int FileRingBuffer::safe_read(int fd, void *data, uint sz) 379 { 380 int ret; 381 unsigned tot = 0; 382 unsigned errcnt = 0; 383 unsigned zerocnt = 0; 384 385 if (fd2 < 0) 386 { 387 VERBOSE(VB_IMPORTANT, LOC_ERR + 388 "Invalid file descriptor in 'safe_read()'"); 389 return 0; 390 } 391 392 if (stopreads) 393 return 0; 394 395 while (tot < sz) 396 { 397 ret = read(fd2, (char *)data + tot, sz - tot); 398 if (ret < 0) 399 { 400 if (errno == EAGAIN) 401 continue; 402 403 VERBOSE(VB_IMPORTANT, 404 LOC_ERR + "File I/O problem in 'safe_read()'" + ENO); 405 406 errcnt++; 407 numfailures++; 408 if (errcnt == 3) 409 break; 410 } 411 else if (ret > 0) 412 { 413 tot += ret; 414 } 415 416 if (oldfile) 417 break; 418 419 if (ret == 0) // EOF returns 0 420 { 421 if (tot > 0) 422 break; 423 424 zerocnt++; 425 426 // 0.36 second timeout for livetvchain with usleep(60000), 427 // or 2.4 seconds if it's a new file less than 30 minutes old. 428 if (zerocnt >= (livetvchain ? 6 : 40)) 429 { 430 break; 431 } 432 } 433 if (stopreads) 434 break; 435 if (tot < sz) 436 usleep(60000); 437 } 438 return tot; 439 } 440 441 /** \fn FileRingBuffer::safe_read(RemoteFile*, void*, uint) 442 * \brief Reads data from the RemoteFile. 443 * 444 * \param rf RemoteFile to read from 445 * \param data Pointer to where data will be written 446 * \param sz Number of bytes to read 447 * \return Returns number of bytes read 448 */ 449 int FileRingBuffer::safe_read(RemoteFile *rf, void *data, uint sz) 450 { 451 int ret = rf->Read(data, sz); 452 if (ret < 0) 453 { 454 VERBOSE(VB_IMPORTANT, LOC_ERR + 455 "safe_read(RemoteFile* ...): read failed"); 456 457 poslock.lockForRead(); 458 rf->Seek(internalreadpos - readAdjust, SEEK_SET); 459 poslock.unlock(); 460 numfailures++; 461 } 462 else if (ret == 0) 463 { 464 VERBOSE(VB_FILE, LOC + 465 "safe_read(RemoteFile* ...): at EOF"); 466 } 467 468 return ret; 469 } 470 471 long long FileRingBuffer::GetReadPosition(void) const 472 { 473 poslock.lockForRead(); 474 long long ret = readpos; 475 poslock.unlock(); 476 return ret; 477 } 478 479 long long FileRingBuffer::GetRealFileSize(void) const 480 { 481 rwlock.lockForRead(); 482 long long ret = -1; 483 if (remotefile) 484 ret = remotefile->GetFileSize(); 485 else 486 ret = QFileInfo(filename).size(); 487 rwlock.unlock(); 488 return ret; 489 } 490 491 long long FileRingBuffer::Seek(long long pos, int whence, bool has_lock) 492 { 493 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)") 494 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET": 495 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END")) 496 .arg(has_lock?"locked":"unlocked")); 497 498 long long ret = -1; 499 500 StopReads(); 501 502 // lockForWrite takes priority over lockForRead, so this will 503 // take priority over the lockForRead in the read ahead thread. 504 if (!has_lock) 505 rwlock.lockForWrite(); 506 507 StartReads(); 508 509 if (writemode) 510 { 511 ret = WriterSeek(pos, whence, true); 512 if (!has_lock) 513 rwlock.unlock(); 514 return ret; 515 } 516 517 poslock.lockForWrite(); 518 519 // Optimize no-op seeks 520 if (readaheadrunning && 521 ((whence == SEEK_SET && pos == readpos) || 522 (whence == SEEK_CUR && pos == 0))) 523 { 524 ret = readpos; 525 526 poslock.unlock(); 527 if (!has_lock) 528 rwlock.unlock(); 529 530 return ret; 531 } 532 533 // only valid for SEEK_SET & SEEK_CUR 534 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos; 535 536 #if 1 537 // Optimize short seeks where the data for 538 // them is in our ringbuffer already. 539 if (readaheadrunning && 540 (SEEK_SET==whence || SEEK_CUR==whence)) 541 { 542 rbrlock.lockForWrite(); 543 rbwlock.lockForRead(); 544 VERBOSE(VB_FILE, LOC + 545 QString("Seek(): rbrpos: %1 rbwpos: %2" 546 "\n\t\t\treadpos: %3 internalreadpos: %4") 547 .arg(rbrpos).arg(rbwpos) 548 .arg(readpos).arg(internalreadpos)); 549 bool used_opt = false; 550 if ((new_pos < readpos)) 551 { 552 int min_safety = max(fill_min, readblocksize); 553 int free = ((rbwpos >= rbrpos) ? 554 rbrpos + kBufferSize : rbrpos) - rbwpos; 555 int internal_backbuf = 556 (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos; 557 internal_backbuf = min(internal_backbuf, free - min_safety); 558 long long sba = readpos - new_pos; 559 VERBOSE(VB_FILE, LOC + 560 QString("Seek(): internal_backbuf: %1 sba: %2") 561 .arg(internal_backbuf).arg(sba)); 562 if (internal_backbuf >= sba) 563 { 564 rbrpos = (rbrpos>=sba) ? rbrpos - sba : 565 kBufferSize + rbrpos - sba; 566 used_opt = true; 567 VERBOSE(VB_FILE, LOC + 568 QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2" 569 "\n\t\t\treadpos: %3 internalreadpos: %4") 570 .arg(rbrpos).arg(rbwpos) 571 .arg(new_pos).arg(internalreadpos)); 572 } 573 } 574 else if ((new_pos >= readpos) && (new_pos <= internalreadpos)) 575 { 576 rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize; 577 used_opt = true; 578 VERBOSE(VB_FILE, LOC + 579 QString("Seek(): OPT2 rbrpos: %1 sba: %2") 580 .arg(rbrpos).arg(readpos - new_pos)); 581 } 582 rbwlock.unlock(); 583 rbrlock.unlock(); 584 585 if (used_opt) 586 { 587 if (ignorereadpos >= 0) 588 { 589 // seek should always succeed since we were at this position 590 int ret; 591 if (remotefile) 592 ret = remotefile->Seek(internalreadpos, SEEK_SET); 593 else 594 { 595 ret = lseek64(fd2, internalreadpos, SEEK_SET); 596 posix_fadvise(fd2, 0, 597 internalreadpos, POSIX_FADV_DONTNEED); 598 posix_fadvise(fd2, internalreadpos, 599 1*1024*1024, POSIX_FADV_WILLNEED); 600 } 601 VERBOSE(VB_FILE, LOC + 602 QString("Seek to %1 from ignore pos %2 returned %3") 603 .arg(internalreadpos).arg(ignorereadpos).arg(ret)); 604 ignorereadpos = -1; 605 } 606 readpos = new_pos; 607 poslock.unlock(); 608 generalWait.wakeAll(); 609 ateof = false; 610 readsallowed = false; 611 if (!has_lock) 612 rwlock.unlock(); 613 return new_pos; 614 } 615 } 616 #endif 617 618 #if 1 619 // This optimizes the seek end-250000, read, seek 0, read portion 620 // of the pattern ffmpeg performs at the start of playback to 621 // determine the pts. 622 // If the seek is a SEEK_END or is a seek where the position 623 // changes over 100 MB we check the file size and if the 624 // destination point is within 300000 bytes of the end of 625 // the file we enter a special mode where the read ahead 626 // buffer stops reading data and all reads are made directly 627 // until another seek is performed. The point of all this is 628 // to avoid flushing out the buffer that still contains all 629 // the data the final seek 0, read will need just to read the 630 // last 250000 bytes. A further optimization would be to buffer 631 // the 250000 byte read, which is currently performed in 32KB 632 // blocks (inefficient with RemoteFile). 633 if ((remotefile || fd2 >= 0) && (ignorereadpos < 0)) 634 { 635 long long off_end = 0xDEADBEEF; 636 if (SEEK_END == whence) 637 { 638 off_end = pos; 639 if (remotefile) 640 { 641 new_pos = remotefile->GetFileSize() - off_end; 642 } 643 else 644 { 645 QFileInfo fi(filename); 646 new_pos = fi.size() - off_end; 647 } 648 } 649 else 650 { 651 if (remotefile) 652 { 653 off_end = remotefile->GetFileSize() - new_pos; 654 } 655 else 656 { 657 QFileInfo fi(filename); 658 off_end = fi.size() - new_pos; 659 } 660 } 661 662 if (off_end != 0xDEADBEEF) 663 { 664 VERBOSE(VB_FILE, LOC + 665 QString("Seek(): Offset from end: %1").arg(off_end)); 666 } 667 668 if (off_end <= 250000) 669 { 670 VERBOSE(VB_FILE, LOC + 671 QString("Seek(): offset from end: %1").arg(off_end) + 672 "\n\t\t\t -- ignoring read ahead thread until next seek."); 673 674 ignorereadpos = new_pos; 675 errno = EINVAL; 676 long long ret; 677 if (remotefile) 678 ret = remotefile->Seek(ignorereadpos, SEEK_SET); 679 else 680 { 681 ret = lseek64(fd2, ignorereadpos, SEEK_SET); 682 posix_fadvise(fd2, ignorereadpos, 250000, POSIX_FADV_WILLNEED); 683 } 684 685 if (ret < 0) 686 { 687 int tmp_eno = errno; 688 QString cmd = QString("Seek(%1, SEEK_SET) ign ") 689 .arg(ignorereadpos); 690 691 ignorereadpos = -1; 692 693 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 694 695 // try to return to former position.. 696 if (remotefile) 697 ret = remotefile->Seek(internalreadpos, SEEK_SET); 698 else 699 ret = lseek64(fd2, internalreadpos, SEEK_SET); 700 if (ret < 0) 701 { 702 QString cmd = QString("Seek(%1, SEEK_SET) int ") 703 .arg(internalreadpos); 704 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 705 } 706 else 707 { 708 QString cmd = QString("Seek(%1, %2) int ") 709 .arg(internalreadpos) 710 .arg((SEEK_SET == whence) ? "SEEK_SET" : 711 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 712 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " succeeded"); 713 } 714 ret = -1; 715 errno = tmp_eno; 716 } 717 else 718 { 719 ateof = false; 720 readsallowed = false; 721 } 722 723 rbwlock.unlock(); 724 rbrlock.unlock(); 725 poslock.unlock(); 726 727 generalWait.wakeAll(); 728 729 if (!has_lock) 730 rwlock.unlock(); 731 732 return ret; 733 } 734 } 735 #endif 736 737 // Here we perform a normal seek. When successful we 738 // need to call ResetReadAhead(). A reset means we will 739 // need to refill the buffer, which takes some time. 740 if (remotefile) 741 { 742 ret = remotefile->Seek(pos, whence, readpos); 743 if (ret<0) 744 errno = EINVAL; 745 } 746 else 747 { 748 ret = lseek64(fd2, pos, whence); 749 if (ret >= 0) 750 { 751 posix_fadvise(fd2, 0, ret, POSIX_FADV_DONTNEED); 752 posix_fadvise(fd2, ret, 1*1024*1024, POSIX_FADV_WILLNEED); 753 } 754 } 755 756 if (ret >= 0) 757 { 758 readpos = ret; 759 760 ignorereadpos = -1; 761 762 if (readaheadrunning) 763 ResetReadAhead(readpos); 764 765 readAdjust = 0; 766 } 767 else 768 { 769 QString cmd = QString("Seek(%1, %2)").arg(pos) 770 .arg((SEEK_SET == whence) ? "SEEK_SET" : 771 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END")); 772 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO); 773 } 774 775 poslock.unlock(); 776 777 generalWait.wakeAll(); 778 779 if (!has_lock) 780 rwlock.unlock(); 781 782 return ret; 783 } -
libs/libmythtv/mythdvdplayer.cpp
11 11 MythDVDPlayer::MythDVDPlayer(bool muted) 12 12 : MythPlayer(muted), m_buttonVersion(0), 13 13 dvd_stillframe_showing(false), need_change_dvd_track(0), 14 m_initial_title(-1), m_initial_audio_track(-1), m_initial_subtitle_track(-1), 14 m_initial_title(-1), m_initial_audio_track(-1), 15 m_initial_subtitle_track(-1), 15 16 m_stillFrameLength(0) 16 17 { 17 18 } … … 25 26 int64_t timecode, bool wrap) 26 27 { 27 28 MythPlayer::ReleaseNextVideoFrame(buffer, timecode, 28 !player_ctx->buffer->I nDiscMenuOrStillFrame());29 !player_ctx->buffer->IsInDiscMenuOrStillFrame()); 29 30 } 30 31 31 32 void MythDVDPlayer::DisableCaptions(uint mode, bool osd_msg) 32 33 { 33 if ((kDisplayAVSubtitle & mode) && player_ctx->buffer-> isDVD())34 if ((kDisplayAVSubtitle & mode) && player_ctx->buffer->IsDVD()) 34 35 player_ctx->buffer->DVD()->SetTrack(kTrackTypeSubtitle, -1); 35 36 MythPlayer::DisableCaptions(mode, osd_msg); 36 37 } 37 38 38 39 void MythDVDPlayer::EnableCaptions(uint mode, bool osd_msg) 39 40 { 40 if ((kDisplayAVSubtitle & mode) && player_ctx->buffer-> isDVD())41 if ((kDisplayAVSubtitle & mode) && player_ctx->buffer->IsDVD()) 41 42 player_ctx->buffer->DVD()->SetTrack(kTrackTypeSubtitle, 42 43 GetTrack(kTrackTypeSubtitle)); 43 44 MythPlayer::EnableCaptions(mode, osd_msg); … … 45 46 46 47 void MythDVDPlayer::DisplayPauseFrame(void) 47 48 { 48 if (player_ctx->buffer->isDVD() && 49 player_ctx->buffer->DVD()->InStillFrame()) 49 if (player_ctx->buffer->IsDVD() && 50 player_ctx->buffer->DVD()->IsInStillFrame()) 51 { 50 52 SetScanType(kScan_Progressive); 53 } 51 54 DisplayDVDButton(); 52 55 MythPlayer::DisplayPauseFrame(); 53 56 } … … 60 63 61 64 bool MythDVDPlayer::PrebufferEnoughFrames(bool pause_audio, int min_buffers) 62 65 { 63 bool instill = player_ctx->buffer->I nDiscMenuOrStillFrame();66 bool instill = player_ctx->buffer->IsInDiscMenuOrStillFrame(); 64 67 return MythPlayer::PrebufferEnoughFrames(!instill, 1); 65 68 } 66 69 … … 74 77 bool MythDVDPlayer::DecoderGetFrameREW(void) 75 78 { 76 79 MythPlayer::DecoderGetFrameREW(); 77 return (player_ctx->buffer-> isDVD() &&78 (player_ctx->buffer->DVD()->GetCurrentTime() < 2));80 return (player_ctx->buffer->IsDVD() && 81 (player_ctx->buffer->DVD()->GetCurrentTime() < 2)); 79 82 } 80 83 81 84 void MythDVDPlayer::PreProcessNormalFrame(void) … … 85 88 86 89 bool MythDVDPlayer::VideoLoop(void) 87 90 { 88 if (!player_ctx->buffer-> isDVD())91 if (!player_ctx->buffer->IsDVD()) 89 92 { 90 93 SetErrored("RingBuffer is not a DVD."); 91 94 return !IsErrored(); … … 104 107 bool release_one = (nbframes > 1) && videoPaused && !allpaused && 105 108 (!videoOutput->EnoughFreeFrames() || 106 109 player_ctx->buffer->DVD()->IsWaiting() || 107 player_ctx->buffer->DVD()->I nStillFrame());110 player_ctx->buffer->DVD()->IsInStillFrame()); 108 111 if (release_all || release_one) 109 112 { 110 113 if (nbframes < 5 && videoOutput) … … 123 126 VERBOSE(VB_PLAYBACK, LOC + "Clearing Mythtv dvd wait state"); 124 127 player_ctx->buffer->DVD()->SkipDVDWaitingForPlayer(); 125 128 ClearAfterSeek(true); 126 if (!player_ctx->buffer->DVD()->I nStillFrame() && videoPaused)129 if (!player_ctx->buffer->DVD()->IsInStillFrame() && videoPaused) 127 130 UnpauseVideo(); 128 131 return !IsErrored(); 129 132 } … … 136 139 { 137 140 VERBOSE(VB_PLAYBACK, LOC + "Clearing DVD wait state"); 138 141 player_ctx->buffer->DVD()->WaitSkip(); 139 if (!player_ctx->buffer->DVD()->I nStillFrame() && videoPaused)142 if (!player_ctx->buffer->DVD()->IsInStillFrame() && videoPaused) 140 143 UnpauseVideo(); 141 144 return !IsErrored(); 142 145 } 143 146 144 147 // we need a custom presentation method for still frame menus with audio 145 148 if (player_ctx->buffer->DVD()->IsInMenu() && 146 !player_ctx->buffer->DVD()->InStillFrame())149 !player_ctx->buffer->DVD()->IsInStillFrame()) 147 150 { 148 151 // ensure we refresh the pause frame 149 152 if (!dvd_stillframe_showing) … … 155 158 } 156 159 157 160 // the still frame is treated as a pause frame 158 if (player_ctx->buffer->DVD()->I nStillFrame())161 if (player_ctx->buffer->DVD()->IsInStillFrame()) 159 162 { 160 163 // ensure we refresh the pause frame 161 164 if (!dvd_stillframe_showing) … … 318 321 319 322 bool MythDVDPlayer::PrepareAudioSample(int64_t &timecode) 320 323 { 321 if (!player_ctx->buffer->I nDiscMenuOrStillFrame())324 if (!player_ctx->buffer->IsInDiscMenuOrStillFrame()) 322 325 WrapTimecode(timecode, TC_AUDIO); 323 326 324 if (player_ctx->buffer-> isDVD() &&325 player_ctx->buffer->DVD()->I nStillFrame())327 if (player_ctx->buffer->IsDVD() && 328 player_ctx->buffer->DVD()->IsInStillFrame()) 326 329 return true; 327 330 return false; 328 331 } 329 332 330 333 void MythDVDPlayer::SetBookmark(void) 331 334 { 332 if (player_ctx->buffer->InDiscMenuOrStillFrame()) 335 if (player_ctx->buffer->IsInDiscMenuOrStillFrame()) 336 { 333 337 SetDVDBookmark(0); 338 } 334 339 else 335 340 { 336 341 SetDVDBookmark(framesPlayed); … … 348 353 349 354 uint64_t MythDVDPlayer::GetBookmark(void) 350 355 { 351 if (gCoreContext->IsDatabaseIgnored() || !player_ctx->buffer-> isDVD())356 if (gCoreContext->IsDatabaseIgnored() || !player_ctx->buffer->IsDVD()) 352 357 return 0; 353 358 354 359 QStringList dvdbookmark = QStringList(); … … 387 392 MythPlayer::ChangeSpeed(); 388 393 if (decoder) 389 394 decoder->UpdateDVDFramesPlayed(); 390 if (play_speed != normal_speed && player_ctx->buffer-> isDVD())395 if (play_speed != normal_speed && player_ctx->buffer->IsDVD()) 391 396 player_ctx->buffer->DVD()->SetDVDSpeed(-1); 392 else if (player_ctx->buffer-> isDVD())397 else if (player_ctx->buffer->IsDVD()) 393 398 player_ctx->buffer->DVD()->SetDVDSpeed(); 394 399 } 395 400 … … 400 405 401 406 long long MythDVDPlayer::CalcMaxFFTime(long long ff, bool setjump) const 402 407 { 403 if ((totalFrames > 0) && player_ctx->buffer-> isDVD() &&408 if ((totalFrames > 0) && player_ctx->buffer->IsDVD() && 404 409 player_ctx->buffer->DVD()->TitleTimeLeft() < 5) 405 410 return 0; 406 411 return MythPlayer::CalcMaxFFTime(ff, setjump); … … 413 418 info.values.insert("position", 0); 414 419 info.values.insert("progbefore", 0); 415 420 info.values.insert("progafter", 0); 416 if (!player_ctx->buffer-> isDVD())421 if (!player_ctx->buffer->IsDVD()) 417 422 return; 418 423 419 424 int playbackLen = totalLength; … … 438 443 void MythDVDPlayer::SeekForScreenGrab(uint64_t &number, uint64_t frameNum, 439 444 bool absolute) 440 445 { 441 if (!player_ctx->buffer-> isDVD())446 if (!player_ctx->buffer->IsDVD()) 442 447 return; 443 448 if (GoToDVDMenu("menu")) 444 449 { 445 450 if (player_ctx->buffer->DVD()->IsInMenu() && 446 !player_ctx->buffer->DVD()->InStillFrame()) 451 !player_ctx->buffer->DVD()->IsInStillFrame()) 452 { 447 453 GoToDVDProgram(1); 454 } 448 455 } 449 456 else if (player_ctx->buffer->DVD()->GetTotalTimeOfTitle() < 60) 450 457 { … … 471 478 { 472 479 if (decoder) 473 480 decoder->ChangeDVDTrack(need_change_dvd_track > 0); 474 ClearAfterSeek(!player_ctx->buffer->I nDiscMenuOrStillFrame());481 ClearAfterSeek(!player_ctx->buffer->IsInDiscMenuOrStillFrame()); 475 482 } 476 483 477 484 void MythDVDPlayer::DisplayDVDButton(void) 478 485 { 479 if (!osd || !player_ctx->buffer-> isDVD())486 if (!osd || !player_ctx->buffer->IsDVD()) 480 487 return; 481 488 482 489 uint buttonversion = 0; … … 484 491 bool numbuttons = player_ctx->buffer->DVD()->NumMenuButtons(); 485 492 486 493 // nothing to do 487 if (buttonversion == m_buttonVersion)494 if (buttonversion == ((uint)m_buttonVersion)) 488 495 { 489 496 player_ctx->buffer->DVD()->ReleaseMenuButton(); 490 497 return; … … 510 517 511 518 bool MythDVDPlayer::GoToDVDMenu(QString str) 512 519 { 513 if (!player_ctx->buffer-> isDVD())520 if (!player_ctx->buffer->IsDVD()) 514 521 return false; 515 522 textDisplayMode = kDisplayNone; 516 523 bool ret = player_ctx->buffer->DVD()->GoToMenu(str); … … 527 534 528 535 void MythDVDPlayer::GoToDVDProgram(bool direction) 529 536 { 530 if (!player_ctx->buffer-> isDVD())537 if (!player_ctx->buffer->IsDVD()) 531 538 return; 532 539 if (direction == 0) 533 540 player_ctx->buffer->DVD()->GoToPreviousProgram(); … … 537 544 538 545 void MythDVDPlayer::SetDVDBookmark(uint64_t frame) 539 546 { 540 if (!player_ctx->buffer-> isDVD())547 if (!player_ctx->buffer->IsDVD()) 541 548 return; 542 549 543 550 uint64_t framenum = frame; … … 556 563 return; 557 564 } 558 565 559 if (!player_ctx->buffer->InDiscMenuOrStillFrame() && 560 player_ctx->buffer->DVD()->GetTotalTimeOfTitle() > 120 && frame > 0) 566 if (!player_ctx->buffer->IsInDiscMenuOrStillFrame() && 567 player_ctx->buffer->DVD()-> 568 GetTotalTimeOfTitle() > 120 && frame > 0) 561 569 { 562 570 audiotrack = GetTrack(kTrackTypeAudio); 563 571 if (GetCaptionMode() == kDisplayAVSubtitle) … … 637 645 638 646 void MythDVDPlayer::StillFrameCheck(void) 639 647 { 640 if (player_ctx->buffer-> isDVD() &&641 player_ctx->buffer->DVD()->I nStillFrame() &&648 if (player_ctx->buffer->IsDVD() && 649 player_ctx->buffer->DVD()->IsInStillFrame() && 642 650 (m_stillFrameLength > 0) && (m_stillFrameLength < 0xff)) 643 651 { 644 652 m_stillFrameTimerLock.lock(); -
libs/libmythtv/previewgenerator.cpp
788 788 } 789 789 } 790 790 791 RingBuffer *rbuf = new RingBuffer(filename, false, false, 0);791 RingBuffer *rbuf = RingBuffer::Create(filename, false, false, 0); 792 792 if (!rbuf->IsOpen()) 793 793 { 794 794 VERBOSE(VB_IMPORTANT, LOC_ERR + "Previewer could not open file: " + -
libs/libmythtv/FileRingBuffer.h
1 #include "RingBuffer.h" 2 3 class MPUBLIC FileRingBuffer : public RingBuffer 4 { 5 friend class RingBuffer; 6 public: 7 ~FileRingBuffer(); 8 9 // Gets 10 virtual bool IsOpen(void) const; 11 virtual long long GetReadPosition(void) const; 12 virtual long long GetRealFileSize(void) const; 13 14 // General Commands 15 virtual bool OpenFile(const QString &lfilename, 16 uint retry_ms = kDefaultOpenTimeout); 17 virtual long long Seek(long long pos, int whence, bool has_lock); 18 19 protected: 20 FileRingBuffer(const QString &lfilename, 21 bool write, bool readahead, int timeout_ms); 22 23 virtual int safe_read(void *data, uint sz) 24 { 25 if (remotefile) 26 return safe_read(remotefile, data, sz); 27 else if (fd2 >= 0) 28 return safe_read(fd2, data, sz); 29 30 errno = EBADF; 31 return -1; 32 } 33 int safe_read(int fd, void *data, uint sz); 34 int safe_read(RemoteFile *rf, void *data, uint sz); 35 }; -
libs/libmythtv/RingBuffer.cpp
9 9 #include <sys/time.h> 10 10 #include <unistd.h> 11 11 #include <fcntl.h> 12 #include <pthread.h>13 12 14 13 // Qt headers 15 14 #include <QFile> 16 15 #include <QDateTime> 17 #include <QFileInfo>18 #include <QDir>19 16 20 using namespace std;21 22 #include "mythcontext.h" // for VERBOSE23 #include "mythconfig.h"24 #include "exitcodes.h"25 #include "RingBuffer.h"26 #include "remotefile.h"27 17 #include "ThreadedFileWriter.h" 28 #include " livetvchain.h"18 #include "FileRingBuffer.h" 29 19 #include "DVDRingBuffer.h" 30 20 #include "BDRingBuffer.h" 31 #include "util.h" 21 #include "livetvchain.h" 22 #include "mythcontext.h" 23 #include "RingBuffer.h" 24 #include "mythconfig.h" 25 #include "remotefile.h" 32 26 #include "compat.h" 27 #include "util.h" 33 28 34 #ifndef O_STREAMING35 #define O_STREAMING 036 #endif37 38 #ifndef O_LARGEFILE39 #define O_LARGEFILE 040 #endif41 42 #ifndef O_BINARY43 #define O_BINARY 044 #endif45 46 29 #if HAVE_POSIX_FADVISE < 1 47 30 static int posix_fadvise(int, off_t, off_t, int) { return 0; } 48 31 #define POSIX_FADV_SEQUENTIAL 0 … … 122 105 * the file after the first failure in 123 106 * milliseconds before giving up. 124 107 */ 125 RingBuffer::RingBuffer(const QString &lfilename, 126 bool write, bool readahead, 127 int timeout_ms) 128 : readpos(0), writepos(0), 129 internalreadpos(0), ignorereadpos(-1), 130 rbrpos(0), rbwpos(0), 131 stopreads(false), 132 filename(lfilename), subtitlefilename(QString::null), 133 tfw(NULL), fd2(-1), 134 writemode(false), remotefile(NULL), 135 startreadahead(readahead),readAheadBuffer(NULL), 136 readaheadrunning(false), reallyrunning(false), 137 request_pause(false), paused(false), 138 ateof(false), readsallowed(false), 139 setswitchtonext(false), streamOnly(false), 140 rawbitrate(8000), playspeed(1.0f), 141 fill_threshold(65536), fill_min(-1), 142 readblocksize(CHUNK), wanttoread(0), 143 numfailures(0), commserror(false), 144 dvdPriv(NULL), bdPriv(NULL), 145 oldfile(false), livetvchain(NULL), 146 ignoreliveeof(false), readAdjust(0) 108 RingBuffer *RingBuffer::Create( 109 const QString &xfilename, bool write, 110 bool usereadahead, int timeout_ms, bool stream_only) 147 111 { 148 filename.detach();112 QString lfilename = xfilename; 149 113 150 {151 QMutexLocker locker(&subExtLock);152 if (!subExt.size())153 {154 // Possible subtitle file extensions '.srt', '.sub', '.txt'155 subExt += ".srt";156 subExt += ".sub";157 subExt += ".txt";158 159 // Extensions for which a subtitle file should not exist160 subExtNoCheck = subExt;161 subExtNoCheck += ".gif";162 subExtNoCheck += ".png";163 }164 }165 166 114 if (write) 167 115 { 168 if (filename.startsWith("myth://")) 169 { 170 remotefile = new RemoteFile(filename, true); 171 if (!remotefile->isOpen()) 172 { 173 VERBOSE(VB_IMPORTANT, 174 QString("RingBuffer::RingBuffer(): Failed to open " 175 "remote file (%1) for write").arg(filename)); 176 delete remotefile; 177 remotefile = NULL; 178 } 179 else 180 writemode = true; 181 } 182 else 183 { 184 tfw = new ThreadedFileWriter( 185 filename, O_WRONLY|O_TRUNC|O_CREAT|O_LARGEFILE, 0644); 186 187 if (!tfw->Open()) 188 { 189 delete tfw; 190 tfw = NULL; 191 } 192 else 193 writemode = true; 194 } 195 return; 116 return new FileRingBuffer( 117 lfilename, write, usereadahead, timeout_ms); 196 118 } 197 119 198 if (timeout_ms >= 0)199 OpenFile(filename, timeout_ms);200 }201 202 /** \fn check_permissions(const QString&)203 * \brief Returns false iff file exists and has incorrect permissions.204 * \param filename File (including path) that we want to know about205 */206 static bool check_permissions(const QString &filename)207 {208 QFileInfo fileInfo(filename);209 if (fileInfo.exists() && !fileInfo.isReadable())210 {211 VERBOSE(VB_IMPORTANT, LOC_ERR +212 "File exists but is not readable by MythTV!");213 return false;214 }215 return true;216 }217 218 static bool is_subtitle_possible(const QString &extension)219 {220 QMutexLocker locker(&RingBuffer::subExtLock);221 bool no_subtitle = false;222 for (uint i = 0; i < (uint)RingBuffer::subExtNoCheck.size(); i++)223 {224 if (extension.contains(RingBuffer::subExtNoCheck[i].right(3)))225 {226 no_subtitle = true;227 break;228 }229 }230 return !no_subtitle;231 }232 233 static QString local_sub_filename(QFileInfo &fileInfo)234 {235 // Subtitle handling236 QString vidFileName = fileInfo.fileName();237 QString dirName = fileInfo.absolutePath();238 239 QString baseName = vidFileName;240 int suffixPos = vidFileName.lastIndexOf(QChar('.'));241 if (suffixPos > 0)242 baseName = vidFileName.left(suffixPos);243 244 QStringList el;245 {246 // The dir listing does not work if the filename has the247 // following chars "[]()" so we convert them to the wildcard '?'248 const QString findBaseName = baseName249 .replace("[", "?")250 .replace("]", "?")251 .replace("(", "?")252 .replace(")", "?");253 254 QMutexLocker locker(&RingBuffer::subExtLock);255 QStringList::const_iterator eit = RingBuffer::subExt.begin();256 for (; eit != RingBuffer::subExt.end(); eit++)257 el += findBaseName + *eit;258 }259 260 // Some Qt versions do not accept paths in the search string of261 // entryList() so we have to set the dir first262 QDir dir;263 dir.setPath(dirName);264 265 const QStringList candidates = dir.entryList(el);266 267 QStringList::const_iterator cit = candidates.begin();268 for (; cit != candidates.end(); ++cit)269 {270 QFileInfo fi(dirName + "/" + *cit);271 if (fi.exists() && (fi.size() >= RingBuffer::kReadTestSize))272 return fi.absoluteFilePath();273 }274 275 return QString::null;276 }277 278 /** \brief Opens a file for reading.279 *280 * \param lfilename Name of file to read281 * \param retry_ms How many ms to retry reading the file282 * after the first try before giving up.283 */284 void RingBuffer::OpenFile(const QString &lfilename, uint retry_ms)285 {286 VERBOSE(VB_PLAYBACK, LOC + QString("OpenFile(%1, %2 ms)")287 .arg(lfilename).arg(retry_ms));288 289 if (retry_ms >= 1 && retry_ms <= 20)290 {291 VERBOSE(VB_IMPORTANT, LOC + QString("OpenFile(%1, %2 ms)")292 .arg(lfilename).arg(retry_ms) +293 "Timeout small, assuming caller meant for this "294 "to be retries." + "\n\t\t\t"295 "WARNING: This workaround will be removed after the "296 "0.24 release, and this client may stop working.");297 retry_ms *= 150;298 qWarning("Applying temporary OpenFile() hack");299 }300 301 rwlock.lockForWrite();302 303 filename = lfilename;304 305 if (remotefile)306 {307 delete remotefile;308 }309 310 if (fd2 >= 0)311 {312 close(fd2);313 fd2 = -1;314 }315 316 bool is_local = false;317 120 bool is_dvd = false; 318 (void) is_dvd; // not used when frontend is disabled. 319 bool is_bd = false; 320 (void) is_bd; 121 bool is_bd = false; 321 122 322 if (!stream Only &&filename.startsWith("myth://"))123 if (!stream_only && lfilename.startsWith("myth://")) 323 124 { 324 125 struct stat fileInfo; 325 if ((RemoteFile::Exists( filename, &fileInfo)) &&126 if ((RemoteFile::Exists(lfilename, &fileInfo)) && 326 127 (S_ISDIR(fileInfo.st_mode))) 327 128 { 328 QString tmpFile = filename + "/VIDEO_TS";129 QString tmpFile = lfilename + "/VIDEO_TS"; 329 130 if (RemoteFile::Exists(tmpFile)) 330 131 { 331 132 is_dvd = true; 332 133 } 333 134 else 334 135 { 335 tmpFile = filename + "/BDMV";136 tmpFile = lfilename + "/BDMV"; 336 137 if (RemoteFile::Exists(tmpFile)) 337 138 is_bd = true; 338 139 } 339 140 } 340 141 } 341 142 342 if ((filename.left(1) == "/") || 343 (QFile::exists(filename))) 344 is_local = true; 345 346 #ifdef USING_FRONTEND 347 else if ((!streamOnly) && 348 ((filename.startsWith("dvd:")) || is_dvd || 349 ((filename.startsWith("myth://")) && 350 ((filename.endsWith(".img")) || 351 (filename.endsWith(".iso")))))) 143 if ((lfilename.left(1) == "/") || (QFile::exists(lfilename))) 352 144 { 145 } 146 else if ((!stream_only) && 147 ((lfilename.startsWith("dvd:")) || is_dvd || 148 ((lfilename.startsWith("myth://")) && 149 ((lfilename.endsWith(".img")) || 150 (lfilename.endsWith(".iso")))))) 151 { 353 152 is_dvd = true; 354 dvdPriv = new DVDRingBufferPriv();355 startreadahead = false;356 153 357 if ( filename.left(6) == "dvd://")// 'Play DVD' sends "dvd:/" + dev358 filename.remove(0,5); //e.g. "dvd://dev/sda"359 else if ( filename.left(5) == "dvd:/")// Less correct URI "dvd:" + path360 filename.remove(0,4); //e.g. "dvd:/videos/ET"154 if (lfilename.left(6) == "dvd://") // 'Play DVD' sends "dvd:/" + dev 155 lfilename.remove(0,5); // e.g. "dvd://dev/sda" 156 else if (lfilename.left(5) == "dvd:/") // Less correct URI "dvd:" + path 157 lfilename.remove(0,4); // e.g. "dvd:/videos/ET" 361 158 362 if (QFile::exists(filename) || filename.startsWith("myth://")) 363 VERBOSE(VB_PLAYBACK, "OpenFile() trying DVD at " + filename); 364 else 159 if (QFile::exists(lfilename) || lfilename.startsWith("myth://")) 365 160 { 366 filename = "/dev/dvd";161 VERBOSE(VB_PLAYBACK, "Trying DVD at " + lfilename); 367 162 } 368 }369 else if ((!streamOnly) && (filename.left(3) == "bd:" || is_bd))370 {371 is_bd = true;372 bdPriv = new BDRingBufferPriv();373 startreadahead = false;374 375 if (filename.left(5) == "bd://") // 'Play DVD' sends "bd:/" + dev376 filename.remove(0,4); // e.g. "bd://dev/sda"377 else if (filename.left(4) == "bd:/") // Less correct URI "bd:" + path378 filename.remove(0,3); // e.g. "bd:/videos/ET"379 380 if (QFile::exists(filename) || filename.startsWith("myth://"))381 VERBOSE(VB_PLAYBACK, "OpenFile() trying BD at " + filename);382 163 else 383 164 { 384 filename = "/dev/dvd";165 lfilename = "/dev/dvd"; 385 166 } 386 }387 #endif // USING_FRONTEND388 167 389 if (is_local) 168 return new DVDRingBuffer(lfilename); 169 } 170 else if ((!stream_only) && (lfilename.left(3) == "bd:" || is_bd)) 390 171 { 391 char buf[kReadTestSize]; 392 int lasterror = 0; 172 is_bd = true; 393 173 394 MythTimer openTimer; 395 openTimer.start(); 174 if (lfilename.left(5) == "bd://") // 'Play DVD' sends "bd:/" + dev 175 lfilename.remove(0,4); // e.g. "bd://dev/sda" 176 else if (lfilename.left(4) == "bd:/") // Less correct URI "bd:" + path 177 lfilename.remove(0,3); // e.g. "bd:/videos/ET" 396 178 397 uint openAttempts = 0; 398 do 179 if (QFile::exists(lfilename) || lfilename.startsWith("myth://")) 399 180 { 400 openAttempts++; 401 lasterror = 0; 402 QByteArray fname = filename.toLocal8Bit(); 403 fd2 = open(fname.constData(), 404 O_RDONLY|O_LARGEFILE|O_STREAMING|O_BINARY); 405 406 if (fd2 < 0) 407 { 408 if (!check_permissions(filename)) 409 { 410 lasterror = 3; 411 break; 412 } 413 414 lasterror = 1; 415 usleep(10 * 1000); 416 } 417 else 418 { 419 int ret = read(fd2, buf, kReadTestSize); 420 if (ret != (int)kReadTestSize) 421 { 422 lasterror = 2; 423 close(fd2); 424 fd2 = -1; 425 if (oldfile) 426 break; // if it's an old file it won't grow.. 427 usleep(10 * 1000); 428 } 429 else 430 { 431 if (0 == lseek(fd2, 0, SEEK_SET)) 432 { 433 posix_fadvise(fd2, 0, 0, POSIX_FADV_SEQUENTIAL); 434 posix_fadvise(fd2, 0, 1*1024*1024, POSIX_FADV_WILLNEED); 435 lasterror = 0; 436 break; 437 } 438 lasterror = 4; 439 close(fd2); 440 fd2 = -1; 441 } 442 } 181 VERBOSE(VB_PLAYBACK, "Trying BD at " + lfilename); 443 182 } 444 while ((uint)openTimer.elapsed() < retry_ms); 445 446 switch (lasterror) 183 else 447 184 { 448 case 0: 449 { 450 QFileInfo fi(filename); 451 oldfile = fi.lastModified() 452 .secsTo(QDateTime::currentDateTime()) > 60; 453 QString extension = fi.completeSuffix().toLower(); 454 if (is_subtitle_possible(extension)) 455 subtitlefilename = local_sub_filename(fi); 456 break; 457 } 458 case 1: 459 VERBOSE(VB_IMPORTANT, LOC_ERR + 460 QString("OpenFile(): Could not open.")); 461 break; 462 case 2: 463 VERBOSE(VB_IMPORTANT, LOC_ERR + 464 QString("OpenFile(): File too small (%1B).") 465 .arg(QFileInfo(filename).size())); 466 break; 467 case 3: 468 VERBOSE(VB_IMPORTANT, LOC_ERR + 469 "OpenFile(): Improper permissions."); 470 break; 471 case 4: 472 VERBOSE(VB_IMPORTANT, LOC_ERR + 473 "OpenFile(): Cannot seek in file."); 474 break; 475 default: 476 break; 185 lfilename = "/dev/dvd"; 477 186 } 478 VERBOSE(VB_FILE, LOC + QString("OpenFile() made %1 attempts in %2 ms")479 .arg(openAttempts).arg(openTimer.elapsed()));480 187 188 return new BDRingBuffer(lfilename); 481 189 } 482 #ifdef USING_FRONTEND483 else if (is_dvd)484 {485 dvdPriv->OpenFile(filename);486 readblocksize = DVD_BLOCK_SIZE * 62;487 }488 else if (is_bd)489 {490 bdPriv->OpenFile(filename);491 readblocksize = BD_BLOCK_SIZE * 62;492 }493 #endif // USING_FRONTEND494 else495 {496 QString tmpSubName = filename;497 QString dirName = ".";498 190 499 int dirPos = filename.lastIndexOf(QChar('/')); 500 if (dirPos > 0) 501 { 502 tmpSubName = filename.mid(dirPos + 1); 503 dirName = filename.left(dirPos); 504 } 191 return new FileRingBuffer( 192 lfilename, write, usereadahead, timeout_ms); 193 } 505 194 506 QString baseName = tmpSubName; 507 QString extension = tmpSubName; 508 QStringList auxFiles; 509 510 int suffixPos = tmpSubName.lastIndexOf(QChar('.')); 511 if (suffixPos > 0) 195 RingBuffer::RingBuffer(void) : 196 readpos(0), writepos(0), 197 internalreadpos(0), ignorereadpos(-1), 198 rbrpos(0), rbwpos(0), 199 stopreads(false), 200 filename(), subtitlefilename(), 201 tfw(NULL), fd2(-1), 202 writemode(false), remotefile(NULL), 203 startreadahead(false), readAheadBuffer(NULL), 204 readaheadrunning(false), reallyrunning(false), 205 request_pause(false), paused(false), 206 ateof(false), readsallowed(false), 207 setswitchtonext(false), 208 rawbitrate(8000), playspeed(1.0f), 209 fill_threshold(65536), fill_min(-1), 210 readblocksize(CHUNK), wanttoread(0), 211 numfailures(0), commserror(false), 212 oldfile(false), livetvchain(NULL), 213 ignoreliveeof(false), readAdjust(0) 214 { 215 { 216 QMutexLocker locker(&subExtLock); 217 if (subExt.empty()) 512 218 { 513 baseName = tmpSubName.left(suffixPos); 514 extension = tmpSubName.right(suffixPos-1); 515 if (is_subtitle_possible(extension)) 516 { 517 QMutexLocker locker(&subExtLock); 518 QStringList::const_iterator eit = subExt.begin(); 519 for (; eit != subExt.end(); eit++) 520 auxFiles += baseName + *eit; 521 } 522 } 219 // Possible subtitle file extensions '.srt', '.sub', '.txt' 220 subExt += ".srt"; 221 subExt += ".sub"; 222 subExt += ".txt"; 523 223 524 remotefile = new RemoteFile(filename, false, true, 525 retry_ms, &auxFiles); 526 if (!remotefile->isOpen()) 527 { 528 VERBOSE(VB_IMPORTANT, LOC_ERR + 529 QString("RingBuffer::RingBuffer(): Failed to open remote " 530 "file (%1)").arg(filename)); 531 delete remotefile; 532 remotefile = NULL; 224 // Extensions for which a subtitle file should not exist 225 subExtNoCheck = subExt; 226 subExtNoCheck += ".gif"; 227 subExtNoCheck += ".png"; 533 228 } 534 else535 {536 QStringList aux = remotefile->GetAuxiliaryFiles();537 if (aux.size())538 subtitlefilename = dirName + "/" + aux[0];539 }540 229 } 541 542 setswitchtonext = false;543 ateof = false;544 commserror = false;545 numfailures = 0;546 547 rawbitrate = 8000;548 CalcReadAheadThresh();549 550 rwlock.unlock();551 230 } 552 231 553 /** \fn RingBuffer::IsOpen(void) const554 * \brief Returns true if the file is open for either reading or writing.555 */556 bool RingBuffer::IsOpen(void) const557 {558 rwlock.lockForRead();559 bool ret;560 #ifdef USING_FRONTEND561 ret = tfw || (fd2 > -1) || remotefile || (dvdPriv && dvdPriv->IsOpen()) ||562 (bdPriv && bdPriv->IsOpen());563 #else // if !USING_FRONTEND564 ret = tfw || (fd2 > -1) || remotefile;565 #endif // !USING_FRONTEND566 rwlock.unlock();567 return ret;568 }569 570 232 /** \fn RingBuffer::~RingBuffer(void) 571 233 * \brief Shuts down any threads and closes any files. 572 234 */ … … 574 236 { 575 237 KillReadAheadThread(); 576 238 577 rwlock.lockForWrite();578 579 if (remotefile)580 {581 delete remotefile;582 remotefile = NULL;583 }584 585 if (tfw)586 {587 delete tfw;588 tfw = NULL;589 }590 591 if (fd2 >= 0)592 {593 close(fd2);594 fd2 = -1;595 }596 597 #ifdef USING_FRONTEND598 if (dvdPriv)599 {600 delete dvdPriv;601 }602 if (bdPriv)603 {604 delete bdPriv;605 }606 #endif // USING_FRONTEND607 608 239 if (readAheadBuffer) // this only runs if thread is terminated 609 240 { 610 241 delete [] readAheadBuffer; … … 653 284 rwlock.unlock(); 654 285 } 655 286 656 /** \fn RingBuffer::safe_read(int, void*, uint)657 * \brief Reads data from the file-descriptor.658 *659 * This will re-read the file forever until the660 * end-of-file is reached or the buffer is full.661 *662 * \param fd File descriptor to read from663 * \param data Pointer to where data will be written664 * \param sz Number of bytes to read665 * \return Returns number of bytes read666 */667 int RingBuffer::safe_read(int fd, void *data, uint sz)668 {669 int ret;670 unsigned tot = 0;671 unsigned errcnt = 0;672 unsigned zerocnt = 0;673 674 if (fd2 < 0)675 {676 VERBOSE(VB_IMPORTANT, LOC_ERR +677 "Invalid file descriptor in 'safe_read()'");678 return 0;679 }680 681 if (stopreads)682 return 0;683 684 while (tot < sz)685 {686 ret = read(fd2, (char *)data + tot, sz - tot);687 if (ret < 0)688 {689 if (errno == EAGAIN)690 continue;691 692 VERBOSE(VB_IMPORTANT,693 LOC_ERR + "File I/O problem in 'safe_read()'" + ENO);694 695 errcnt++;696 numfailures++;697 if (errcnt == 3)698 break;699 }700 else if (ret > 0)701 {702 tot += ret;703 }704 705 if (oldfile)706 break;707 708 if (ret == 0) // EOF returns 0709 {710 if (tot > 0)711 break;712 713 zerocnt++;714 715 // 0.36 second timeout for livetvchain with usleep(60000),716 // or 2.4 seconds if it's a new file less than 30 minutes old.717 if (zerocnt >= (livetvchain ? 6 : 40))718 {719 break;720 }721 }722 if (stopreads)723 break;724 if (tot < sz)725 usleep(60000);726 }727 return tot;728 }729 730 /** \fn RingBuffer::safe_read(RemoteFile*, void*, uint)731 * \brief Reads data from the RemoteFile.732 *733 * \param rf RemoteFile to read from734 * \param data Pointer to where data will be written735 * \param sz Number of bytes to read736 * \return Returns number of bytes read737 */738 int RingBuffer::safe_read(RemoteFile *rf, void *data, uint sz)739 {740 int ret = rf->Read(data, sz);741 if (ret < 0)742 {743 VERBOSE(VB_IMPORTANT, LOC_ERR +744 "RingBuffer::safe_read(RemoteFile* ...): read failed");745 746 poslock.lockForRead();747 rf->Seek(internalreadpos - readAdjust, SEEK_SET);748 poslock.unlock();749 numfailures++;750 }751 else if (ret == 0)752 {753 VERBOSE(VB_FILE, LOC +754 "RingBuffer::safe_read(RemoteFile* ...): at EOF");755 }756 757 return ret;758 }759 760 287 /** \fn RingBuffer::UpdateRawBitrate(uint) 761 288 * \brief Set the raw bit rate, to allow RingBuffer adjust effective bitrate. 762 289 * \param raw_bitrate Streams average number of kilobits per second when … … 1228 755 "Reading enough data to start playback"); 1229 756 } 1230 757 758 if (remotefile && livetvchain && livetvchain->HasNext()) 759 remotefile->SetTimeout(true); 760 1231 761 VERBOSE(VB_FILE|VB_EXTRA, 1232 762 LOC + QString("safe_read(...@%1, %2) -- begin") 1233 763 .arg(rbwpos).arg(totfree)); 1234 if (remotefile) 1235 { 1236 if (livetvchain && livetvchain->HasNext()) 1237 remotefile->SetTimeout(true); 1238 read_return = safe_read( 1239 remotefile, readAheadBuffer + rbwpos, totfree); 1240 } 1241 #ifdef USING_FRONTEND 1242 else if (dvdPriv) 1243 { 1244 read_return = dvdPriv->safe_read( 1245 readAheadBuffer + rbwpos, totfree); 1246 } 1247 else if (bdPriv) 1248 { 1249 read_return = bdPriv->safe_read( 1250 readAheadBuffer + rbwpos, totfree); 1251 } 1252 #endif // USING_FRONTEND 1253 else 1254 { 1255 read_return = safe_read(fd2, readAheadBuffer + rbwpos, totfree); 1256 } 764 765 read_return = safe_read(readAheadBuffer + rbwpos, totfree); 766 1257 767 VERBOSE(VB_FILE|VB_EXTRA, LOC + 1258 768 QString("safe_read(...@%1, %2) -> %3") 1259 769 .arg(rbwpos).arg(totfree).arg(read_return)); 770 1260 771 rbwlock.unlock(); 1261 772 } 1262 773 … … 1485 996 poslock.unlock(); 1486 997 } 1487 998 1488 int ret; 1489 if (remotefile) 1490 ret = safe_read(remotefile, buf, count); 1491 #ifdef USING_FRONTEND 1492 else if (dvdPriv) 1493 ret = dvdPriv->safe_read(buf, count); 1494 else if (bdPriv) 1495 ret = bdPriv->safe_read(buf, count); 1496 #endif // USING_FRONTEND 1497 else if (fd2 >= 0) 1498 ret = safe_read(fd2, buf, count); 1499 else 1500 { 1501 ret = -1; 1502 errno = EBADF; 1503 } 999 int ret = safe_read(buf, count); 1504 1000 1505 1001 poslock.lockForWrite(); 1506 1002 if (ignorereadpos >= 0 && ret > 0) … … 1527 1023 1528 1024 if (peek && ret > 0) 1529 1025 { 1530 if ( !dvdPriv && !bdPriv)1026 if ((IsDVD() || IsBD()) && old_pos != 0) 1531 1027 { 1532 long long new_pos = Seek(old_pos, SEEK_SET, true);1533 if (new_pos != old_pos)1534 {1535 VERBOSE(VB_IMPORTANT, LOC_ERR +1536 QString("Peek() Failed to return from new "1537 "position %1 to old position %2, now "1538 "at position %3")1539 .arg(old_pos - ret).arg(old_pos).arg(new_pos));1540 }1541 }1542 else if (old_pos != 0)1543 {1544 1028 VERBOSE(VB_IMPORTANT, LOC_ERR + 1545 1029 "DVD and Blu-Ray do not support arbitrary " 1546 1030 "peeks except when read-ahead is enabled." 1547 1031 "\n\t\t\tWill seek to beginning of video."); 1032 old_pos = 0; 1548 1033 } 1549 #ifdef USING_FRONTEND 1550 if (dvdPriv) 1551 dvdPriv->NormalSeek(old_pos); 1552 else if (bdPriv) 1553 bdPriv->Seek(old_pos); 1554 #endif // USING_FRONTEND 1034 1035 long long new_pos = Seek(old_pos, SEEK_SET, true); 1036 1037 if (new_pos != old_pos) 1038 { 1039 VERBOSE(VB_IMPORTANT, LOC_ERR + 1040 QString("Peek() Failed to return from new " 1041 "position %1 to old position %2, now " 1042 "at position %3") 1043 .arg(old_pos - ret).arg(old_pos).arg(new_pos)); 1044 } 1555 1045 } 1556 1046 1557 1047 return ret; … … 1777 1267 rwlock.unlock(); 1778 1268 } 1779 1269 1780 /** \brief Seeks to a particular position in the file.1781 */1782 long long RingBuffer::Seek(long long pos, int whence, bool has_lock)1783 {1784 VERBOSE(VB_FILE, LOC + QString("Seek(%1,%2,%3)")1785 .arg(pos).arg((SEEK_SET==whence)?"SEEK_SET":1786 ((SEEK_CUR==whence)?"SEEK_CUR":"SEEK_END"))1787 .arg(has_lock?"locked":"unlocked"));1788 1789 long long ret = -1;1790 1791 StopReads();1792 1793 // lockForWrite takes priority over lockForRead, so this will1794 // take priority over the lockForRead in the read ahead thread.1795 if (!has_lock)1796 rwlock.lockForWrite();1797 1798 StartReads();1799 1800 if (writemode)1801 {1802 ret = WriterSeek(pos, whence, true);1803 if (!has_lock)1804 rwlock.unlock();1805 return ret;1806 }1807 1808 poslock.lockForWrite();1809 1810 // Optimize no-op seeks1811 if (readaheadrunning &&1812 ((whence == SEEK_SET && pos == readpos) ||1813 (whence == SEEK_CUR && pos == 0)))1814 {1815 ret = readpos;1816 1817 poslock.unlock();1818 if (!has_lock)1819 rwlock.unlock();1820 1821 return ret;1822 }1823 1824 // only valid for SEEK_SET & SEEK_CUR1825 long long new_pos = (SEEK_SET==whence) ? pos : readpos + pos;1826 1827 #if 11828 // Optimize short seeks where the data for1829 // them is in our ringbuffer already.1830 if (readaheadrunning &&1831 (SEEK_SET==whence || SEEK_CUR==whence))1832 {1833 rbrlock.lockForWrite();1834 rbwlock.lockForRead();1835 VERBOSE(VB_FILE, LOC +1836 QString("Seek(): rbrpos: %1 rbwpos: %2"1837 "\n\t\t\treadpos: %3 internalreadpos: %4")1838 .arg(rbrpos).arg(rbwpos)1839 .arg(readpos).arg(internalreadpos));1840 bool used_opt = false;1841 if ((new_pos < readpos))1842 {1843 int min_safety = max(fill_min, readblocksize);1844 int free = ((rbwpos >= rbrpos) ?1845 rbrpos + kBufferSize : rbrpos) - rbwpos;1846 int internal_backbuf =1847 (rbwpos >= rbrpos) ? rbrpos : rbrpos - rbwpos;1848 internal_backbuf = min(internal_backbuf, free - min_safety);1849 long long sba = readpos - new_pos;1850 VERBOSE(VB_FILE, LOC +1851 QString("Seek(): internal_backbuf: %1 sba: %2")1852 .arg(internal_backbuf).arg(sba));1853 if (internal_backbuf >= sba)1854 {1855 rbrpos = (rbrpos>=sba) ? rbrpos - sba :1856 kBufferSize + rbrpos - sba;1857 used_opt = true;1858 VERBOSE(VB_FILE, LOC +1859 QString("Seek(): OPT1 rbrpos: %1 rbwpos: %2"1860 "\n\t\t\treadpos: %3 internalreadpos: %4")1861 .arg(rbrpos).arg(rbwpos)1862 .arg(new_pos).arg(internalreadpos));1863 }1864 }1865 else if ((new_pos >= readpos) && (new_pos <= internalreadpos))1866 {1867 rbrpos = (rbrpos + (new_pos - readpos)) % kBufferSize;1868 used_opt = true;1869 VERBOSE(VB_FILE, LOC +1870 QString("Seek(): OPT2 rbrpos: %1 sba: %2")1871 .arg(rbrpos).arg(readpos - new_pos));1872 }1873 rbwlock.unlock();1874 rbrlock.unlock();1875 1876 if (used_opt)1877 {1878 if (ignorereadpos >= 0)1879 {1880 // seek should always succeed since we were at this position1881 int ret;1882 if (remotefile)1883 ret = remotefile->Seek(internalreadpos, SEEK_SET);1884 else1885 {1886 ret = lseek64(fd2, internalreadpos, SEEK_SET);1887 posix_fadvise(fd2, 0,1888 internalreadpos, POSIX_FADV_DONTNEED);1889 posix_fadvise(fd2, internalreadpos,1890 1*1024*1024, POSIX_FADV_WILLNEED);1891 }1892 VERBOSE(VB_FILE, LOC +1893 QString("Seek to %1 from ignore pos %2 returned %3")1894 .arg(internalreadpos).arg(ignorereadpos).arg(ret));1895 ignorereadpos = -1;1896 }1897 readpos = new_pos;1898 poslock.unlock();1899 generalWait.wakeAll();1900 ateof = false;1901 readsallowed = false;1902 if (!has_lock)1903 rwlock.unlock();1904 return new_pos;1905 }1906 }1907 #endif1908 1909 #if 11910 // This optimizes the seek end-250000, read, seek 0, read portion1911 // of the pattern ffmpeg performs at the start of playback to1912 // determine the pts.1913 // If the seek is a SEEK_END or is a seek where the position1914 // changes over 100 MB we check the file size and if the1915 // destination point is within 300000 bytes of the end of1916 // the file we enter a special mode where the read ahead1917 // buffer stops reading data and all reads are made directly1918 // until another seek is performed. The point of all this is1919 // to avoid flushing out the buffer that still contains all1920 // the data the final seek 0, read will need just to read the1921 // last 250000 bytes. A further optimization would be to buffer1922 // the 250000 byte read, which is currently performed in 32KB1923 // blocks (inefficient with RemoteFile).1924 if ((remotefile || fd2 >= 0) && (ignorereadpos < 0))1925 {1926 long long off_end = 0xDEADBEEF;1927 if (SEEK_END == whence)1928 {1929 off_end = pos;1930 if (remotefile)1931 {1932 new_pos = remotefile->GetFileSize() - off_end;1933 }1934 else1935 {1936 QFileInfo fi(filename);1937 new_pos = fi.size() - off_end;1938 }1939 }1940 else1941 {1942 if (remotefile)1943 {1944 off_end = remotefile->GetFileSize() - new_pos;1945 }1946 else1947 {1948 QFileInfo fi(filename);1949 off_end = fi.size() - new_pos;1950 }1951 }1952 1953 if (off_end != 0xDEADBEEF)1954 {1955 VERBOSE(VB_FILE, LOC +1956 QString("Seek(): Offset from end: %1").arg(off_end));1957 }1958 1959 if (off_end <= 250000)1960 {1961 VERBOSE(VB_FILE, LOC +1962 QString("Seek(): offset from end: %1").arg(off_end) +1963 "\n\t\t\t -- ignoring read ahead thread until next seek.");1964 1965 ignorereadpos = new_pos;1966 errno = EINVAL;1967 long long ret;1968 if (remotefile)1969 ret = remotefile->Seek(ignorereadpos, SEEK_SET);1970 else1971 {1972 ret = lseek64(fd2, ignorereadpos, SEEK_SET);1973 posix_fadvise(fd2, ignorereadpos, 250000, POSIX_FADV_WILLNEED);1974 }1975 1976 if (ret < 0)1977 {1978 int tmp_eno = errno;1979 QString cmd = QString("Seek(%1, SEEK_SET) ign ")1980 .arg(ignorereadpos);1981 1982 ignorereadpos = -1;1983 1984 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);1985 1986 // try to return to former position..1987 if (remotefile)1988 ret = remotefile->Seek(internalreadpos, SEEK_SET);1989 else1990 ret = lseek64(fd2, internalreadpos, SEEK_SET);1991 if (ret < 0)1992 {1993 QString cmd = QString("Seek(%1, SEEK_SET) int ")1994 .arg(internalreadpos);1995 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);1996 }1997 else1998 {1999 QString cmd = QString("Seek(%1, %2) int ")2000 .arg(internalreadpos)2001 .arg((SEEK_SET == whence) ? "SEEK_SET" :2002 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));2003 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " succeeded");2004 }2005 ret = -1;2006 errno = tmp_eno;2007 }2008 else2009 {2010 ateof = false;2011 readsallowed = false;2012 }2013 2014 rbwlock.unlock();2015 rbrlock.unlock();2016 poslock.unlock();2017 2018 generalWait.wakeAll();2019 2020 if (!has_lock)2021 rwlock.unlock();2022 2023 return ret;2024 }2025 }2026 #endif2027 2028 // Here we perform a normal seek. When successful we2029 // need to call ResetReadAhead(). A reset means we will2030 // need to refill the buffer, which takes some time.2031 if (remotefile)2032 {2033 ret = remotefile->Seek(pos, whence, readpos);2034 if (ret<0)2035 errno = EINVAL;2036 }2037 #ifdef USING_FRONTEND2038 else if ((dvdPriv || bdPriv) && (SEEK_END == whence))2039 {2040 errno = EINVAL;2041 ret = -1;2042 }2043 else if (dvdPriv)2044 {2045 dvdPriv->NormalSeek(new_pos);2046 ret = new_pos;2047 }2048 else if (bdPriv)2049 {2050 bdPriv->Seek(new_pos);2051 ret = new_pos;2052 }2053 #endif // USING_FRONTEND2054 else2055 {2056 ret = lseek64(fd2, pos, whence);2057 if (ret >= 0)2058 {2059 posix_fadvise(fd2, 0, ret, POSIX_FADV_DONTNEED);2060 posix_fadvise(fd2, ret, 1*1024*1024, POSIX_FADV_WILLNEED);2061 }2062 }2063 2064 if (ret >= 0)2065 {2066 readpos = ret;2067 2068 ignorereadpos = -1;2069 2070 if (readaheadrunning)2071 ResetReadAhead(readpos);2072 2073 readAdjust = 0;2074 }2075 else2076 {2077 QString cmd = QString("Seek(%1, %2)").arg(pos)2078 .arg((SEEK_SET == whence) ? "SEEK_SET" :2079 ((SEEK_CUR == whence) ?"SEEK_CUR" : "SEEK_END"));2080 VERBOSE(VB_IMPORTANT, LOC_ERR + cmd + " Failed" + ENO);2081 }2082 2083 poslock.unlock();2084 2085 generalWait.wakeAll();2086 2087 if (!has_lock)2088 rwlock.unlock();2089 2090 return ret;2091 }2092 2093 1270 /** \brief Calls ThreadedFileWriter::Seek(long long,int). 2094 1271 */ 2095 1272 long long RingBuffer::WriterSeek(long long pos, int whence, bool has_lock) … … 2174 1351 rwlock.unlock(); 2175 1352 } 2176 1353 2177 // This appears to allow direct access to the DVD/BD device2178 // when called with false (the default value), and enable2179 // the ring buffer when called with true. But I'm not entirely2180 // certain. -- dtk 2010-08-262181 void RingBuffer::SetStreamOnly(bool stream)2182 {2183 rwlock.lockForWrite();2184 streamOnly = stream;2185 rwlock.unlock();2186 }2187 2188 1354 /// Returns name of file used by this RingBuffer 2189 1355 QString RingBuffer::GetFilename(void) const 2190 1356 { 2191 1357 rwlock.lockForRead(); 2192 1358 QString tmp = filename; 2193 tmp.detach();2194 1359 rwlock.unlock(); 2195 1360 return tmp; 2196 1361 } … … 2199 1364 { 2200 1365 rwlock.lockForRead(); 2201 1366 QString tmp = subtitlefilename; 2202 tmp.detach();2203 1367 rwlock.unlock(); 2204 1368 return tmp; 2205 1369 } 2206 1370 2207 /** \fn RingBuffer::GetReadPosition(void) const2208 * \brief Returns how far into the file we have read.2209 */2210 long long RingBuffer::GetReadPosition(void) const2211 {2212 rwlock.lockForRead();2213 poslock.lockForRead();2214 long long ret = readpos;2215 #ifdef USING_FRONTEND2216 if (dvdPriv)2217 ret = dvdPriv->GetReadPosition();2218 else if (bdPriv)2219 ret = bdPriv->GetReadPosition();2220 #endif // USING_FRONTEND2221 poslock.unlock();2222 rwlock.unlock();2223 return ret;2224 }2225 2226 1371 /** \fn RingBuffer::GetWritePosition(void) const 2227 1372 * \brief Returns how far into a ThreadedFileWriter file we have written. 2228 1373 */ … … 2234 1379 return ret; 2235 1380 } 2236 1381 2237 /** \fn RingBuffer::GetRealFileSize(void) const2238 * \brief Returns the size of the file we are reading/writing,2239 * or -1 if the query fails.2240 */2241 long long RingBuffer::GetRealFileSize(void) const2242 {2243 rwlock.lockForRead();2244 long long ret = -1;2245 if (remotefile)2246 ret = remotefile->GetFileSize();2247 else2248 ret = QFileInfo(filename).size();2249 rwlock.unlock();2250 return ret;2251 }2252 2253 1382 /** \fn RingBuffer::LiveMode(void) const 2254 1383 * \brief Returns true if this RingBuffer has been assigned a LiveTVChain. 2255 1384 * \sa SetLiveMode(LiveTVChain*) … … 2281 1410 rwlock.unlock(); 2282 1411 } 2283 1412 2284 /** \brief Returns true if this is a DVD backed RingBuffer. 2285 * 2286 * NOTE: This is not locked because ReadDirect calls 2287 * DVD safe_read which sleeps with a write lock on 2288 * rwlock in the DVDNAV_WAIT condition. 2289 * 2290 * Due to the lack of locking is only safe to call once OpenFile() 2291 * has completed. 2292 */ 2293 bool RingBuffer::IsDVD(void) const 1413 const DVDRingBuffer *RingBuffer::DVD(void) const 2294 1414 { 2295 //rwlock.lockForRead(); 2296 bool ret = dvdPriv; 2297 //rwlock.unlock(); 2298 return ret; 1415 return dynamic_cast<const DVDRingBuffer*>(this); 2299 1416 } 2300 1417 2301 /** \brief Returns true if this is a DVD backed RingBuffer. 2302 * 2303 * NOTE: This is not locked because ReadDirect calls 2304 * DVD safe_read which sleeps with a write lock on 2305 * rwlock in the DVDNAV_WAIT condition. 2306 * 2307 * Due to the lack of locking is only safe to call once OpenFile() 2308 * has completed. 2309 */ 2310 bool RingBuffer::InDiscMenuOrStillFrame(void) 1418 const BDRingBuffer *RingBuffer::BD(void) const 2311 1419 { 2312 //rwlock.lockForRead(); 2313 bool ret = false; 2314 #ifdef USING_FRONTEND 2315 if (dvdPriv) 2316 ret = (dvdPriv->IsInMenu() || dvdPriv->InStillFrame()); 2317 else if (bdPriv) 2318 ret = (bdPriv->IsInMenu() || bdPriv->InStillFrame()); 2319 #endif // USING_FRONTEND 2320 //rwlock.unlock(); 2321 return ret; 1420 return dynamic_cast<const BDRingBuffer*>(this); 2322 1421 } 2323 1422 2324 /// Returns true if this is a Blu-ray backed RingBuffer. 2325 bool RingBuffer::IsBD(void) const 1423 DVDRingBuffer *RingBuffer::DVD(void) 2326 1424 { 2327 //rwlock.lockForRead(); 2328 bool ret = bdPriv; 2329 //rwlock.unlock(); 2330 return ret; 1425 return dynamic_cast<DVDRingBuffer*>(this); 2331 1426 } 2332 1427 1428 BDRingBuffer *RingBuffer::BD(void) 1429 { 1430 return dynamic_cast<BDRingBuffer*>(this); 1431 } 1432 2333 1433 /* vim: set expandtab tabstop=4 shiftwidth=4: */ -
libs/libmythtv/DVDRingBuffer.h
10 10 #include <QMutex> 11 11 #include <QRect> 12 12 13 #include "RingBuffer.h" 13 14 #include "util.h" 15 14 16 extern "C" { 15 17 #include "libavcodec/avcodec.h" 16 18 } … … 25 27 26 28 class MythDVDPlayer; 27 29 28 class MPUBLIC DVDRingBuffer Priv30 class MPUBLIC DVDRingBuffer : public RingBuffer 29 31 { 30 32 public: 31 DVDRingBuffer Priv();32 virtual ~DVDRingBuffer Priv();33 DVDRingBuffer(const QString &lfilename); 34 virtual ~DVDRingBuffer(); 33 35 34 36 // gets 35 37 int GetTitle(void) const { return m_title; } … … 38 40 int GetCurrentAngle(void) const { return m_currentAngle; }; 39 41 int GetNumAngles(void) { return m_currentTitleAngleCount; }; 40 42 bool IsOpen(void) const { return m_dvdnav; } 41 long long GetReadPosition(void);43 virtual long long GetReadPosition(void) const; 42 44 long long GetTotalReadPosition(void) { return m_titleLength; } 43 45 void GetDescForPos(QString &desc); 44 46 void GetPartAndTitle(int &_part, int &_title) const … … 48 50 uint GetCellStart(void); 49 51 bool PGCLengthChanged(void); 50 52 bool CellChanged(void); 51 bool I nStillFrame(void) const { return m_still > 0; }52 bool NeedsStillFrame(void) { return I nStillFrame() || NewSequence(); }53 bool IsInStillFrame(void) const { return m_still > 0; } 54 bool NeedsStillFrame(void) { return IsInStillFrame() || NewSequence(); } 53 55 bool NewSequence(bool new_sequence = false); 54 56 bool AudioStreamsChanged(void) const { return m_audioStreamsChanged; } 55 57 bool IsWaiting(void) const { return m_dvdWaiting; } 56 58 int NumPartsInTitle(void) const { return m_titleParts; } 57 59 void GetMenuSPUPkt(uint8_t *buf, int len, int stream_id); 60 virtual bool IsInDiscMenuOrStillFrame(void) const 61 { return IsInMenu() || IsInStillFrame(); } // RingBuffer 58 62 59 63 // Public menu/button stuff 60 64 AVSubtitle *GetMenuSubtitle(uint &version); 61 65 int NumMenuButtons(void) const; 62 66 QRect GetButtonCoords(void); 63 67 void ReleaseMenuButton(void); 64 bool IsInMenu(void) { return m_inMenu; }68 bool IsInMenu(void) const { return m_inMenu; } 65 69 void ActivateButton(void); 66 70 void MoveButtonLeft(void); 67 71 void MoveButtonRight(void); … … 85 89 (m_titleParts == 1)); } 86 90 87 91 // commands 88 bool OpenFile(const QString &filename); 92 virtual bool OpenFile(const QString &lfilename, 93 uint retry_ms = kDefaultOpenTimeout); // RingBuffer 89 94 void PlayTitleAndPart(int _title, int _part) 90 95 { dvdnav_part_play(m_dvdnav, _title, _part); } 91 96 bool StartFromBeginning(void); 92 97 void CloseDVD(void); 93 98 bool nextTrack(void); 94 99 void prevTrack(void); 95 int safe_read(void *data, unsigned sz); 100 virtual int safe_read(void *data, uint sz); // RingBuffer 101 virtual long long Seek(long long pos, int whence, bool has_lock); 96 102 long long NormalSeek(long long time); 97 103 void SkipStillFrame(void); 98 104 void WaitSkip(void); … … 118 124 dvdnav_t *m_dvdnav; 119 125 unsigned char m_dvdBlockWriteBuf[DVD_BLOCK_SIZE]; 120 126 unsigned char *m_dvdBlockReadBuf; 121 QString m_dvdFilename;122 127 int m_dvdBlockRPos; 123 128 int m_dvdBlockWPos; 124 129 long long m_pgLength; -
libs/libmythtv/tv_play.cpp
2038 2038 "cardtype(%2)") 2039 2039 .arg(playbackURL).arg(ctx->tvchain->GetCardType(-1))); 2040 2040 2041 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 2042 opennow ? RingBuffer::kLiveTVOpenTimeout : -1)); 2041 ctx->SetRingBuffer( 2042 RingBuffer::Create( 2043 playbackURL, false, true, 2044 opennow ? RingBuffer::kLiveTVOpenTimeout : -1)); 2045 2043 2046 ctx->buffer->SetLiveMode(ctx->tvchain); 2044 2047 } 2045 2048 … … 2113 2116 } 2114 2117 ctx->UnlockPlayingInfo(__FILE__, __LINE__); 2115 2118 2116 ctx->SetRingBuffer( new RingBuffer(playbackURL, false));2119 ctx->SetRingBuffer(RingBuffer::Create(playbackURL, false)); 2117 2120 2118 2121 if (ctx->buffer && ctx->buffer->IsOpen()) 2119 2122 { … … 2239 2242 ITVRestart(ctx, false); 2240 2243 } 2241 2244 2242 if (ctx->buffer && ctx->buffer-> isDVD())2245 if (ctx->buffer && ctx->buffer->IsDVD()) 2243 2246 { 2244 2247 UpdateLCD(); 2245 2248 } … … 2367 2370 2368 2371 SetActive(mctx, 0, false); 2369 2372 2370 if (ctx->buffer && ctx->buffer-> isDVD())2373 if (ctx->buffer && ctx->buffer->IsDVD()) 2371 2374 { 2372 2375 VERBOSE(VB_PLAYBACK,LOC + " StopStuff() -- " 2373 2376 "get dvd player out of still frame or wait status"); … … 3062 3065 if (StateIsLiveTV(GetState(actx))) 3063 3066 ShowLCDChannelInfo(actx); 3064 3067 3065 if (actx->buffer && actx->buffer-> isDVD())3068 if (actx->buffer && actx->buffer->IsDVD()) 3066 3069 { 3067 3070 ShowLCDDVDInfo(actx); 3068 showProgress = !actx->buffer->I nDiscMenuOrStillFrame();3071 showProgress = !actx->buffer->IsInDiscMenuOrStillFrame(); 3069 3072 } 3070 3073 3071 3074 if (showProgress) … … 3735 3738 3736 3739 handled = false; 3737 3740 3738 bool isDVD = actx->buffer && actx->buffer->isDVD(); 3739 bool isDVDStill = isDVD && actx->buffer->InDiscMenuOrStillFrame(); 3740 bool isBD = actx->buffer && actx->buffer->isBD(); 3741 bool isBDStill = isBD && actx->buffer->InDiscMenuOrStillFrame(); 3741 bool isDVD = actx->buffer && actx->buffer->IsDVD(); 3742 bool isMenuOrStill = actx->buffer->IsInDiscMenuOrStillFrame(); 3742 3743 3743 3744 handled = handled || BrowseHandleAction(actx, actions); 3744 3745 handled = handled || ManualZoomHandleAction(actx, actions); 3745 3746 handled = handled || PictureAttributeHandleAction(actx, actions); 3746 3747 handled = handled || TimeStretchHandleAction(actx, actions); 3747 3748 handled = handled || AudioSyncHandleAction(actx, actions); 3748 handled = handled || DiscMenuHandleAction(actx, actions, isDVD, isDVDStill, isBD); 3749 handled = handled || ActiveHandleAction(actx, actions, isDVD, isDVDStill); 3749 handled = handled || DiscMenuHandleAction(actx, actions); 3750 handled = handled || ActiveHandleAction( 3751 actx, actions, isDVD, isMenuOrStill); 3750 3752 handled = handled || ToggleHandleAction(actx, actions, isDVD); 3751 3753 handled = handled || PxPHandleAction(actx, actions); 3752 3754 handled = handled || FFRewHandleAction(actx, actions); … … 3972 3974 return handled; 3973 3975 } 3974 3976 3975 bool TV::DiscMenuHandleAction(PlayerContext *ctx, 3976 const QStringList &actions, 3977 bool isDVD, bool isDVDStill, 3978 bool isBD) 3977 bool TV::DiscMenuHandleAction(PlayerContext *ctx, const QStringList &actions) 3979 3978 { 3980 3979 bool handled = false; 3980 DVDRingBuffer *dvdrb = ctx->buffer->DVD(); 3981 BDRingBuffer *bdrb = ctx->buffer->BD(); 3981 3982 3982 if ( isDVD)3983 if (dvdrb) 3983 3984 { 3984 int nb_buttons = ctx->buffer->DVD()->NumMenuButtons();3985 int nb_buttons = dvdrb->NumMenuButtons(); 3985 3986 if (nb_buttons == 0) 3986 3987 return false; 3987 3988 … … 3989 3990 if (has_action("UP", actions) || 3990 3991 has_action("CHANNELUP", actions)) 3991 3992 { 3992 ctx->buffer->DVD()->MoveButtonUp();3993 dvdrb->MoveButtonUp(); 3993 3994 } 3994 3995 else if (has_action("DOWN", actions) || 3995 3996 has_action("CHANNELDOWN", actions)) 3996 3997 { 3997 ctx->buffer->DVD()->MoveButtonDown();3998 dvdrb->MoveButtonDown(); 3998 3999 } 3999 4000 else if (has_action("LEFT", actions) || 4000 4001 has_action("SEEKRWND", actions)) 4001 4002 { 4002 ctx->buffer->DVD()->MoveButtonLeft();4003 dvdrb->MoveButtonLeft(); 4003 4004 } 4004 4005 else if (has_action("RIGHT", actions) || 4005 4006 has_action("SEEKFFWD", actions)) 4006 4007 { 4007 ctx->buffer->DVD()->MoveButtonRight();4008 dvdrb->MoveButtonRight(); 4008 4009 } 4009 4010 else if (has_action("SELECT", actions)) 4010 4011 { 4011 4012 ctx->LockDeletePlayer(__FILE__, __LINE__); 4012 ctx->buffer->DVD()->ActivateButton();4013 dvdrb->ActivateButton(); 4013 4014 ctx->UnlockDeletePlayer(__FILE__, __LINE__); 4014 4015 } 4015 4016 else 4016 4017 handled = false; 4017 4018 } 4018 if (isBD)4019 else if (bdrb) 4019 4020 { 4020 4021 int64_t pts = 0; 4021 4022 VideoOutput *output = ctx->player->getVideoOutput(); … … 4033 4034 if (has_action("UP", actions) || 4034 4035 has_action("CHANNELUP", actions)) 4035 4036 { 4036 ctx->buffer->BD()->PressButton(BD_VK_UP, pts);4037 bdrb->PressButton(BD_VK_UP, pts); 4037 4038 } 4038 4039 else if (has_action("DOWN", actions) || 4039 4040 has_action("CHANNELDOWN", actions)) 4040 4041 { 4041 ctx->buffer->BD()->PressButton(BD_VK_DOWN, pts);4042 bdrb->PressButton(BD_VK_DOWN, pts); 4042 4043 } 4043 4044 else if (has_action("LEFT", actions) || 4044 4045 has_action("SEEKRWND", actions)) 4045 4046 { 4046 ctx->buffer->BD()->PressButton(BD_VK_LEFT, pts);4047 bdrb->PressButton(BD_VK_LEFT, pts); 4047 4048 } 4048 4049 else if (has_action("RIGHT", actions) || 4049 4050 has_action("SEEKFFWD", actions)) 4050 4051 { 4051 ctx->buffer->BD()->PressButton(BD_VK_RIGHT, pts);4052 bdrb->PressButton(BD_VK_RIGHT, pts); 4052 4053 } 4053 4054 else if (has_action("MENUTEXT", actions)) 4054 4055 { 4055 ctx->buffer->BD()->PressButton(BD_VK_POPUP, pts);4056 bdrb->PressButton(BD_VK_POPUP, pts); 4056 4057 } 4057 4058 else if (has_action("0", actions)) 4058 4059 { 4059 ctx->buffer->BD()->PressButton(BD_VK_0, pts);4060 bdrb->PressButton(BD_VK_0, pts); 4060 4061 } 4061 4062 else if (has_action("1", actions)) 4062 4063 { 4063 ctx->buffer->BD()->PressButton(BD_VK_1, pts);4064 bdrb->PressButton(BD_VK_1, pts); 4064 4065 } 4065 4066 else if (has_action("2", actions)) 4066 4067 { 4067 ctx->buffer->BD()->PressButton(BD_VK_2, pts);4068 bdrb->PressButton(BD_VK_2, pts); 4068 4069 } 4069 4070 else if (has_action("3", actions)) 4070 4071 { 4071 ctx->buffer->BD()->PressButton(BD_VK_3, pts);4072 bdrb->PressButton(BD_VK_3, pts); 4072 4073 } 4073 4074 else if (has_action("4", actions)) 4074 4075 { 4075 ctx->buffer->BD()->PressButton(BD_VK_4, pts);4076 bdrb->PressButton(BD_VK_4, pts); 4076 4077 } 4077 4078 else if (has_action("5", actions)) 4078 4079 { 4079 ctx->buffer->BD()->PressButton(BD_VK_5, pts);4080 bdrb->PressButton(BD_VK_5, pts); 4080 4081 } 4081 4082 else if (has_action("6", actions)) 4082 4083 { 4083 ctx->buffer->BD()->PressButton(BD_VK_6, pts);4084 bdrb->PressButton(BD_VK_6, pts); 4084 4085 } 4085 4086 else if (has_action("7", actions)) 4086 4087 { 4087 ctx->buffer->BD()->PressButton(BD_VK_7, pts);4088 bdrb->PressButton(BD_VK_7, pts); 4088 4089 } 4089 4090 else if (has_action("8", actions)) 4090 4091 { 4091 ctx->buffer->BD()->PressButton(BD_VK_8, pts);4092 bdrb->PressButton(BD_VK_8, pts); 4092 4093 } 4093 4094 else if (has_action("9", actions)) 4094 4095 { 4095 ctx->buffer->BD()->PressButton(BD_VK_9, pts);4096 bdrb->PressButton(BD_VK_9, pts); 4096 4097 } 4097 4098 else if (has_action("SELECT", actions)) 4098 4099 { 4099 ctx->buffer->BD()->PressButton(BD_VK_ENTER, pts);4100 bdrb->PressButton(BD_VK_ENTER, pts); 4100 4101 } 4101 4102 else 4102 4103 handled = false; … … 4814 4815 } 4815 4816 else if (tokens.size() >= 3 && tokens[1] == "SEEK" && ctx->HasPlayer()) 4816 4817 { 4817 if (ctx->buffer && ctx->buffer->I nDiscMenuOrStillFrame())4818 if (ctx->buffer && ctx->buffer->IsInDiscMenuOrStillFrame()) 4818 4819 return; 4819 4820 4820 4821 ctx->LockDeletePlayer(__FILE__, __LINE__); … … 4929 4930 } 4930 4931 else 4931 4932 { 4932 if (ctx->buffer-> isDVD())4933 if (ctx->buffer->IsDVD()) 4933 4934 infoStr = "DVD"; 4934 4935 else if (ctx->playingInfo->IsRecording()) 4935 4936 infoStr = "Recorded"; … … 5753 5754 if (!ctx) 5754 5755 return 0.0f; 5755 5756 5756 if (ctx->buffer && ctx->buffer->I nDiscMenuOrStillFrame())5757 if (ctx->buffer && ctx->buffer->IsInDiscMenuOrStillFrame()) 5757 5758 return 0.0f; 5758 5759 5759 5760 ctx->ff_rew_speed = 0; … … 5792 5793 if (!ctx || !ctx->HasPlayer()) 5793 5794 return; 5794 5795 5795 if (ctx->buffer && ctx->buffer->I nDiscMenuOrStillFrame())5796 if (ctx->buffer && ctx->buffer->IsInDiscMenuOrStillFrame()) 5796 5797 return; 5797 5798 5798 5799 if (ctx->paused) … … 6585 6586 ctx->LockPlayingInfo(__FILE__, __LINE__); 6586 6587 QString playbackURL = ctx->playingInfo->GetPlaybackURL(true); 6587 6588 bool opennow = (ctx->tvchain->GetCardType(-1) != "DUMMY"); 6588 ctx->SetRingBuffer(new RingBuffer(playbackURL, false, true, 6589 opennow ? RingBuffer::kLiveTVOpenTimeout : -1)); 6589 ctx->SetRingBuffer( 6590 RingBuffer::Create( 6591 playbackURL, false, true, 6592 opennow ? RingBuffer::kLiveTVOpenTimeout : -1)); 6590 6593 6591 6594 ctx->tvchain->SetProgram(*ctx->playingInfo); 6592 6595 ctx->buffer->SetLiveMode(ctx->tvchain); … … 7647 7650 { 7648 7651 class LCD * lcd = LCD::Get(); 7649 7652 7650 if (!lcd || !ctx->buffer || !ctx->buffer-> isDVD())7653 if (!lcd || !ctx->buffer || !ctx->buffer->IsDVD()) 7651 7654 { 7652 7655 return; 7653 7656 } 7654 7657 7655 DVDRingBuffer Priv*dvd = ctx->buffer->DVD();7658 DVDRingBuffer *dvd = ctx->buffer->DVD(); 7656 7659 QString dvdName, dvdSerial; 7657 7660 QString mainStatus, subStatus; 7658 7661 … … 7660 7663 { 7661 7664 dvdName = tr("DVD"); 7662 7665 } 7666 7663 7667 if (dvd->IsInMenu()) 7668 { 7664 7669 mainStatus = tr("Menu"); 7665 else if (dvd->InStillFrame()) 7670 } 7671 else if (dvd->IsInStillFrame()) 7672 { 7666 7673 mainStatus = tr("Still Frame"); 7674 } 7667 7675 else 7668 7676 { 7669 7677 QString timeMins, timeHrsMin; … … 11480 11488 */ 11481 11489 void TV::DVDJumpBack(PlayerContext *ctx) 11482 11490 { 11483 if (!ctx->HasPlayer() || !ctx->buffer || !ctx->buffer->isDVD()) 11491 DVDRingBuffer *dvdrb = dynamic_cast<DVDRingBuffer*>(ctx->buffer); 11492 if (!ctx->HasPlayer() || !dvdrb) 11484 11493 return; 11485 11494 11486 if (ctx->buffer->I nDiscMenuOrStillFrame())11495 if (ctx->buffer->IsInDiscMenuOrStillFrame()) 11487 11496 { 11488 11497 UpdateOSDSeekMessage(ctx, tr("Skip Back Not Allowed"), kOSDTimeout_Med); 11489 11498 } 11490 else if (! ctx->buffer->DVD()->StartOfTitle())11499 else if (!dvdrb->StartOfTitle()) 11491 11500 { 11492 11501 ctx->LockDeletePlayer(__FILE__, __LINE__); 11493 11502 if (ctx->player) … … 11497 11506 } 11498 11507 else 11499 11508 { 11500 uint titleLength = ctx->buffer->DVD()->GetTotalTimeOfTitle();11501 uint chapterLength = ctx->buffer->DVD()->GetChapterLength();11509 uint titleLength = dvdrb->GetTotalTimeOfTitle(); 11510 uint chapterLength = dvdrb->GetChapterLength(); 11502 11511 if ((titleLength == chapterLength) && chapterLength > 300) 11503 11512 { 11504 11513 DoSeek(ctx, -ctx->jumptime * 60, tr("Jump Back")); … … 11520 11529 */ 11521 11530 void TV::DVDJumpForward(PlayerContext *ctx) 11522 11531 { 11523 if (!ctx->HasPlayer() || !ctx->buffer || !ctx->buffer->isDVD()) 11532 DVDRingBuffer *dvdrb = dynamic_cast<DVDRingBuffer*>(ctx->buffer); 11533 if (!ctx->HasPlayer() || !dvdrb) 11524 11534 return; 11525 11535 11526 bool in_still = ctx->buffer->DVD()->InStillFrame();11527 bool in_menu = ctx->buffer->DVD()->IsInMenu();11528 if (in_still && ! ctx->buffer->DVD()->NumMenuButtons())11536 bool in_still = dvdrb->IsInStillFrame(); 11537 bool in_menu = dvdrb->IsInMenu(); 11538 if (in_still && !dvdrb->NumMenuButtons()) 11529 11539 { 11530 ctx->buffer->DVD()->SkipStillFrame();11540 dvdrb->SkipStillFrame(); 11531 11541 UpdateOSDSeekMessage(ctx, tr("Skip Still Frame"), kOSDTimeout_Med); 11532 11542 } 11533 else if (! ctx->buffer->DVD()->EndOfTitle() && !in_still && !in_menu)11543 else if (!dvdrb->EndOfTitle() && !in_still && !in_menu) 11534 11544 { 11535 11545 ctx->LockDeletePlayer(__FILE__, __LINE__); 11536 11546 if (ctx->player) … … 11541 11551 } 11542 11552 else if (!in_still && !in_menu) 11543 11553 { 11544 uint titleLength = ctx->buffer->DVD()->GetTotalTimeOfTitle();11545 uint chapterLength = ctx->buffer->DVD()->GetChapterLength();11546 uint currentTime = ctx->buffer->DVD()->GetCurrentTime();11554 uint titleLength = dvdrb->GetTotalTimeOfTitle(); 11555 uint chapterLength = dvdrb->GetChapterLength(); 11556 uint currentTime = dvdrb->GetCurrentTime(); 11547 11557 if ((titleLength == chapterLength) && 11548 11558 (currentTime < (chapterLength - (ctx->jumptime * 60))) && 11549 11559 chapterLength > 300) … … 11567 11577 */ 11568 11578 bool TV::IsBookmarkAllowed(const PlayerContext *ctx) const 11569 11579 { 11570 bool isDVD = ctx->buffer && ctx->buffer-> isDVD();11580 bool isDVD = ctx->buffer && ctx->buffer->IsDVD(); 11571 11581 11572 11582 ctx->LockPlayingInfo(__FILE__, __LINE__); 11573 11583 … … 11624 11634 11625 11635 if (StateIsLiveTV(GetState(ctx))) 11626 11636 videotype = tr("Live TV"); 11627 else if (ctx->buffer-> isDVD())11637 else if (ctx->buffer->IsDVD()) 11628 11638 videotype = tr("this DVD"); 11629 11639 11630 11640 ctx->LockPlayingInfo(__FILE__, __LINE__); -
libs/libmythtv/BDRingBuffer.h
8 8 #include "libmythbluray/bluray.h" 9 9 #include "libmythbluray/keys.h" 10 10 11 #include "RingBuffer.h" 11 12 #include "util.h" 12 13 13 14 /** \class BDRingBufferPriv … … 18 19 19 20 class NuppelVideoPlayer; 20 21 21 class MPUBLIC BDRingBuffer Priv22 class MPUBLIC BDRingBuffer : public RingBuffer 22 23 { 23 24 public: 24 BDRingBuffer Priv();25 virtual ~BDRingBuffer Priv();25 BDRingBuffer(const QString &lfilename); 26 virtual ~BDRingBuffer(); 26 27 27 28 uint32_t GetNumTitles(void) const { return m_numTitles; } 28 29 int GetCurrentTitle(void) const; … … 33 34 // Get The total duration of the current title in 90Khz ticks. 34 35 uint64_t GetTotalTimeOfTitle(void) const { return (m_currentTitleLength / 90000); } 35 36 uint64_t GetCurrentTime(void) { return (m_currentTime / 90000); } 36 uint64_t GetReadPosition(void);37 virtual long long GetReadPosition(void) const; // RingBuffer 37 38 uint64_t GetTotalReadPosition(void); 38 39 uint32_t GetNumChapters(void); 39 40 uint64_t GetNumAngles(void) { return m_currentTitleAngleCount; } … … 42 43 bool IsOpen(void) const { return bdnav; } 43 44 bool IsHDMVNavigation(void) const { return m_is_hdmv_navigation; } 44 45 bool IsInMenu(void) const { return m_inMenu; } 45 bool InStillFrame(void) { return m_still > 0; } 46 bool IsInStillFrame(void) const { return m_still > 0; } 47 virtual bool IsInDiscMenuOrStillFrame(void) const 48 { return IsInMenu() || IsInStillFrame(); } // RingBuffer 46 49 47 50 void GetDescForPos(QString &desc) const; 48 51 double GetFrameRate(void); … … 51 54 int GetSubtitleLanguage(uint streamID); 52 55 53 56 // commands 54 bool OpenFile(const QString &filename); 57 virtual bool OpenFile(const QString &filename, 58 uint retry_ms = kDefaultOpenTimeout); // RingBuffer 55 59 void close(void); 56 60 57 61 bool GoToMenu(const QString str); 58 62 bool SwitchTitle(uint title); 59 63 bool SwitchAngle(uint angle); 60 64 61 int safe_read(void *data, unsigned sz); 65 virtual int safe_read(void *data, uint sz); // RingBuffer 66 virtual long long Seek(long long pos, int whence, bool has_lock); 62 67 uint64_t Seek(uint64_t pos); 63 68 64 69 bool HandleBDEvents(void); … … 97 102 98 103 public: 99 104 bool m_still; 100 boolm_inMenu;105 volatile bool m_inMenu; 101 106 102 107 }; 103 108 #endif -
libs/libmythtv/RingBuffer.h
17 17 18 18 #include "mythexp.h" 19 19 20 class RemoteFile;21 20 class ThreadedFileWriter; 22 class DVDRingBuffer Priv;23 class BDRingBuffer Priv;21 class DVDRingBuffer; 22 class BDRingBuffer; 24 23 class LiveTVChain; 24 class RemoteFile; 25 25 26 26 class MPUBLIC RingBuffer : protected QThread 27 27 { 28 28 public: 29 RingBuffer(const QString &lfilename, bool write, 30 bool usereadahead = true, 31 int timeout_ms = kDefaultOpenTimeout); 32 ~RingBuffer(); 29 static RingBuffer *Create(const QString &lfilename, bool write, 30 bool usereadahead = true, 31 int timeout_ms = kDefaultOpenTimeout, 32 bool stream_only = false); 33 ~RingBuffer(); 33 34 34 35 // Sets 35 36 void SetWriteBufferSize(int newSize); 36 37 void SetWriteBufferMinWriteSize(int newMinSize); 37 38 void SetOldFile(bool is_old); 38 void SetStreamOnly(bool stream);39 39 void UpdateRawBitrate(uint rawbitrate); 40 40 void UpdatePlaySpeed(float playspeed); 41 41 … … 46 46 /// \sa StartReads(void), StopReads(void) 47 47 bool GetStopReads(void) const { return stopreads; } 48 48 bool isPaused(void) const; 49 long long GetReadPosition(void) const; 49 /// \brief Returns how far into the file we have read. 50 virtual long long GetReadPosition(void) const = 0; 50 51 long long GetWritePosition(void) const; 51 long long GetRealFileSize(void) const; 52 bool IsOpen(void) const; 52 /// \brief Returns the size of the file we are reading/writing, 53 /// or -1 if the query fails. 54 virtual long long GetRealFileSize(void) const { return -1; } 53 55 bool IsNearEnd(double fps, uint vvf) const; 56 /// \brief Returns true if open for either reading or writing. 57 virtual bool IsOpen(void) const = 0; 54 58 59 bool IsDisc(void) const { return IsDVD() || IsBD(); } 60 bool IsDVD(void) const { return DVD() != NULL; } 61 bool IsBD(void) const { return BD() != NULL; } 62 const DVDRingBuffer *DVD(void) const; 63 const BDRingBuffer *BD(void) const; 64 DVDRingBuffer *DVD(void); 65 BDRingBuffer *BD(void); 66 67 virtual bool IsInDiscMenuOrStillFrame(void) const { return false; } 68 55 69 // General Commands 56 void OpenFile(const QString &lfilename, 57 uint retry_ms = kDefaultOpenTimeout); 70 71 /** \brief Opens a file for reading. 72 * 73 * \param lfilename Name of file to read 74 * \param retry_ms How many ms to retry reading the file 75 * after the first try before giving up. 76 */ 77 virtual bool OpenFile(const QString &lfilename, 78 uint retry_ms = kDefaultOpenTimeout) = 0; 79 58 80 int Read(void *buf, int count); 59 81 int Peek(void *buf, int count); // only works with readahead 60 82 … … 62 84 bool toAdjust = false, 63 85 bool resetInternal = false); 64 86 65 // Seeks 66 long long Seek(long long pos, int whence, bool has_lock = false); 87 /// \brief Seeks to a particular position in the file. 88 virtual long long Seek( 89 long long pos, int whence, bool has_lock = false) = 0; 67 90 68 91 // Pause commands 69 92 void Pause(void); … … 87 110 void Sync(void); 88 111 long long WriterSeek(long long pos, int whence, bool has_lock = false); 89 112 90 // DVDRingBuffer proxies91 bool IsDVD(void) const;92 93 // BDRingBuffer proxies94 bool IsBD(void) const;95 96 // Universal still frame/menu check97 bool InDiscMenuOrStillFrame(void);98 99 113 long long SetAdjustFilesize(void); 100 114 101 115 /// Calls SetOldFile(), do not use 102 116 void SetTimeout(bool is_old) MDEPRECATED { SetOldFile(is_old); } 103 /// Calls IsDVD(), do not use104 bool isDVD(void) const MDEPRECATED { return IsDVD(); }105 /// Calls IsBD(), do not use106 bool isBD(void) const MDEPRECATED { return IsBD(); }107 /// Illicitly manipulating privates is ill advised!108 /// DO NOT USE109 DVDRingBufferPriv *DVD() MDEPRECATED110 {111 return dvdPriv;112 }113 /// Illicitly manipulating privates is ill advised!114 /// DO NOT USE115 BDRingBufferPriv *BD() MDEPRECATED116 {117 return bdPriv;118 }119 117 120 118 static const int kDefaultOpenTimeout; 121 119 static const int kLiveTVOpenTimeout; 122 120 123 121 protected: 122 RingBuffer(); 123 124 124 void run(void); // QThread 125 125 void CalcReadAheadThresh(void); 126 126 bool PauseAndWait(void); 127 int safe_read_bd(void *data, uint sz); 128 int safe_read_dvd(void *data, uint sz); 129 int safe_read(int fd, void *data, uint sz); 130 int safe_read(RemoteFile *rf, void *data, uint sz); 127 virtual int safe_read(void *data, uint sz) = 0; 131 128 132 129 int ReadPriv(void *buf, int count, bool peek); 133 130 int ReadDirect(void *buf, int count, bool peek); … … 140 137 void ResetReadAhead(long long newinternal); 141 138 void KillReadAheadThread(void); 142 139 143 pr ivate:140 protected: 144 141 mutable QReadWriteLock poslock; 145 142 long long readpos; // protected by poslock 146 143 long long writepos; // protected by poslock … … 176 173 bool ateof; // protected by rwlock 177 174 bool readsallowed; // protected by rwlock 178 175 bool setswitchtonext; // protected by rwlock 179 bool streamOnly; // protected by rwlock180 176 bool ignorereadahead; // protected by rwlock 181 177 uint rawbitrate; // protected by rwlock 182 178 float playspeed; // protected by rwlock … … 187 183 int numfailures; // protected by rwlock (see note 1) 188 184 bool commserror; // protected by rwlock 189 185 190 // We should really subclass for these two sets of functionality..191 // current implementation is not thread-safe.192 DVDRingBufferPriv *dvdPriv; // NOT protected by a lock193 BDRingBufferPriv *bdPriv; // NOT protected by a lock194 195 186 bool oldfile; // protected by rwlock 196 187 197 188 LiveTVChain *livetvchain; // protected by rwlock -
libs/libmythtv/decoderbase.cpp
106 106 // Overwrites current positionmap with entire contents of database 107 107 frm_pos_map_t posMap; 108 108 109 if (ringBuffer-> isDVD())109 if (ringBuffer->IsDVD()) 110 110 { 111 111 long long totframes; 112 112 keyframedist = 15; … … 116 116 totframes = (long long)(ringBuffer->DVD()->GetTotalTimeOfTitle() * fps); 117 117 posMap[totframes] = ringBuffer->DVD()->GetTotalReadPosition(); 118 118 } 119 else if (ringBuffer-> isBD())119 else if (ringBuffer->IsBD()) 120 120 { 121 121 long long totframes; 122 122 keyframedist = 15; … … 182 182 m_positionMap.push_back(e); 183 183 } 184 184 185 if (!m_positionMap.empty() && !ringBuffer->isDVD() && 186 !ringBuffer->isBD()) 185 if (!m_positionMap.empty() && !ringBuffer->IsDisc()) 187 186 indexOffset = m_positionMap[0].index; 188 187 189 188 if (!m_positionMap.empty()) … … 234 233 m_positionMap.push_back(e); 235 234 } 236 235 237 if (!m_positionMap.empty() && !ringBuffer->isDVD() && 238 !ringBuffer->isBD()) 236 if (!m_positionMap.empty() && !ringBuffer->IsDisc()) 239 237 indexOffset = m_positionMap[0].index; 240 238 241 239 if (!m_positionMap.empty()) … … 335 333 long long totframes = 0; 336 334 int length = 0; 337 335 338 if (ringBuffer-> isDVD())336 if (ringBuffer->IsDVD()) 339 337 { 340 338 length = ringBuffer->DVD()->GetTotalTimeOfTitle(); 341 339 QMutexLocker locker(&m_positionMapLock); 342 340 totframes = m_positionMap.back().index; 343 341 } 344 else if (ringBuffer-> isBD())342 else if (ringBuffer->IsBD()) 345 343 { 346 344 length = ringBuffer->BD()->GetTotalTimeOfTitle(); 347 345 QMutexLocker locker(&m_positionMapLock); … … 509 507 normalframes = max(normalframes, 0); 510 508 SeekReset(lastKey, normalframes, true, discardFrames); 511 509 512 if (ringBuffer-> isDVD() || ringBuffer->isBD() || discardFrames)510 if (ringBuffer->IsDisc() || discardFrames) 513 511 { 514 512 // We need to tell the NVP and VideoOutput what frame we're on. 515 513 m_parent->SetFramesPlayed(framesPlayed+1); … … 521 519 522 520 long long DecoderBase::GetKey(const PosMapEntry &e) const 523 521 { 524 long long kf = (ringBuffer->isDVD() || ringBuffer->isBD()) ? 1LL : keyframedist;522 long long kf = (ringBuffer->IsDisc()) ? 1LL : keyframedist; 525 523 return (hasKeyFrameAdjustTable) ? e.adjFrame :(e.index - indexOffset) * kf; 526 524 } 527 525 528 526 bool DecoderBase::DoRewindSeek(long long desiredFrame) 529 527 { 530 if (ringBuffer-> isDVD())528 if (ringBuffer->IsDVD()) 531 529 { 532 530 long long pos = DVDFindPosition(desiredFrame); 533 531 ringBuffer->Seek(pos, SEEK_SET); 534 532 lastKey = desiredFrame + 1; 535 533 return true; 536 534 } 537 else if (ringBuffer-> isBD())535 else if (ringBuffer->IsBD()) 538 536 { 539 537 long long pos = BDFindPosition(desiredFrame); 540 538 ringBuffer->Seek(pos, SEEK_SET); … … 645 643 .arg(desiredFrame).arg(framesPlayed) 646 644 .arg((discardFrames) ? "do" : "don't")); 647 645 648 if (ringBuffer-> isDVD() &&649 ringBuffer->DVD()->TitleTimeLeft() < 5&&650 !ringBuffer->InDiscMenuOrStillFrame())646 if (ringBuffer->IsDVD() && 647 !ringBuffer->IsInDiscMenuOrStillFrame() && 648 ringBuffer->DVD()->TitleTimeLeft() < 5) 651 649 { 652 650 return false; 653 651 } … … 753 751 */ 754 752 void DecoderBase::DoFastForwardSeek(long long desiredFrame, bool &needflush) 755 753 { 756 if (ringBuffer-> isDVD())754 if (ringBuffer->IsDVD()) 757 755 { 758 756 long long pos = DVDFindPosition(desiredFrame); 759 757 ringBuffer->Seek(pos,SEEK_SET); … … 763 761 framesRead = lastKey; 764 762 return; 765 763 } 766 else if (ringBuffer-> isBD())764 else if (ringBuffer->IsBD()) 767 765 { 768 766 long long pos = BDFindPosition(desiredFrame); 769 767 ringBuffer->Seek(pos,SEEK_SET); … … 830 828 831 829 void DecoderBase::ChangeDVDTrack(bool ffw) 832 830 { 833 if (!ringBuffer-> isDVD())831 if (!ringBuffer->IsDVD()) 834 832 return; 835 833 836 834 bool result = true; … … 853 851 854 852 long long DecoderBase::DVDFindPosition(long long desiredFrame) 855 853 { 856 if (!ringBuffer-> isDVD())854 if (!ringBuffer->IsDVD()) 857 855 return 0; 858 856 int diffTime = 0; 859 857 long long desiredTimePos; … … 884 882 885 883 long long DecoderBase::BDFindPosition(long long desiredFrame) 886 884 { 887 if (!ringBuffer-> isBD())885 if (!ringBuffer->IsBD()) 888 886 return 0; 889 887 int diffTime = 0; 890 888 long long desiredTimePos; … … 915 913 916 914 void DecoderBase::UpdateDVDFramesPlayed(void) 917 915 { 918 if (!ringBuffer-> isDVD())916 if (!ringBuffer->IsDVD()) 919 917 return; 920 918 long long currentpos = (long long)(ringBuffer->DVD()->GetCurrentTime() * fps); 921 919 framesPlayed = framesRead = currentpos ; … … 925 923 926 924 void DecoderBase::UpdateBDFramesPlayed(void) 927 925 { 928 if (!ringBuffer-> isBD())926 if (!ringBuffer->IsBD()) 929 927 return; 930 928 long long currentpos = (long long)(ringBuffer->BD()->GetCurrentTime() * fps); 931 929 framesPlayed = framesRead = currentpos ; -
libs/libmythtv/tv_rec.cpp
4066 4066 bool write = genOpt.cardtype != "IMPORT"; 4067 4067 VERBOSE(VB_IMPORTANT, LOC + QString("rec->GetPathname(): '%1'") 4068 4068 .arg(rec->GetPathname())); 4069 SetRingBuffer( new RingBuffer(rec->GetPathname(), write));4069 SetRingBuffer(RingBuffer::Create(rec->GetPathname(), write)); 4070 4070 if (!ringBuffer->IsOpen() && write) 4071 4071 { 4072 4072 VERBOSE(VB_IMPORTANT, LOC_ERR + … … 4451 4451 4452 4452 StartedRecording(prog); 4453 4453 4454 *rb = new RingBuffer(prog->GetPathname(), true);4454 *rb = RingBuffer::Create(prog->GetPathname(), true); 4455 4455 if (!(*rb)->IsOpen()) 4456 4456 { 4457 4457 VERBOSE(VB_IMPORTANT, LOC_ERR + -
libs/libmythtv/textsubtitleparser.cpp
119 119 bool TextSubtitleParser::LoadSubtitles(QString fileName, TextSubtitles &target) 120 120 { 121 121 demux_sputext_t sub_data; 122 sub_data.rbuffer = new RingBuffer(fileName, 0, false);122 sub_data.rbuffer = RingBuffer::Create(fileName, 0, false); 123 123 124 124 if (!sub_data.rbuffer) 125 125 return false; -
programs/mythfrontend/main.cpp
750 750 751 751 if (pginfo->IsVideoDVD()) 752 752 { 753 RingBuffer *tmprbuf = new RingBuffer(pginfo->GetPathname(), false);753 RingBuffer *tmprbuf = RingBuffer::Create(pginfo->GetPathname(), false); 754 754 755 755 if (!tmprbuf) 756 756 { … … 759 759 } 760 760 QString name; 761 761 QString serialid; 762 if (tmprbuf-> isDVD() &&763 762 if (tmprbuf->IsDVD() && 763 tmprbuf->DVD()->GetNameAndSerialNum(name, serialid)) 764 764 { 765 765 QStringList fields = pginfo->QueryDVDBookmark(serialid, false); 766 766 if (!fields.empty()) -
programs/mythtranscode/transcode.cpp
377 377 nvr = new NuppelVideoRecorder(NULL, NULL); 378 378 379 379 // Input setup 380 inRingBuffer = new RingBuffer(inputname, false, false);380 inRingBuffer = RingBuffer::Create(inputname, false, false); 381 381 player = new MythPlayer(); 382 382 383 383 player_ctx = new PlayerContext(kTranscoderInUseID); … … 684 684 else if (vidsetting == "RTjpeg") 685 685 nvr->SetupRTjpeg(); 686 686 687 outRingBuffer = new RingBuffer(outputname, true, false);687 outRingBuffer = RingBuffer::Create(outputname, true, false); 688 688 nvr->SetRingBuffer(outRingBuffer); 689 689 nvr->WriteHeader(); 690 690 nvr->StreamAllocate(); -
programs/mythcommflag/main.cpp
155 155 else 156 156 filename = get_filename(program_info); 157 157 158 RingBuffer *tmprbuf = new RingBuffer(filename, false);158 RingBuffer *tmprbuf = RingBuffer::Create(filename, false); 159 159 if (!tmprbuf) 160 160 { 161 161 VERBOSE(VB_IMPORTANT, … … 737 737 738 738 QString filename = get_filename(program_info); 739 739 740 RingBuffer *tmprbuf = new RingBuffer(filename, false);740 RingBuffer *tmprbuf = RingBuffer::Create(filename, false); 741 741 if (!tmprbuf) 742 742 { 743 743 VERBOSE(VB_IMPORTANT, -
programs/mythbackend/filetransfer.cpp
11 11 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, 12 12 bool usereadahead, int timeout_ms) : 13 13 readthreadlive(true), readsLocked(false), 14 rbuffer( new RingBuffer(filename, false, usereadahead, timeout_ms)),14 rbuffer(RingBuffer::Create(filename, false, usereadahead, timeout_ms)), 15 15 sock(remote), ateof(false), lock(QMutex::NonRecursive), 16 16 refLock(QMutex::NonRecursive), refCount(0), writemode(false) 17 17 { … … 21 21 22 22 FileTransfer::FileTransfer(QString &filename, MythSocket *remote, bool write) : 23 23 readthreadlive(true), readsLocked(false), 24 rbuffer( new RingBuffer(filename, write)),24 rbuffer(RingBuffer::Create(filename, write)), 25 25 sock(remote), ateof(false), lock(QMutex::NonRecursive), 26 26 refLock(QMutex::NonRecursive), refCount(0), writemode(write) 27 27 { … … 234 234 if (pginfo) 235 235 pginfo->UpdateInUseMark(); 236 236 237 rbuffer->Set Timeout(fast);237 rbuffer->SetOldFile(fast); 238 238 } 239 239 240 240 /* vim: set expandtab tabstop=4 shiftwidth=4: */