nsresult sbWindowWatcher::RemoveWindow(nsIDOMWindow* aWindow) { // Validate arguments. NS_ASSERTION(aWindow, "aWindow is null"); // Function variables. bool success; nsresult rv; // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Get the removed window information. WindowInfo* windowInfo; success = mWindowInfoTable.Get(aWindow, &windowInfo); if (!success) windowInfo = nsnull; // Remove listener for the end of window overlay load events. if (windowInfo) { rv = windowInfo->eventListener->ClearEventListeners(); NS_ENSURE_SUCCESS(rv, rv); } // Remove the closed window from the window information map. mWindowInfoTable.Remove(aWindow); // Remove the closed window from the window list. mWindowList.RemoveObject(aWindow); return NS_OK; }
void sbWindowWatcher::Shutdown() { // Validate state. NS_ASSERTION(SB_IsMainThread(mThreadManager), "not on main thread"); // Operate within the monitor. { mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Do nothing if already shutting down. if (mIsShuttingDown) return; // Indicate that this instance is shutting down. mIsShuttingDown = PR_TRUE; } // Remove quit-application-granted observer. mObserverService->RemoveObserver(this, "quit-application-granted"); // Invoke all call with window callbacks. InvokeCallWithWindowCallbacks(nsnull); // Remove window watcher observer. if (mWindowWatcher) mWindowWatcher->UnregisterNotification(this); }
NS_IMETHODIMP sbWindowWatcher::WaitForWindow(const nsAString& aWindowType) { nsresult rv; // This method may not be called on the main thread. NS_ENSURE_TRUE(!SB_IsMainThread(mThreadManager), NS_ERROR_UNEXPECTED); // Don't wait if this instance is shutting down. { // Check is shutting down within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); if (mIsShuttingDown) return NS_OK; } // Create a wait for window object. nsRefPtr<sbWindowWatcherWaitForWindow> waitForWindow; rv = sbWindowWatcherWaitForWindow::New(getter_AddRefs(waitForWindow)); NS_ENSURE_SUCCESS(rv, rv); // Wait for the window. rv = waitForWindow->Wait(aWindowType); NS_ENSURE_SUCCESS(rv, rv); return NS_OK; }
nsresult sbWindowWatcher::AddWindow(nsIDOMWindow* aWindow) { // Validate arguments and state. NS_ASSERTION(aWindow, "aWindow is null"); // Function variables. bool success; nsresult rv; // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Create the window info object. nsAutoPtr<WindowInfo> windowInfo; windowInfo = new WindowInfo(); NS_ENSURE_TRUE(windowInfo, NS_ERROR_OUT_OF_MEMORY); windowInfo->window = aWindow; // Get the window event target. nsCOMPtr<nsIDOMWindow> window = do_QueryInterface(aWindow, &rv); NS_ENSURE_SUCCESS(rv, rv); nsCOMPtr<nsIDOMEventTarget> windowEventTarget; rv = window->GetWindowRoot(getter_AddRefs(windowEventTarget)); NS_ENSURE_SUCCESS(rv, rv); windowInfo->eventTarget = windowEventTarget; // Create a window event listener. nsRefPtr<sbWindowWatcherEventListener> eventListener; rv = sbWindowWatcherEventListener::New(getter_AddRefs(eventListener), this, aWindow); NS_ENSURE_SUCCESS(rv, rv); windowInfo->eventListener = eventListener; // Add the window info to the window info table. mWindowInfoTable.Put(aWindow, windowInfo.forget()); // Add the opened window to the window list. success = mWindowList.AppendObject(aWindow); NS_ENSURE_TRUE(success, NS_ERROR_FAILURE); // Listen for when the window has opened completely. // Due to annoying platform differences, we need to figure out when the // _last_ of a combination of events to occur (but the first instance of each) const char* DOM_WINDOW_READY_EVENT_TYPES[] = { "resize", "sb-overlay-load" }; for (unsigned int i = 0; i < NS_ARRAY_LENGTH(DOM_WINDOW_READY_EVENT_TYPES); ++i) { rv = eventListener->AddEventListener(DOM_WINDOW_READY_EVENT_TYPES[i]); NS_ENSURE_SUCCESS(rv, rv); } return NS_OK; }
nsresult nsRawReader::Seek(PRInt64 aTime, PRInt64 aStartTime, PRInt64 aEndTime, PRInt64 aCurrentTime) { mozilla::MonitorAutoEnter autoEnter(mMonitor); NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread."); nsMediaStream *stream = mDecoder->GetCurrentStream(); NS_ASSERTION(stream, "Decoder has no media stream"); PRUint32 frame = mCurrentFrame; if (aTime >= UINT_MAX) return NS_ERROR_FAILURE; mCurrentFrame = aTime * mFrameRate / USECS_PER_S; PRUint32 offset; if (!MulOverflow32(mCurrentFrame, mFrameSize, offset)) return NS_ERROR_FAILURE; offset += sizeof(nsRawVideoHeader); nsresult rv = stream->Seek(nsISeekableStream::NS_SEEK_SET, offset); NS_ENSURE_SUCCESS(rv, rv); mVideoQueue.Erase(); while(mVideoQueue.GetSize() == 0) { PRBool keyframeSkip = PR_FALSE; if (!DecodeVideoFrame(keyframeSkip, 0)) { mCurrentFrame = frame; return NS_ERROR_FAILURE; } { mozilla::MonitorAutoExit autoMonitorExit(mMonitor); mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) { mCurrentFrame = frame; return NS_ERROR_FAILURE; } } nsAutoPtr<VideoData> video(mVideoQueue.PeekFront()); if (video && video->mEndTime < aTime) { mVideoQueue.PopFront(); video = nsnull; } else { video.forget(); } } return NS_OK; }
void sbWindowWatcher::RemoveAllWindows() { // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Remove all of the windows. PRInt32 windowCount = mWindowList.Count(); for (PRInt32 i = windowCount - 1; i >= 0; i--) { RemoveWindow(mWindowList[i]); } }
NS_IMETHODIMP sbWindowWatcher::GetIsShuttingDown(bool* aIsShuttingDown) { // Validate arguments. NS_ENSURE_ARG_POINTER(aIsShuttingDown); // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Return results. *aIsShuttingDown = mIsShuttingDown; return NS_OK; }
nsresult nsRawReader::Seek(int64_t aTime, int64_t aStartTime, int64_t aEndTime, int64_t aCurrentTime) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); MediaResource *resource = mDecoder->GetResource(); NS_ASSERTION(resource, "Decoder has no media resource"); uint32_t frame = mCurrentFrame; if (aTime >= UINT_MAX) return NS_ERROR_FAILURE; mCurrentFrame = aTime * mFrameRate / USECS_PER_S; CheckedUint32 offset = CheckedUint32(mCurrentFrame) * mFrameSize; offset += sizeof(nsRawVideoHeader); NS_ENSURE_TRUE(offset.isValid(), NS_ERROR_FAILURE); nsresult rv = resource->Seek(nsISeekableStream::NS_SEEK_SET, offset.value()); NS_ENSURE_SUCCESS(rv, rv); mVideoQueue.Erase(); while(mVideoQueue.GetSize() == 0) { bool keyframeSkip = false; if (!DecodeVideoFrame(keyframeSkip, 0)) { mCurrentFrame = frame; return NS_ERROR_FAILURE; } { mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor()); if (mDecoder->GetDecodeState() == nsBuiltinDecoderStateMachine::DECODER_STATE_SHUTDOWN) { mCurrentFrame = frame; return NS_ERROR_FAILURE; } } nsAutoPtr<VideoData> video(mVideoQueue.PeekFront()); if (video && video->mEndTime < aTime) { mVideoQueue.PopFront(); video = nullptr; } else { video.forget(); } } return NS_OK; }
nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); nsMediaStream* stream = mDecoder->GetCurrentStream(); NS_ASSERTION(stream, "Decoder has no media stream"); if (!ReadFromStream(stream, reinterpret_cast<PRUint8*>(&mMetadata), sizeof(mMetadata))) return NS_ERROR_FAILURE; // Validate the header if (!(mMetadata.headerPacketID == 0 /* Packet ID of 0 for the header*/ && mMetadata.codecID == RAW_ID /* "YUV" */ && mMetadata.majorVersion == 0 && mMetadata.minorVersion == 1)) return NS_ERROR_FAILURE; PRUint32 dummy; if (!MulOverflow32(mMetadata.frameWidth, mMetadata.frameHeight, dummy)) return NS_ERROR_FAILURE; if (mMetadata.aspectDenominator == 0 || mMetadata.framerateDenominator == 0) return NS_ERROR_FAILURE; // Invalid data // Determine and verify frame display size. float pixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) / mMetadata.aspectDenominator; nsIntSize display(mMetadata.frameWidth, mMetadata.frameHeight); ScaleDisplayByAspectRatio(display, pixelAspectRatio); mPicture = nsIntRect(0, 0, mMetadata.frameWidth, mMetadata.frameHeight); nsIntSize frameSize(mMetadata.frameWidth, mMetadata.frameHeight); if (!nsVideoInfo::ValidateVideoRegion(frameSize, mPicture, display)) { // Video track's frame sizes will overflow. Fail. return NS_ERROR_FAILURE; } mInfo.mHasVideo = true; mInfo.mHasAudio = false; mInfo.mDisplay = display; mFrameRate = static_cast<float>(mMetadata.framerateNumerator) / mMetadata.framerateDenominator; // Make some sanity checks if (mFrameRate > 45 || mFrameRate == 0 || pixelAspectRatio == 0 || mMetadata.frameWidth > 2000 || mMetadata.frameHeight > 2000 || mMetadata.chromaChannelBpp != 4 || mMetadata.lumaChannelBpp != 8 || mMetadata.colorspace != 1 /* 4:2:0 */) return NS_ERROR_FAILURE; mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight * (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 + sizeof(nsRawPacketHeader); PRInt64 length = stream->GetLength(); if (length != -1) { mozilla::ReentrantMonitorAutoEnter autoMonitor(mDecoder->GetReentrantMonitor()); mDecoder->GetStateMachine()->SetDuration(USECS_PER_S * (length - sizeof(nsRawVideoHeader)) / (mFrameSize * mFrameRate)); } *aInfo = mInfo; return NS_OK; }
nsresult nsRawReader::ReadMetadata(nsVideoInfo* aInfo) { NS_ASSERTION(mDecoder->OnStateMachineThread(), "Should be on state machine thread."); mozilla::MonitorAutoEnter autoEnter(mMonitor); nsMediaStream* stream = mDecoder->GetCurrentStream(); NS_ASSERTION(stream, "Decoder has no media stream"); if (!ReadFromStream(stream, reinterpret_cast<PRUint8*>(&mMetadata), sizeof(mMetadata))) return NS_ERROR_FAILURE; // Validate the header if (!(mMetadata.headerPacketID == 0 /* Packet ID of 0 for the header*/ && mMetadata.codecID == RAW_ID /* "YUV" */ && mMetadata.majorVersion == 0 && mMetadata.minorVersion == 1)) return NS_ERROR_FAILURE; PRUint32 dummy; if (!MulOverflow32(mMetadata.frameWidth, mMetadata.frameHeight, dummy)) return NS_ERROR_FAILURE; mInfo.mHasVideo = PR_TRUE; mInfo.mPicture.x = 0; mInfo.mPicture.y = 0; mInfo.mPicture.width = mMetadata.frameWidth; mInfo.mPicture.height = mMetadata.frameHeight; mInfo.mFrame.width = mMetadata.frameWidth; mInfo.mFrame.height = mMetadata.frameHeight; if (mMetadata.aspectDenominator == 0 || mMetadata.framerateDenominator == 0) return NS_ERROR_FAILURE; // Invalid data mInfo.mPixelAspectRatio = static_cast<float>(mMetadata.aspectNumerator) / mMetadata.aspectDenominator; mInfo.mHasAudio = PR_FALSE; mFrameRate = static_cast<float>(mMetadata.framerateNumerator) / mMetadata.framerateDenominator; // Make some sanity checks if (mFrameRate > 45 || mFrameRate == 0 || mInfo.mPixelAspectRatio == 0 || mMetadata.frameWidth > 2000 || mMetadata.frameHeight > 2000 || mMetadata.chromaChannelBpp != 4 || mMetadata.lumaChannelBpp != 8 || mMetadata.colorspace != 1 /* 4:2:0 */) return NS_ERROR_FAILURE; mFrameSize = mMetadata.frameWidth * mMetadata.frameHeight * (mMetadata.lumaChannelBpp + mMetadata.chromaChannelBpp) / 8.0 + sizeof(nsRawPacketHeader); PRInt64 length = stream->GetLength(); if (length != -1) { mozilla::MonitorAutoExit autoExitMonitor(mMonitor); mozilla::MonitorAutoEnter autoMonitor(mDecoder->GetMonitor()); mDecoder->GetStateMachine()->SetDuration(USECS_PER_S * (length - sizeof(nsRawVideoHeader)) / (mFrameSize * mFrameRate)); } *aInfo = mInfo; return NS_OK; }
NS_IMETHODIMP sbWindowWatcher::GetWindow(const nsAString& aWindowType, nsIDOMWindow** _retval) { // Validate arguments. NS_ENSURE_ARG_POINTER(_retval); // Function variables. nsCOMPtr<nsIDOMWindow> retWindow; bool success; nsresult rv; // This method may only be called on the main thread. NS_ENSURE_TRUE(SB_IsMainThread(mThreadManager), NS_ERROR_UNEXPECTED); // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Get an enumerator of all windows of the specified type, sorted from oldest // to youngest. nsCOMPtr<nsISimpleEnumerator> enumerator; rv = mWindowMediator->GetEnumerator(aWindowType.BeginReading(), getter_AddRefs(enumerator)); NS_ENSURE_SUCCESS(rv, rv); // Search for the most recently focused ready window of the specified type. // The enumerator enumerates from oldest to youngest (least recently focused // to most recently), so the last matching window is the most recently focused // one. bool hasMoreElements; rv = enumerator->HasMoreElements(&hasMoreElements); NS_ENSURE_SUCCESS(rv, rv); while (hasMoreElements) { // Get the window. Skip if not ready. nsCOMPtr<nsISupports> _window; nsCOMPtr<nsIDOMWindow> window; rv = enumerator->GetNext(getter_AddRefs(_window)); NS_ENSURE_SUCCESS(rv, rv); window = do_QueryInterface(_window, &rv); NS_ENSURE_SUCCESS(rv, rv); rv = enumerator->HasMoreElements(&hasMoreElements); NS_ENSURE_SUCCESS(rv, rv); // Skip window if not ready. WindowInfo* windowInfo; success = mWindowInfoTable.Get(window, &windowInfo); if (!success || !(windowInfo->isReady)) continue; // Get the window type. nsAutoString windowType; rv = GetWindowType(window, windowType); if (NS_FAILED(rv)) continue; // Check for a match. if (aWindowType.Equals(windowType)) { retWindow = window; } } // Return results. NS_IF_ADDREF(*_retval = retWindow); return NS_OK; }
nsresult sbWindowWatcher::CallWithWindow_Proxy(const nsAString& aWindowType, sbICallWithWindowCallback* aCallback, bool aWait) { // Validate arguments. NS_ENSURE_ARG_POINTER(aCallback); // Function variables. nsresult rv; // If not on main thread, call back through a proxy. if (!SB_IsMainThread(mThreadManager)) { nsRefPtr<sbRunnable_<nsresult>> job = new sbRunnableMethod3_<nsresult,sbWindowWatcher, const nsAString&,sbICallWithWindowCallback*,bool>( *this,&sbWindowWatcher::CallWithWindow_Proxy, aWindowType,aCallback,aWait); // Call back through the proxy. Wait for window if specified to do so. rv = NS_OK; while (1) { // Call the proxied window watcher. Exit loop on success or if not // waiting. NS_DispatchToMainThread(job); rv = job->Wait(); if (NS_SUCCEEDED(rv) || !aWait) break; if (rv != NS_ERROR_NOT_AVAILABLE) NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // Wait for a window if none available. rv = WaitForWindow(aWindowType); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); } NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); return NS_OK; } // Operate within the monitor. mozilla::ReentrantMonitorAutoEnter autoMonitor(mMonitor); // Check if window is already available. nsCOMPtr<nsIDOMWindow> window; rv = GetWindow(aWindowType, getter_AddRefs(window)); NS_ENSURE_SUCCESS(rv, NS_ERROR_FAILURE); // If a window is available or this instance is shutting down, call the // callback. Otherwise, place the call with window information on the call // with window list. if (window || mIsShuttingDown) { aCallback->HandleWindowCallback(window); } else { // If specified to wait and the window is not available, return a not // available error indication instead of enqueuing onto the call with window // list. if (aWait) return NS_ERROR_NOT_AVAILABLE; // Place the call with window information on the call with window list. CallWithWindowInfo callWithWindowInfo; callWithWindowInfo.windowType = aWindowType; callWithWindowInfo.callback = aCallback; mCallWithWindowList.AppendElement(callWithWindowInfo); } return NS_OK; }