Bug 1182933: Implement MediaReadAt. r=bholley

Ensure SilentReadAt seek back to original position even in case of error.
Properly set the MediaByteBuffer length.
This commit is contained in:
Jean-Yves Avenard 2015-07-10 16:08:07 +10:00
parent 3f3b036b5f
commit d2d40f98bd
2 changed files with 73 additions and 33 deletions

View File

@ -759,25 +759,27 @@ nsresult ChannelMediaResource::ReadAt(int64_t aOffset,
}
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();
}
@ -1217,6 +1219,7 @@ public:
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;
@ -1281,6 +1284,8 @@ 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.
@ -1541,31 +1546,52 @@ nsresult FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
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();
}

View File

@ -289,6 +289,31 @@ public:
// 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
@ -299,21 +324,10 @@ public:
// 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();
}
@ -640,7 +654,7 @@ public:
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;