Bug 1182933 - Implement MediaReadAt. r=bholley, a=ritu
authorJean-Yves Avenard <jyavenard@mozilla.com>
Fri, 10 Jul 2015 16:08:07 +1000
changeset 281549 414e93c84fe37711d907c1373e7fc2fefa608024
parent 281548 73587058aa473d3f0ed401367bbba67e97c983df
child 281550 e2e14c4cfd09e1fbc75d815e0721714b20c96d81
push id4932
push userjlund@mozilla.com
push dateMon, 10 Aug 2015 18:23:06 +0000
treeherdermozilla-beta@6dd5a4f5f745 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersbholley, ritu
bugs1182933
milestone41.0a2
Bug 1182933 - Implement MediaReadAt. r=bholley, a=ritu Ensure SilentReadAt seek back to original position even in case of error. Properly set the MediaByteBuffer length.
dom/media/MediaResource.cpp
dom/media/MediaResource.h
--- a/dom/media/MediaResource.cpp
+++ b/dom/media/MediaResource.cpp
@@ -754,35 +754,37 @@ nsresult ChannelMediaResource::ReadAt(in
   nsresult rv = mCacheStream.ReadAt(aOffset, aBuffer, aCount, aBytes);
   if (NS_SUCCEEDED(rv)) {
     DispatchBytesConsumed(*aBytes, aOffset);
   }
   return rv;
 }
 
 already_AddRefed<MediaByteBuffer>
-ChannelMediaResource::SilentReadAt(int64_t aOffset, uint32_t aCount)
+ChannelMediaResource::MediaReadAt(int64_t aOffset, uint32_t aCount)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
-  bool ok = bytes->SetCapacity(aCount, fallible);
+  bool ok = bytes->SetLength(aCount, fallible);
   NS_ENSURE_TRUE(ok, nullptr);
-  int64_t pos = mCacheStream.Tell();
   char* curr = reinterpret_cast<char*>(bytes->Elements());
+  const char* start = curr;
   while (aCount > 0) {
     uint32_t bytesRead;
     nsresult rv = mCacheStream.ReadAt(aOffset, curr, aCount, &bytesRead);
     NS_ENSURE_SUCCESS(rv, nullptr);
-    NS_ENSURE_TRUE(bytesRead > 0, nullptr);
+    if (!bytesRead) {
+      break;
+    }
     aOffset += bytesRead;
     aCount -= bytesRead;
     curr += bytesRead;
   }
-  mCacheStream.Seek(nsISeekableStream::NS_SEEK_SET, pos);
+  bytes->SetLength(curr - start);
   return bytes.forget();
 }
 
 nsresult ChannelMediaResource::Seek(int32_t aWhence, int64_t aOffset)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   CMLOG("Seek requested for aOffset [%lld] for decoder [%p]",
@@ -1212,16 +1214,17 @@ public:
   // These methods are called off the main thread.
 
   // Other thread
   virtual void     SetReadMode(MediaCacheStream::ReadMode aMode) override {}
   virtual void     SetPlaybackRate(uint32_t aBytesPerSecond) override {}
   virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) override;
   virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
                           uint32_t aCount, uint32_t* aBytes) override;
+  virtual already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount) override;
   virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount) override;
   virtual nsresult Seek(int32_t aWhence, int64_t aOffset) override;
   virtual int64_t  Tell() override;
 
   // Any thread
   virtual void    Pin() override {}
   virtual void    Unpin() override {}
   virtual double  GetDownloadRate(bool* aIsReliable) override
@@ -1276,16 +1279,18 @@ protected:
   // calling. The implmentation of Read, Seek and ReadAt obtains the
   // lock before calling these Unsafe variants to read or seek.
   nsresult UnsafeRead(char* aBuffer, uint32_t aCount, uint32_t* aBytes);
   nsresult UnsafeSeek(int32_t aWhence, int64_t aOffset);
 private:
   // Ensures mSize is initialized, if it can be.
   // mLock must be held when this is called, and mInput must be non-null.
   void EnsureSizeInitialized();
+  already_AddRefed<MediaByteBuffer> UnsafeMediaReadAt(
+                        int64_t aOffset, uint32_t aCount);
 
   // The file size, or -1 if not known. Immutable after Open().
   // Can be used from any thread.
   int64_t mSize;
 
   // This lock handles synchronisation between calls to Close() and
   // the Read, Seek, etc calls. Close must not be called while a
   // Read or Seek is in progress since it resets various internal
@@ -1537,40 +1542,61 @@ nsresult FileMediaResource::ReadAt(int64
   }
   if (NS_SUCCEEDED(rv)) {
     DispatchBytesConsumed(*aBytes, aOffset);
   }
   return rv;
 }
 
 already_AddRefed<MediaByteBuffer>
+FileMediaResource::MediaReadAt(int64_t aOffset, uint32_t aCount)
+{
+  NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
+
+  MutexAutoLock lock(mLock);
+  return UnsafeMediaReadAt(aOffset, aCount);
+}
+
+already_AddRefed<MediaByteBuffer>
+FileMediaResource::UnsafeMediaReadAt(int64_t aOffset, uint32_t aCount)
+{
+  nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
+  bool ok = bytes->SetLength(aCount, fallible);
+  NS_ENSURE_TRUE(ok, nullptr);
+  nsresult rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
+  NS_ENSURE_SUCCESS(rv, nullptr);
+  char* curr = reinterpret_cast<char*>(bytes->Elements());
+  const char* start = curr;
+  while (aCount > 0) {
+    uint32_t bytesRead;
+    rv = UnsafeRead(curr, aCount, &bytesRead);
+    NS_ENSURE_SUCCESS(rv, nullptr);
+    if (!bytesRead) {
+      break;
+    }
+    aCount -= bytesRead;
+    curr += bytesRead;
+  }
+  bytes->SetLength(curr - start);
+  return bytes.forget();
+}
+
+already_AddRefed<MediaByteBuffer>
 FileMediaResource::SilentReadAt(int64_t aOffset, uint32_t aCount)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   MutexAutoLock lock(mLock);
-  nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
-  bool ok = bytes->SetCapacity(aCount, fallible);
-  NS_ENSURE_TRUE(ok, nullptr);
   int64_t pos = 0;
   NS_ENSURE_TRUE(mSeekable, nullptr);
   nsresult rv = mSeekable->Tell(&pos);
   NS_ENSURE_SUCCESS(rv, nullptr);
-  rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
-  NS_ENSURE_SUCCESS(rv, nullptr);
-  char* curr = reinterpret_cast<char*>(bytes->Elements());
-  while (aCount > 0) {
-    uint32_t bytesRead;
-    rv = UnsafeRead(curr, aCount, &bytesRead);
-    NS_ENSURE_SUCCESS(rv, nullptr);
-    NS_ENSURE_TRUE(bytesRead > 0, nullptr);
-    aCount -= bytesRead;
-    curr += bytesRead;
-  }
+  nsRefPtr<MediaByteBuffer> bytes = UnsafeMediaReadAt(aOffset, aCount);
   UnsafeSeek(nsISeekableStream::NS_SEEK_SET, pos);
+  NS_ENSURE_TRUE(bytes && bytes->Length() == aCount, nullptr);
   return bytes.forget();
 }
 
 nsresult FileMediaResource::Seek(int32_t aWhence, int64_t aOffset)
 {
   NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
 
   MutexAutoLock lock(mLock);
--- a/dom/media/MediaResource.h
+++ b/dom/media/MediaResource.h
@@ -284,41 +284,55 @@ public:
   // read, and call again if necessary.
   virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) = 0;
   // Read up to aCount bytes from the stream. The read starts at
   // aOffset in the stream, seeking to that location initially if
   // it is not the current stream offset. The remaining arguments,
   // results and requirements are the same as per the Read method.
   virtual nsresult ReadAt(int64_t aOffset, char* aBuffer,
                           uint32_t aCount, uint32_t* aBytes) = 0;
+  // This method returns nullptr if anything fails.
+  // Otherwise, it returns an owned buffer.
+  // MediaReadAt may return fewer bytes than requested if end of stream is
+  // encountered. There is no need to call it again to get more data.
+  virtual already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount)
+  {
+    nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
+    bool ok = bytes->SetLength(aCount, fallible);
+    NS_ENSURE_TRUE(ok, nullptr);
+    char* curr = reinterpret_cast<char*>(bytes->Elements());
+    const char* start = curr;
+    while (aCount > 0) {
+      uint32_t bytesRead;
+      nsresult rv = ReadAt(aOffset, curr, aCount, &bytesRead);
+      NS_ENSURE_SUCCESS(rv, nullptr);
+      if (!bytesRead) {
+        break;
+      }
+      aOffset += bytesRead;
+      aCount -= bytesRead;
+      curr += bytesRead;
+    }
+    bytes->SetLength(curr - start);
+    return bytes.forget();
+  }
 
   // ReadAt without side-effects. Given that our MediaResource infrastructure
   // is very side-effecty, this accomplishes its job by checking the initial
   // position and seeking back to it. If the seek were to fail, a side-effect
   // might be observable.
   //
   // This method returns null if anything fails, including the failure to read
   // aCount bytes. Otherwise, it returns an owned buffer.
   virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount)
   {
-    nsRefPtr<MediaByteBuffer> bytes = new MediaByteBuffer();
-    bool ok = bytes->SetCapacity(aCount, fallible);
-    NS_ENSURE_TRUE(ok, nullptr);
     int64_t pos = Tell();
-    char* curr = reinterpret_cast<char*>(bytes->Elements());
-    while (aCount > 0) {
-      uint32_t bytesRead;
-      nsresult rv = ReadAt(aOffset, curr, aCount, &bytesRead);
-      NS_ENSURE_SUCCESS(rv, nullptr);
-      NS_ENSURE_TRUE(bytesRead > 0, nullptr);
-      aOffset += bytesRead;
-      aCount -= bytesRead;
-      curr += bytesRead;
-    }
+    nsRefPtr<MediaByteBuffer> bytes = MediaReadAt(aOffset, aCount);
     Seek(nsISeekableStream::NS_SEEK_SET, pos);
+    NS_ENSURE_TRUE(bytes && bytes->Length() == aCount, nullptr);
     return bytes.forget();
   }
 
   // Seek to the given bytes offset in the stream. aWhence can be
   // one of:
   //   NS_SEEK_SET
   //   NS_SEEK_CUR
   //   NS_SEEK_END
@@ -635,17 +649,17 @@ public:
   virtual void     EnsureCacheUpToDate() override;
 
   // Other thread
   virtual void     SetReadMode(MediaCacheStream::ReadMode aMode) override;
   virtual void     SetPlaybackRate(uint32_t aBytesPerSecond) override;
   virtual nsresult Read(char* aBuffer, uint32_t aCount, uint32_t* aBytes) override;
   virtual nsresult ReadAt(int64_t offset, char* aBuffer,
                           uint32_t aCount, uint32_t* aBytes) override;
-  virtual already_AddRefed<MediaByteBuffer> SilentReadAt(int64_t aOffset, uint32_t aCount) override;
+  virtual already_AddRefed<MediaByteBuffer> MediaReadAt(int64_t aOffset, uint32_t aCount) override;
   virtual nsresult Seek(int32_t aWhence, int64_t aOffset) override;
   virtual int64_t  Tell() override;
 
   // Any thread
   virtual void    Pin() override;
   virtual void    Unpin() override;
   virtual double  GetDownloadRate(bool* aIsReliable) override;
   virtual int64_t GetLength() override;