summaryrefslogtreecommitdiffstats
path: root/dom/media/BaseMediaResource.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'dom/media/BaseMediaResource.cpp')
-rw-r--r--dom/media/BaseMediaResource.cpp171
1 files changed, 171 insertions, 0 deletions
diff --git a/dom/media/BaseMediaResource.cpp b/dom/media/BaseMediaResource.cpp
new file mode 100644
index 0000000000..e5ba50109a
--- /dev/null
+++ b/dom/media/BaseMediaResource.cpp
@@ -0,0 +1,171 @@
+/* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */
+/* vim: set ts=8 sts=2 et sw=2 tw=80: */
+/* 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 "BaseMediaResource.h"
+
+#include "ChannelMediaResource.h"
+#include "CloneableWithRangeMediaResource.h"
+#include "FileMediaResource.h"
+#include "MediaContainerType.h"
+#include "mozilla/dom/BlobImpl.h"
+#include "mozilla/dom/BlobURLProtocolHandler.h"
+#include "mozilla/dom/HTMLMediaElement.h"
+#include "mozilla/InputStreamLengthHelper.h"
+#include "nsDebug.h"
+#include "nsError.h"
+#include "nsICloneableInputStream.h"
+#include "nsIFile.h"
+#include "nsIFileChannel.h"
+#include "nsIInputStream.h"
+#include "nsNetUtil.h"
+
+namespace mozilla {
+
+already_AddRefed<BaseMediaResource> BaseMediaResource::Create(
+ MediaResourceCallback* aCallback, nsIChannel* aChannel,
+ bool aIsPrivateBrowsing) {
+ NS_ASSERTION(NS_IsMainThread(),
+ "MediaResource::Open called on non-main thread");
+
+ // If the channel was redirected, we want the post-redirect URI;
+ // but if the URI scheme was expanded, say from chrome: to jar:file:,
+ // we want the original URI.
+ nsCOMPtr<nsIURI> uri;
+ nsresult rv = NS_GetFinalChannelURI(aChannel, getter_AddRefs(uri));
+ NS_ENSURE_SUCCESS(rv, nullptr);
+
+ nsAutoCString contentTypeString;
+ aChannel->GetContentType(contentTypeString);
+ Maybe<MediaContainerType> containerType =
+ MakeMediaContainerType(contentTypeString);
+ if (!containerType) {
+ return nullptr;
+ }
+
+ // Let's try to create a FileMediaResource in case the channel is a nsIFile
+ nsCOMPtr<nsIFileChannel> fc = do_QueryInterface(aChannel);
+ if (fc) {
+ RefPtr<BaseMediaResource> resource =
+ new FileMediaResource(aCallback, aChannel, uri);
+ return resource.forget();
+ }
+
+ int64_t streamLength = -1;
+
+ RefPtr<mozilla::dom::BlobImpl> blobImpl;
+ if (dom::IsBlobURI(uri) &&
+ NS_SUCCEEDED(NS_GetBlobForBlobURI(uri, getter_AddRefs(blobImpl))) &&
+ blobImpl) {
+ IgnoredErrorResult rv;
+
+ nsCOMPtr<nsIInputStream> stream;
+ blobImpl->CreateInputStream(getter_AddRefs(stream), rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ return nullptr;
+ }
+
+ // If this stream knows its own size synchronously, we can still use
+ // FileMediaResource. If the size is known, it means that the reading
+ // doesn't require any async operation. This is required because
+ // FileMediaResource doesn't work with nsIAsyncInputStreams.
+ int64_t length;
+ if (InputStreamLengthHelper::GetSyncLength(stream, &length) &&
+ length >= 0) {
+ RefPtr<BaseMediaResource> resource =
+ new FileMediaResource(aCallback, aChannel, uri, length);
+ return resource.forget();
+ }
+
+ // Also if the stream doesn't know its own size synchronously, we can still
+ // read the length from the blob.
+ uint64_t size = blobImpl->GetSize(rv);
+ if (NS_WARN_IF(rv.Failed())) {
+ return nullptr;
+ }
+
+ // Maybe this blob URL can be cloned with a range.
+ nsCOMPtr<nsICloneableInputStreamWithRange> cloneableWithRange =
+ do_QueryInterface(stream);
+ if (cloneableWithRange) {
+ RefPtr<BaseMediaResource> resource = new CloneableWithRangeMediaResource(
+ aCallback, aChannel, uri, stream, size);
+ return resource.forget();
+ }
+
+ // We know the size of the stream for blobURLs, let's use it.
+ streamLength = size;
+ }
+
+ RefPtr<BaseMediaResource> resource = new ChannelMediaResource(
+ aCallback, aChannel, uri, streamLength, aIsPrivateBrowsing);
+ return resource.forget();
+}
+
+void BaseMediaResource::SetLoadInBackground(bool aLoadInBackground) {
+ if (aLoadInBackground == mLoadInBackground) {
+ return;
+ }
+ mLoadInBackground = aLoadInBackground;
+ if (!mChannel) {
+ // No channel, resource is probably already loaded.
+ return;
+ }
+
+ MediaDecoderOwner* owner = mCallback->GetMediaOwner();
+ if (!owner) {
+ NS_WARNING("Null owner in MediaResource::SetLoadInBackground()");
+ return;
+ }
+ RefPtr<dom::HTMLMediaElement> element = owner->GetMediaElement();
+ if (!element) {
+ NS_WARNING("Null element in MediaResource::SetLoadInBackground()");
+ return;
+ }
+
+ bool isPending = false;
+ if (NS_SUCCEEDED(mChannel->IsPending(&isPending)) && isPending) {
+ nsLoadFlags loadFlags;
+ DebugOnly<nsresult> rv = mChannel->GetLoadFlags(&loadFlags);
+ NS_ASSERTION(NS_SUCCEEDED(rv), "GetLoadFlags() failed!");
+
+ if (aLoadInBackground) {
+ loadFlags |= nsIRequest::LOAD_BACKGROUND;
+ } else {
+ loadFlags &= ~nsIRequest::LOAD_BACKGROUND;
+ }
+ Unused << NS_WARN_IF(NS_FAILED(ModifyLoadFlags(loadFlags)));
+ }
+}
+
+nsresult BaseMediaResource::ModifyLoadFlags(nsLoadFlags aFlags) {
+ nsCOMPtr<nsILoadGroup> loadGroup;
+ nsresult rv = mChannel->GetLoadGroup(getter_AddRefs(loadGroup));
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "GetLoadGroup() failed!");
+
+ bool inLoadGroup = false;
+ if (loadGroup) {
+ nsresult status;
+ mChannel->GetStatus(&status);
+
+ rv = loadGroup->RemoveRequest(mChannel, nullptr, status);
+ if (NS_WARN_IF(NS_FAILED(rv))) {
+ return rv;
+ }
+ inLoadGroup = true;
+ }
+
+ rv = mChannel->SetLoadFlags(aFlags);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "SetLoadFlags() failed!");
+
+ if (inLoadGroup) {
+ rv = loadGroup->AddRequest(mChannel, nullptr);
+ MOZ_ASSERT(NS_SUCCEEDED(rv), "AddRequest() failed!");
+ }
+
+ return NS_OK;
+}
+
+} // namespace mozilla