author | Sebastian Hengst <archaeopteryx@coole-files.de> |
Wed, 08 Nov 2017 19:33:00 +0200 | |
changeset 444071 | db4daa1627fff3d54176ee8835ad3bb3d84aaf5d |
parent 444070 | e046373e0dca3c6a3834812b2f04b2da35f508cf (current diff) |
parent 444022 | 75c04adb414bc00d39a0af80691a82af1ceebbd0 (diff) |
child 444072 | 09381b4fe070c999166bdebaab127ba84fbe1a51 |
push id | 1618 |
push user | Callek@gmail.com |
push date | Thu, 11 Jan 2018 17:45:48 +0000 |
treeherder | mozilla-release@882ca853e05a [default view] [failures only] |
perfherder | [talos] [build metrics] [platform microbench] (compared to previous push) |
reviewers | backout |
milestone | 58.0a1 |
first release with | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
last release without | nightly linux32
nightly linux64
nightly mac
nightly win32
nightly win64
|
--- a/dom/media/MediaCache.cpp +++ b/dom/media/MediaCache.cpp @@ -2457,82 +2457,16 @@ MediaCacheStream::ThrottleReadahead(bool ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor()); if (mThrottleReadahead != bThrottle) { LOGI("Stream %p ThrottleReadahead %d", this, bThrottle); mThrottleReadahead = bThrottle; mMediaCache->QueueUpdate(); } } -uint32_t -MediaCacheStream::ReadPartialBlock(int64_t aOffset, Span<char> aBuffer) -{ - mMediaCache->GetReentrantMonitor().AssertCurrentThreadIn(); - MOZ_ASSERT(IsOffsetAllowed(aOffset)); - - if (OffsetToBlockIndexUnchecked(mChannelOffset) != - OffsetToBlockIndexUnchecked(aOffset) || - aOffset >= mChannelOffset) { - // Not in the partial block or no data to read. - return 0; - } - - auto source = MakeSpan<const uint8_t>( - mPartialBlockBuffer.get() + OffsetInBlock(aOffset), - OffsetInBlock(mChannelOffset) - OffsetInBlock(aOffset)); - // We have |source.Length() <= BLOCK_SIZE < INT32_MAX| to guarantee - // that |bytesToRead| can fit into a uint32_t. - uint32_t bytesToRead = std::min(aBuffer.Length(), source.Length()); - memcpy(aBuffer.Elements(), source.Elements(), bytesToRead); - return bytesToRead; -} - -Result<uint32_t, nsresult> -MediaCacheStream::ReadBlockFromCache(int64_t aOffset, Span<char> aBuffer) -{ - mMediaCache->GetReentrantMonitor().AssertCurrentThreadIn(); - MOZ_ASSERT(IsOffsetAllowed(aOffset)); - - // OffsetToBlockIndexUnchecked() is always non-negative. - uint32_t index = OffsetToBlockIndexUnchecked(aOffset); - int32_t cacheBlock = index < mBlocks.Length() ? mBlocks[index] : -1; - if (cacheBlock < 0) { - // Not in the cache. - return 0; - } - - if (aBuffer.Length() > size_t(BLOCK_SIZE)) { - // Clamp the buffer to avoid overflow below since we will read at most - // BLOCK_SIZE bytes. - aBuffer = aBuffer.First(BLOCK_SIZE); - } - // |BLOCK_SIZE - OffsetInBlock(aOffset)| <= BLOCK_SIZE - int32_t bytesToRead = - std::min<int32_t>(BLOCK_SIZE - OffsetInBlock(aOffset), aBuffer.Length()); - int32_t bytesRead = 0; - nsresult rv = - mMediaCache->ReadCacheFile(cacheBlock * BLOCK_SIZE + OffsetInBlock(aOffset), - aBuffer.Elements(), - bytesToRead, - &bytesRead); - - // Ensure |cacheBlock * BLOCK_SIZE + OffsetInBlock(aOffset)| won't overflow. - static_assert(INT64_MAX >= BLOCK_SIZE * (uint32_t(INT32_MAX) + 1), - "BLOCK_SIZE too large!"); - - if (NS_FAILED(rv)) { - nsCString name; - GetErrorName(rv, name); - LOGE("Stream %p ReadCacheFile failed, rv=%s", this, name.Data()); - return mozilla::Err(rv); - } - - return bytesRead; -} - int64_t MediaCacheStream::Tell() { ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor()); return mStreamOffset; } nsresult @@ -2667,59 +2601,77 @@ MediaCacheStream::ReadAt(int64_t aOffset ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor()); nsresult rv = Seek(nsISeekableStream::NS_SEEK_SET, aOffset); if (NS_FAILED(rv)) return rv; return Read(aBuffer, aCount, aBytes); } nsresult -MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) +MediaCacheStream::ReadFromCache(char* aBuffer, int64_t aOffset, int64_t aCount) { ReentrantMonitorAutoEnter mon(mMediaCache->GetReentrantMonitor()); - // The buffer we are about to fill. - auto buffer = MakeSpan<char>(aBuffer, aCount); - // Read one block (or part of a block) at a time + uint32_t count = 0; int64_t streamOffset = aOffset; - while (!buffer.IsEmpty()) { + while (count < aCount) { if (mClosed) { // We need to check |mClosed| in each iteration which might be changed // after calling |mMediaCache->ReadCacheFile|. return NS_ERROR_FAILURE; } - - if (!IsOffsetAllowed(streamOffset)) { - LOGE("Stream %p invalid offset=%" PRId64, this, streamOffset); - return NS_ERROR_ILLEGAL_VALUE; + int32_t streamBlock = OffsetToBlockIndex(streamOffset); + if (streamBlock < 0) { + break; } + uint32_t offsetInStreamBlock = + uint32_t(streamOffset - streamBlock*BLOCK_SIZE); + int64_t size = std::min<int64_t>(aCount - count, BLOCK_SIZE - offsetInStreamBlock); - Result<uint32_t, nsresult> rv = ReadBlockFromCache(streamOffset, buffer); - if (rv.isErr()) { - return rv.unwrapErr(); + if (mStreamLength >= 0) { + // Don't try to read beyond the end of the stream + int64_t bytesRemaining = mStreamLength - streamOffset; + if (bytesRemaining <= 0) { + return NS_ERROR_FAILURE; + } + size = std::min(size, bytesRemaining); + // Clamp size until 64-bit file size issues are fixed. + size = std::min(size, int64_t(INT32_MAX)); } - uint32_t bytes = rv.unwrap(); - if (bytes > 0) { - // Read data from the cache successfully. Let's try next block. - streamOffset += bytes; - buffer = buffer.From(bytes); - continue; + int32_t bytes; + int32_t channelBlock = OffsetToBlockIndexUnchecked(mChannelOffset); + int32_t cacheBlock = + size_t(streamBlock) < mBlocks.Length() ? mBlocks[streamBlock] : -1; + if (channelBlock == streamBlock && streamOffset < mChannelOffset) { + // We can just use the data in mPartialBlockBuffer. In fact we should + // use it rather than waiting for the block to fill and land in + // the cache. + // Clamp bytes until 64-bit file size issues are fixed. + int64_t toCopy = std::min<int64_t>(size, mChannelOffset - streamOffset); + bytes = std::min(toCopy, int64_t(INT32_MAX)); + MOZ_ASSERT(bytes >= 0 && bytes <= toCopy, "Bytes out of range."); + memcpy(aBuffer + count, + mPartialBlockBuffer.get() + offsetInStreamBlock, bytes); + } else { + if (cacheBlock < 0) { + // We expect all blocks to be cached! Fail! + return NS_ERROR_FAILURE; + } + int64_t offset = cacheBlock*BLOCK_SIZE + offsetInStreamBlock; + MOZ_ASSERT(size >= 0 && size <= INT32_MAX, "Size out of range."); + nsresult rv = mMediaCache->ReadCacheFile( + offset, aBuffer + count, int32_t(size), &bytes); + if (NS_FAILED(rv)) { + return rv; + } } - - // The partial block is our last chance to get data. - bytes = ReadPartialBlock(streamOffset, buffer); - if (bytes < buffer.Length()) { - // Not enough data to read. - return NS_ERROR_FAILURE; - } - - // Return for we've got all the requested bytes. - return NS_OK; + streamOffset += bytes; + count += bytes; } return NS_OK; } nsresult MediaCacheStream::Init(int64_t aContentLength) {
--- a/dom/media/MediaCache.h +++ b/dom/media/MediaCache.h @@ -3,17 +3,16 @@ /* This Source Code Form is subject to the terms of the Mozilla Public * License, v. 2.0. If a copy of the MPL was not distributed with this * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ #ifndef MediaCache_h_ #define MediaCache_h_ #include "Intervals.h" -#include "mozilla/Result.h" #include "mozilla/UniquePtr.h" #include "nsCOMPtr.h" #include "nsHashKeys.h" #include "nsTArray.h" #include "nsTHashtable.h" class nsIEventTarget; class nsIPrincipal; @@ -310,17 +309,19 @@ public: // growing. The stream should be pinned while this runs and while its results // are used, to ensure no data is evicted. nsresult GetCachedRanges(MediaByteRangeSet& aRanges); // Reads from buffered data only. Will fail if not all data to be read is // in the cache. Will not mark blocks as read. Can be called from the main // thread. It's the caller's responsibility to wrap the call in a pin/unpin, // and also to check that the range they want is cached before calling this. - nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount); + nsresult ReadFromCache(char* aBuffer, + int64_t aOffset, + int64_t aCount); // IsDataCachedToEndOfStream returns true if all the data from // aOffset to the end of the stream (the server-reported end, if the // real end is not known) is in cache. If we know nothing about the // end of the stream, this returns false. bool IsDataCachedToEndOfStream(int64_t aOffset); // The mode is initially MODE_PLAYBACK. void SetReadMode(ReadMode aMode); @@ -420,26 +421,16 @@ private: nsTHashtable<Entry> mEntries; // The index of the first block in the list, or -1 if the list is empty. int32_t mFirstBlock; // The number of blocks in the list. int32_t mCount; }; - // Read data from the partial block and return the number of bytes read - // successfully. 0 if aOffset is not an offset in the partial block or there - // is nothing to read. - uint32_t ReadPartialBlock(int64_t aOffset, Span<char> aBuffer); - - // Read data from the cache block specified by aOffset. Return the number of - // bytes read successfully or an error code if any failure. - Result<uint32_t, nsresult> ReadBlockFromCache(int64_t aOffset, - Span<char> aBuffer); - // Returns the end of the bytes starting at the given offset // which are in cache. // This method assumes that the cache monitor is held and can be called on // any thread. int64_t GetCachedDataEndInternal(int64_t aOffset); // Returns the offset of the first byte of cached data at or after aOffset, // or -1 if there is no such cached data. // This method assumes that the cache monitor is held and can be called on