Bug 1361964. P1 - let ReadFromCache() return the number of bytes read successfully. draft
authorJW Wang <jwwang@mozilla.com>
Thu, 04 May 2017 17:37:43 +0800
changeset 572701 5664be39cac0e4dc97426c8916043019f4f98b32
parent 572442 b9151926f9cf72eec5dc8da45ecbdbcbee271508
child 572702 548d4e1b39ae907e075055e90c65dbeb6d356959
push id57147
push userjwwang@mozilla.com
push dateThu, 04 May 2017 14:25:41 +0000
bugs1361964
milestone55.0a1
Bug 1361964. P1 - let ReadFromCache() return the number of bytes read successfully. MozReview-Commit-ID: DvgfRuuMe6h
dom/media/BufferMediaResource.h
dom/media/MediaCache.cpp
dom/media/MediaCache.h
dom/media/MediaResource.cpp
dom/media/MediaResource.h
dom/media/fmp4/MP4Stream.cpp
dom/media/gtest/MockMediaResource.h
dom/media/mediasource/ContainerParser.cpp
dom/media/mediasource/MediaSourceResource.h
dom/media/mediasource/SourceBufferResource.cpp
dom/media/mediasource/SourceBufferResource.h
dom/media/ogg/OggDemuxer.cpp
media/libstagefright/binding/ResourceStream.cpp
--- a/dom/media/BufferMediaResource.h
+++ b/dom/media/BufferMediaResource.h
@@ -76,24 +76,25 @@ private:
   int64_t GetLength() override { return mLength; }
   int64_t GetNextCachedData(int64_t aOffset) override { return aOffset; }
   int64_t GetCachedDataEnd(int64_t aOffset) override { return mLength; }
   bool IsDataCachedToEndOfResource(int64_t aOffset) override { return true; }
   bool IsSuspendedByCache() override { return false; }
   bool IsSuspended() override { return false; }
   nsresult ReadFromCache(char* aBuffer,
                          int64_t aOffset,
-                         uint32_t aCount) override
+                         uint32_t aCount,
+                         uint32_t* aBytes) override
   {
     if (aOffset < 0) {
       return NS_ERROR_FAILURE;
     }
 
-    uint32_t bytes = std::min(mLength - static_cast<uint32_t>(aOffset), aCount);
-    memcpy(aBuffer, mBuffer + aOffset, bytes);
+    *aBytes = std::min(mLength - static_cast<uint32_t>(aOffset), aCount);
+    memcpy(aBuffer, mBuffer + aOffset, *aBytes);
     return NS_OK;
   }
 
   nsresult Open(nsIStreamListener** aStreamListener) override
   {
     return NS_ERROR_FAILURE;
   }
 
--- a/dom/media/MediaCache.cpp
+++ b/dom/media/MediaCache.cpp
@@ -2333,17 +2333,18 @@ MediaCacheStream::ReadAt(int64_t aOffset
 
   ReentrantMonitorAutoEnter mon(gMediaCache->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, int64_t aCount)
+MediaCacheStream::ReadFromCache(
+  char* aBuffer, int64_t aOffset, int64_t aCount, uint32_t* aBytes)
 {
   ReentrantMonitorAutoEnter mon(gMediaCache->GetReentrantMonitor());
 
   // Read one block (or part of a block) at a time
   uint32_t count = 0;
   int64_t streamOffset = aOffset;
   while (count < aCount) {
     if (mClosed) {
@@ -2391,16 +2392,17 @@ MediaCacheStream::ReadFromCache(char* aB
       if (NS_FAILED(rv)) {
         return rv;
       }
     }
     streamOffset += bytes;
     count += bytes;
   }
 
+  *aBytes = count;
   return NS_OK;
 }
 
 nsresult
 MediaCacheStream::Init()
 {
   NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
 
--- a/dom/media/MediaCache.h
+++ b/dom/media/MediaCache.h
@@ -305,17 +305,18 @@ public:
   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,
-                         int64_t aCount);
+                         int64_t aCount,
+                         uint32_t* aBytes);
 
   // 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);
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -667,19 +667,20 @@ void ChannelMediaResource::CloseChannel(
     // at the moment.
     mChannel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
     mChannel = nullptr;
   }
 }
 
 nsresult ChannelMediaResource::ReadFromCache(char* aBuffer,
                                              int64_t aOffset,
-                                             uint32_t aCount)
+                                             uint32_t aCount,
+                                             uint32_t* aBytes)
 {
-  return mCacheStream.ReadFromCache(aBuffer, aOffset, aCount);
+  return mCacheStream.ReadFromCache(aBuffer, aOffset, aCount, aBytes);
 }
 
 nsresult ChannelMediaResource::ReadAt(int64_t aOffset,
                                       char* aBuffer,
                                       uint32_t aCount,
                                       uint32_t* aBytes)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
@@ -1138,17 +1139,17 @@ public:
   // Main thread
   nsresult Open(nsIStreamListener** aStreamListener) override;
   nsresult Close() override;
   void     Suspend(bool aCloseImmediately) override {}
   void     Resume() override {}
   already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override;
   bool     CanClone() override;
   already_AddRefed<MediaResource> CloneData(MediaResourceCallback* aCallback) override;
-  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
+  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes) override;
 
   // These methods are called off the main thread.
 
   // Other thread
   void     SetReadMode(MediaCacheStream::ReadMode aMode) override {}
   void     SetPlaybackRate(uint32_t aBytesPerSecond) override {}
   nsresult ReadAt(int64_t aOffset, char* aBuffer,
                   uint32_t aCount, uint32_t* aBytes) override;
@@ -1378,17 +1379,18 @@ already_AddRefed<MediaResource> FileMedi
 
   if (NS_FAILED(rv))
     return nullptr;
 
   RefPtr<MediaResource> resource(new FileMediaResource(aCallback, channel, mURI, GetContentType()));
   return resource.forget();
 }
 
-nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
+nsresult FileMediaResource::ReadFromCache(
+  char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes)
 {
   MutexAutoLock lock(mLock);
 
   EnsureSizeInitialized();
   if (!aCount) {
     return NS_OK;
   }
   int64_t offset = 0;
@@ -1409,16 +1411,18 @@ nsresult FileMediaResource::ReadFromCach
 
   // Reset read head to original position so we don't disturb any other
   // reading thread.
   nsresult seekres = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, offset);
 
   // If a read failed in the loop above, we want to return its failure code.
   NS_ENSURE_SUCCESS(res,res);
 
+  *aBytes = bytesRead;
+
   // Else we succeed if the reset-seek succeeds.
   return seekres;
 }
 
 nsresult FileMediaResource::UnsafeRead(char* aBuffer, uint32_t aCount, uint32_t* aBytes)
 {
   EnsureSizeInitialized();
   return mInput->Read(aBuffer, aCount, aBytes);
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -301,17 +301,18 @@ public:
   virtual bool IsSuspended() = 0;
   // Reads only data which is cached in the media cache. If you try to read
   // any data which overlaps uncached data, or if aCount bytes otherwise can't
   // be read, this function will return failure. This function be called from
   // any thread, and it is the only read operation which is safe to call on
   // the main thread, since it's guaranteed to be non blocking.
   virtual nsresult ReadFromCache(char* aBuffer,
                                  int64_t aOffset,
-                                 uint32_t aCount) = 0;
+                                 uint32_t aCount,
+                                 uint32_t* aBytes) = 0;
   // Returns true if the resource can be seeked to unbuffered ranges, i.e.
   // for an HTTP network stream this returns true if HTTP1.1 Byte Range
   // requests are supported by the connection/server.
   virtual bool IsTransportSeekable() = 0;
 
   /**
    * Create a resource, reading data from the channel. Call on main thread only.
    * The caller must follow up by calling resource->Open().
@@ -566,17 +567,17 @@ public:
   // |ChannelMediaResource| will create it's own statistics objects in |Open|.
   void RecordStatisticsTo(MediaChannelStatistics *aStatistics) override {
     NS_ASSERTION(aStatistics, "Statistics param cannot be null!");
     MutexAutoLock lock(mLock);
     if (!mChannelStatistics) {
       mChannelStatistics = aStatistics;
     }
   }
-  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
+  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes) override;
   void     EnsureCacheUpToDate() override;
 
   // Other thread
   void     SetReadMode(MediaCacheStream::ReadMode aMode) override;
   void     SetPlaybackRate(uint32_t aBytesPerSecond) override;
   nsresult ReadAt(int64_t offset, char* aBuffer,
                   uint32_t aCount, uint32_t* aBytes) override;
   already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount) override;
--- a/dom/media/fmp4/MP4Stream.cpp
+++ b/dom/media/fmp4/MP4Stream.cpp
@@ -75,24 +75,24 @@ MP4Stream::CachedReadAt(int64_t aOffset,
   for (size_t i = 0; i < mCache.Length(); ++i) {
     if (mCache[i].mOffset == aOffset && mCache[i].mCount >= aCount) {
       memcpy(aBuffer, mCache[i].Buffer(), aCount);
       *aBytesRead = aCount;
       return true;
     }
   }
 
-  nsresult rv =
-    mResource.GetResource()->ReadFromCache(reinterpret_cast<char*>(aBuffer),
-                                           aOffset, aCount);
+  uint32_t bytesRead = 0;
+  nsresult rv = mResource.GetResource()->ReadFromCache(
+    reinterpret_cast<char*>(aBuffer), aOffset, aCount, &bytesRead);
   if (NS_FAILED(rv)) {
     *aBytesRead = 0;
     return false;
   }
-  *aBytesRead = aCount;
+  *aBytesRead = bytesRead;
   return true;
 }
 
 bool
 MP4Stream::Length(int64_t* aSize)
 {
   if (mResource.GetLength() < 0)
     return false;
--- a/dom/media/gtest/MockMediaResource.h
+++ b/dom/media/gtest/MockMediaResource.h
@@ -45,22 +45,22 @@ public:
   int64_t GetCachedDataEnd(int64_t aOffset) override;
   bool IsDataCachedToEndOfResource(int64_t aOffset) override
   {
     return false;
   }
   bool IsSuspendedByCache() override { return false; }
   bool IsSuspended() override { return false; }
   nsresult ReadFromCache(char* aBuffer, int64_t aOffset,
-                         uint32_t aCount) override
+                         uint32_t aCount, uint32_t* aBytes) override
   {
-    uint32_t bytesRead = 0;
-    nsresult rv = ReadAt(aOffset, aBuffer, aCount, &bytesRead);
+    *aBytes = 0;
+    nsresult rv = ReadAt(aOffset, aBuffer, aCount, aBytes);
     NS_ENSURE_SUCCESS(rv, rv);
-    return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
+    return *aBytes == aCount ? NS_OK : NS_ERROR_FAILURE;
   }
 
   bool IsTransportSeekable() override { return true; }
   nsresult Open(nsIStreamListener** aStreamListener) override;
   nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override;
   const MediaContainerType& GetContentType() const override
   {
     return mContainerType;
--- a/dom/media/mediasource/ContainerParser.cpp
+++ b/dom/media/mediasource/ContainerParser.cpp
@@ -239,17 +239,18 @@ public:
         MOZ_ASSERT(mParser.mInitEndOffset <= mResource->GetLength());
         if (!mInitData->SetLength(mParser.mInitEndOffset, fallible)) {
           // Super unlikely OOM
           return NS_ERROR_OUT_OF_MEMORY;
         }
         mCompleteInitSegmentRange =
           MediaByteRange(0, mParser.mInitEndOffset) + mGlobalOffset;
         char* buffer = reinterpret_cast<char*>(mInitData->Elements());
-        mResource->ReadFromCache(buffer, 0, mParser.mInitEndOffset);
+        uint32_t bytesRead = 0;
+        mResource->ReadFromCache(buffer, 0, mParser.mInitEndOffset, &bytesRead);
         MSE_DEBUG(WebMContainerParser, "Stashed init of %" PRId64 " bytes.",
                   mParser.mInitEndOffset);
         mResource = nullptr;
       } else {
         MSE_DEBUG(WebMContainerParser, "Incomplete init found.");
       }
       mHasInitData = true;
     }
@@ -524,17 +525,18 @@ public:
       MediaByteRange& range = mParser->mInitRange;
       if (range.Length()) {
         mCompleteInitSegmentRange = range + mGlobalOffset;
         if (!mInitData->SetLength(range.Length(), fallible)) {
           // Super unlikely OOM
           return NS_ERROR_OUT_OF_MEMORY;
         }
         char* buffer = reinterpret_cast<char*>(mInitData->Elements());
-        mResource->ReadFromCache(buffer, range.mStart, range.Length());
+        uint32_t bytesRead = 0;
+        mResource->ReadFromCache(buffer, range.mStart, range.Length(), &bytesRead);
         MSE_DEBUG(MP4ContainerParser ,"Stashed init of %" PRIu64 " bytes.",
                   range.Length());
       } else {
         MSE_DEBUG(MP4ContainerParser, "Incomplete init found.");
       }
       mHasInitData = true;
     }
     mTotalParsed += aData->Length();
--- a/dom/media/mediasource/MediaSourceResource.h
+++ b/dom/media/mediasource/MediaSourceResource.h
@@ -43,17 +43,17 @@ public:
   void Unpin() override { UNIMPLEMENTED(); }
   double GetDownloadRate(bool* aIsReliable) override { UNIMPLEMENTED(); *aIsReliable = false; return 0; }
   int64_t GetLength() override { UNIMPLEMENTED(); return -1; }
   int64_t GetNextCachedData(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
   int64_t GetCachedDataEnd(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
   bool IsDataCachedToEndOfResource(int64_t aOffset) override { UNIMPLEMENTED(); return false; }
   bool IsSuspendedByCache() override { UNIMPLEMENTED(); return false; }
   bool IsSuspended() override { UNIMPLEMENTED(); return false; }
-  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
+  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
   nsresult Open(nsIStreamListener** aStreamListener) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
 
   already_AddRefed<nsIPrincipal> GetCurrentPrincipal() override
   {
     return RefPtr<nsIPrincipal>(mPrincipal).forget();
   }
 
   nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
--- a/dom/media/mediasource/SourceBufferResource.cpp
+++ b/dom/media/mediasource/SourceBufferResource.cpp
@@ -89,27 +89,27 @@ SourceBufferResource::ReadAtInternal(int
 
   mInputBuffer.CopyData(aOffset, count, aBuffer);
   *aBytes = count;
 
   return NS_OK;
 }
 
 nsresult
-SourceBufferResource::ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount)
+SourceBufferResource::ReadFromCache(
+  char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes)
 {
   SBR_DEBUG("ReadFromCache(aBuffer=%p, aOffset=%" PRId64 ", aCount=%u)",
             aBuffer, aOffset, aCount);
   ReentrantMonitorAutoEnter mon(mMonitor);
-  uint32_t bytesRead;
-  nsresult rv = ReadAtInternal(aOffset, aBuffer, aCount, &bytesRead, /* aMayBlock = */ false);
+  nsresult rv = ReadAtInternal(aOffset, aBuffer, aCount, aBytes, /* aMayBlock = */ false);
   NS_ENSURE_SUCCESS(rv, rv);
 
   // ReadFromCache return failure if not all the data is cached.
-  return bytesRead == aCount ? NS_OK : NS_ERROR_FAILURE;
+  return *aBytes == aCount ? NS_OK : NS_ERROR_FAILURE;
 }
 
 uint32_t
 SourceBufferResource::EvictData(uint64_t aPlaybackOffset, int64_t aThreshold,
                                 ErrorResult& aRv)
 {
   SBR_DEBUG("EvictData(aPlaybackOffset=%" PRIu64 ","
             "aThreshold=%" PRId64 ")", aPlaybackOffset, aThreshold);
--- a/dom/media/mediasource/SourceBufferResource.h
+++ b/dom/media/mediasource/SourceBufferResource.h
@@ -60,17 +60,17 @@ public:
       return -1;
     }
     return aOffset;
   }
   int64_t GetCachedDataEnd(int64_t aOffset) override { UNIMPLEMENTED(); return -1; }
   bool IsDataCachedToEndOfResource(int64_t aOffset) override { return false; }
   bool IsSuspendedByCache() override { UNIMPLEMENTED(); return false; }
   bool IsSuspended() override { UNIMPLEMENTED(); return false; }
-  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount) override;
+  nsresult ReadFromCache(char* aBuffer, int64_t aOffset, uint32_t aCount, uint32_t* aBytes) override;
   bool IsTransportSeekable() override { UNIMPLEMENTED(); return true; }
   nsresult Open(nsIStreamListener** aStreamListener) override { UNIMPLEMENTED(); return NS_ERROR_FAILURE; }
 
   nsresult GetCachedRanges(MediaByteRangeSet& aRanges) override
   {
     ReentrantMonitorAutoEnter mon(mMonitor);
     if (mInputBuffer.GetLength()) {
       aRanges += MediaByteRange(mInputBuffer.GetOffset(),
--- a/dom/media/ogg/OggDemuxer.cpp
+++ b/dom/media/ogg/OggDemuxer.cpp
@@ -1243,20 +1243,19 @@ OggDemuxer::PageSync(MediaResourceIndex*
       int64_t bytesToRead = std::min(static_cast<int64_t>(PAGE_STEP),
                                    aEndOffset - readHead);
       NS_ASSERTION(bytesToRead <= UINT32_MAX, "bytesToRead range check");
       if (bytesToRead <= 0) {
         return PAGE_SYNC_END_OF_RANGE;
       }
       nsresult rv = NS_OK;
       if (aCachedDataOnly) {
-        rv = aResource->GetResource()->ReadFromCache(buffer, readHead,
-                                                     static_cast<uint32_t>(bytesToRead));
+        rv = aResource->GetResource()->ReadFromCache(
+          buffer, readHead, static_cast<uint32_t>(bytesToRead), &bytesRead);
         NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
-        bytesRead = static_cast<uint32_t>(bytesToRead);
       } else {
         rv = aResource->Seek(nsISeekableStream::NS_SEEK_SET, readHead);
         NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
         rv = aResource->Read(buffer,
                              static_cast<uint32_t>(bytesToRead),
                              &bytesRead);
         NS_ENSURE_SUCCESS(rv,PAGE_SYNC_ERROR);
       }
@@ -1532,19 +1531,19 @@ OggDemuxer::RangeEndTime(TrackInfo::Trac
       limit = std::max(static_cast<int64_t>(0), limit);
       limit = std::min(limit, static_cast<int64_t>(step));
       uint32_t bytesToRead = static_cast<uint32_t>(limit);
       uint32_t bytesRead = 0;
       char* buffer = ogg_sync_buffer(&sync.mState, bytesToRead);
       NS_ASSERTION(buffer, "Must have buffer");
       nsresult res;
       if (aCachedDataOnly) {
-        res = Resource(aType)->GetResource()->ReadFromCache(buffer, readHead, bytesToRead);
+        res = Resource(aType)->GetResource()->ReadFromCache(
+          buffer, readHead, bytesToRead, &bytesRead);
         NS_ENSURE_SUCCESS(res, -1);
-        bytesRead = bytesToRead;
       } else {
         NS_ASSERTION(readHead < aEndOffset,
                      "resource pos must be before range end");
         res = Resource(aType)->Seek(nsISeekableStream::NS_SEEK_SET, readHead);
         NS_ENSURE_SUCCESS(res, -1);
         res = Resource(aType)->Read(buffer, bytesToRead, &bytesRead);
         NS_ENSURE_SUCCESS(res, -1);
       }
--- a/media/libstagefright/binding/ResourceStream.cpp
+++ b/media/libstagefright/binding/ResourceStream.cpp
@@ -40,23 +40,24 @@ ResourceStream::ReadAt(int64_t aOffset, 
   *aBytesRead = sum;
   return true;
 }
 
 bool
 ResourceStream::CachedReadAt(int64_t aOffset, void* aBuffer, size_t aCount,
                         size_t* aBytesRead)
 {
+  uint32_t bytesRead = 0;
   nsresult rv = mResource->ReadFromCache(reinterpret_cast<char*>(aBuffer),
-                                         aOffset, aCount);
+                                         aOffset, aCount, &bytesRead);
   if (NS_FAILED(rv)) {
     *aBytesRead = 0;
     return false;
   }
-  *aBytesRead = aCount;
+  *aBytesRead = bytesRead;
   return true;
 }
 
 bool
 ResourceStream::Length(int64_t* aSize)
 {
   if (mResource->GetLength() < 0)
     return false;