summaryrefslogtreecommitdiffstats
path: root/dom/media/FileMediaResource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/FileMediaResource.cpp')
-rw-r--r--dom/media/FileMediaResource.cpp223
1 files changed, 223 insertions, 0 deletions
diff --git a/dom/media/FileMediaResource.cpp b/dom/media/FileMediaResource.cpp
new file mode 100644
index 0000000000..16bcc5c3de
--- /dev/null
+++ b/dom/media/FileMediaResource.cpp
@@ -0,0 +1,223 @@
+/* vim:set ts=2 sw=2 sts=2 et cindent: */
+/* 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/. */
+
+#include "FileMediaResource.h"
+
+#include "mozilla/AbstractThread.h"
+#include "mozilla/dom/BlobImpl.h"
+#include "mozilla/dom/BlobURLProtocolHandler.h"
+#include "nsContentUtils.h"
+#include "nsIFile.h"
+#include "nsIFileChannel.h"
+#include "nsIFileStreams.h"
+#include "nsITimedChannel.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+
+void FileMediaResource::EnsureSizeInitialized() {
+ mLock.AssertCurrentThreadOwns();
+ NS_ASSERTION(mInput, "Must have file input stream");
+ if (mSizeInitialized && mNotifyDataEndedProcessed) {
+ return;
+ }
+
+ if (!mSizeInitialized) {
+ // Get the file size and inform the decoder.
+ uint64_t size;
+ nsresult res = mInput->Available(&size);
+ if (NS_SUCCEEDED(res) && size <= INT64_MAX) {
+ mSize = (int64_t)size;
+ }
+ }
+ mSizeInitialized = true;
+ if (!mNotifyDataEndedProcessed && mSize >= 0) {
+ mCallback->AbstractMainThread()->Dispatch(NewRunnableMethod<nsresult>(
+ "MediaResourceCallback::NotifyDataEnded", mCallback.get(),
+ &MediaResourceCallback::NotifyDataEnded, NS_OK));
+ }
+ mNotifyDataEndedProcessed = true;
+}
+
+nsresult FileMediaResource::GetCachedRanges(MediaByteRangeSet& aRanges) {
+ MutexAutoLock lock(mLock);
+
+ EnsureSizeInitialized();
+ if (mSize == -1) {
+ return NS_ERROR_FAILURE;
+ }
+ aRanges += MediaByteRange(0, mSize);
+ return NS_OK;
+}
+
+nsresult FileMediaResource::Open(nsIStreamListener** aStreamListener) {
+ NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+ MOZ_ASSERT(aStreamListener);
+
+ *aStreamListener = nullptr;
+ nsresult rv = NS_OK;
+
+ MutexAutoLock lock(mLock);
+ // The channel is already open. We need a synchronous stream that
+ // implements nsISeekableStream, so we have to find the underlying
+ // file and reopen it
+ nsCOMPtr<nsIFileChannel> fc(do_QueryInterface(mChannel));
+ if (fc) {
+ nsCOMPtr<nsIFile> file;
+ rv = fc->GetFile(getter_AddRefs(file));
+ NS_ENSURE_SUCCESS(rv, rv);
+
+ rv = NS_NewLocalFileInputStream(getter_AddRefs(mInput), file, -1, -1,
+ nsIFileInputStream::SHARE_DELETE);
+ NS_ENSURE_SUCCESS(rv, rv);
+ } else if (dom::IsBlobURI(mURI)) {
+ RefPtr<dom::BlobImpl> blobImpl;
+ rv = NS_GetBlobForBlobURI(mURI, getter_AddRefs(blobImpl));
+ NS_ENSURE_SUCCESS(rv, rv);
+ MOZ_ASSERT(blobImpl);
+
+ ErrorResult err;
+ blobImpl->CreateInputStream(getter_AddRefs(mInput), err);
+ if (NS_WARN_IF(err.Failed())) {
+ return err.StealNSResult();
+ }
+ }
+
+ mSeekable = do_QueryInterface(mInput);
+ if (!mSeekable) {
+ // XXX The file may just be a .url or similar
+ // shortcut that points to a Web site. We need to fix this by
+ // doing an async open and waiting until we locate the real resource,
+ // then using that (if it's still a file!).
+ return NS_ERROR_FAILURE;
+ }
+
+ return NS_OK;
+}
+
+RefPtr<GenericPromise> FileMediaResource::Close() {
+ NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+
+ // Since mChennel is only accessed by main thread, there is no necessary to
+ // take the lock.
+ if (mChannel) {
+ mChannel->Cancel(NS_ERROR_PARSED_DATA_CACHED);
+ mChannel = nullptr;
+ }
+
+ return GenericPromise::CreateAndResolve(true, __func__);
+}
+
+already_AddRefed<nsIPrincipal> FileMediaResource::GetCurrentPrincipal() {
+ NS_ASSERTION(NS_IsMainThread(), "Only call on main thread");
+
+ nsCOMPtr<nsIPrincipal> principal;
+ nsIScriptSecurityManager* secMan = nsContentUtils::GetSecurityManager();
+ if (!secMan || !mChannel) return nullptr;
+ secMan->GetChannelResultPrincipal(mChannel, getter_AddRefs(principal));
+ return principal.forget();
+}
+
+bool FileMediaResource::HadCrossOriginRedirects() {
+ MOZ_ASSERT(NS_IsMainThread());
+
+ nsCOMPtr<nsITimedChannel> timedChannel = do_QueryInterface(mChannel);
+ if (!timedChannel) {
+ return false;
+ }
+
+ bool allRedirectsSameOrigin = false;
+ return NS_SUCCEEDED(timedChannel->GetAllRedirectsSameOrigin(
+ &allRedirectsSameOrigin)) &&
+ !allRedirectsSameOrigin;
+}
+
+nsresult FileMediaResource::ReadFromCache(char* aBuffer, int64_t aOffset,
+ uint32_t aCount) {
+ MutexAutoLock lock(mLock);
+
+ EnsureSizeInitialized();
+ if (!aCount) {
+ return NS_OK;
+ }
+ int64_t offset = 0;
+ nsresult res = mSeekable->Tell(&offset);
+ NS_ENSURE_SUCCESS(res, res);
+ res = mSeekable->Seek(nsISeekableStream::NS_SEEK_SET, aOffset);
+ NS_ENSURE_SUCCESS(res, res);
+ uint32_t bytesRead = 0;
+ do {
+ uint32_t x = 0;
+ uint32_t bytesToRead = aCount - bytesRead;
+ res = mInput->Read(aBuffer, bytesToRead, &x);
+ bytesRead += x;
+ if (!x) {
+ res = NS_ERROR_FAILURE;
+ }
+ } while (bytesRead != aCount && res == NS_OK);
+
+ // 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);
+
+ // 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);
+}
+
+nsresult FileMediaResource::ReadAt(int64_t aOffset, char* aBuffer,
+ uint32_t aCount, uint32_t* aBytes) {
+ NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
+
+ nsresult rv;
+ {
+ MutexAutoLock lock(mLock);
+ rv = UnsafeSeek(nsISeekableStream::NS_SEEK_SET, aOffset);
+ if (NS_FAILED(rv)) return rv;
+ rv = UnsafeRead(aBuffer, aCount, aBytes);
+ }
+ return rv;
+}
+
+already_AddRefed<MediaByteBuffer> FileMediaResource::UnsafeMediaReadAt(
+ int64_t aOffset, uint32_t aCount) {
+ RefPtr<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();
+}
+
+nsresult FileMediaResource::UnsafeSeek(int32_t aWhence, int64_t aOffset) {
+ NS_ASSERTION(!NS_IsMainThread(), "Don't call on main thread");
+
+ if (!mSeekable) return NS_ERROR_FAILURE;
+ EnsureSizeInitialized();
+ return mSeekable->Seek(aWhence, aOffset);
+}
+
+} // namespace mozilla