int main(int argc, char *argv[]) { register char *s, *p; register char *pn = argv[0]; // configure the I/O ports AD1PCFG = 0xFFFF; // Default all pins to digital mJTAGPortEnable(0); // turn off jtag // setup the CPU SYSTEMConfigPerformance(CLOCKFREQ); // System config performance mOSCSetPBDIV(OSC_PB_DIV_1); // fix the peripheral bus to half main clock speed INTEnableSystemMultiVectoredInt(); TRISBbits.TRISB15 = 0; // TRISDbits.TRISD11 = 0; // ODCDbits.ODCD11 = 1; // LATDbits.LATD11=0; TRISBbits.TRISB13 = 0; ODCBbits.ODCB13 = 1; PORTBbits.RB13=0; #ifdef UARTConsole UARTInit(); #endif initKeyboard(); #ifdef UseVideo initVideo(); #endif #ifdef CPU_SPEED f_flag = CPU_SPEED; tmax = CPU_SPEED * 10000; #endif argc = 0; while (--argc > 0 && (*++argv)[0] == '-') for (s = argv[0] + 1; *s != '\0'; s++) switch (*s) { case 's': /* save core and CPU on exit */ s_flag = 1; break; case 'l': /* load core and CPU from file */ l_flag = 1; break; #ifdef Z80_UNDOC case 'z': /* trap undocumented Z80 ops */ z_flag = 1; break; #endif case 'i': /* trap I/O on unused ports */ i_flag = 1; break; case 'm': /* initialize Z80 memory */ m_flag = exatoi(s + 1); s += strlen(s + 1); break; case 'f': /* set emulation speed */ f_flag = atoi(s + 1); s += strlen(s + 1); tmax = f_flag * 10000; break; case 'x': /* get filename with Z80 executable */ x_flag = 1; s++; p = xfn; while (*s) *p++ = *s++; *p = '\0'; s--; break; case '?': goto usage; default: printf("illegal option %c\n", *s); #ifndef Z80_UNDOC usage: printf("usage:\t%s -s -l -i -mn -fn -xfilename\n", pn); #else usage: printf("usage:\t%s -s -l -i -z -mn -fn -xfilename\n", pn); #endif puts("\ts = save core and cpu"); puts("\tl = load core and cpu"); puts("\ti = trap on I/O to unused ports"); #ifdef Z80_UNDOC puts("\tz = trap on undocumented Z80 ops"); #endif puts("\tm = init memory with n"); puts("\tf = CPU frequenzy n in MHz"); puts("\tx = load and execute filename"); exit(1); } putchar('\n'); puts("####### ##### ### ##### ### # #"); puts(" # # # # # # # # ## ##"); puts(" # # # # # # # # # # #"); puts(" # ##### # # ##### ##### # # # #"); puts(" # # # # # # # # #"); puts(" # # # # # # # # # #"); puts("####### ##### ### ##### ### # #"); printf("\nRelease %s, %s\n", RELEASE, COPYR); printf("\nPort to PIC32 By kenseglerdesigns.com\n"); if (f_flag > 0) printf("\nCPU speed is %d MHz\n", f_flag); else printf("\nCPU speed is unlimited\n"); #ifdef USR_COM printf("\n%s Release %s, %s\n", USR_COM, USR_REL, USR_CPR); #endif fflush(stdout); wrk_ram = PC = ram; STACK = ram +0xffff; memset((char *) ram, m_flag, 65536); if (l_flag) if (load_core()) return (1); int_on(); init_io(); mon(); if (s_flag) save_core(); exit_io(); int_off(); return (0); }
nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); *aTags = nullptr; // Initialize the internal OMX Decoder. nsresult rv = InitOmxDecoder(); if (NS_FAILED(rv)) { return rv; } if (!mOmxDecoder->TryLoad()) { return NS_ERROR_FAILURE; } #ifdef MOZ_AUDIO_OFFLOAD CheckAudioOffload(); #endif if (IsWaitingMediaResources()) { return NS_OK; } // Set the total duration (the max of the audio and video track). int64_t durationUs; mOmxDecoder->GetDuration(&durationUs); if (durationUs) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(durationUs); } if (mOmxDecoder->HasVideo()) { int32_t displayWidth, displayHeight, width, height; mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight, &width, &height); nsIntRect pictureRect(0, 0, width, height); // Validate the container-reported frame and pictureRect sizes. This ensures // that our video frame creation code doesn't overflow. nsIntSize displaySize(displayWidth, displayHeight); nsIntSize frameSize(width, height); if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) { return NS_ERROR_FAILURE; } // Video track's frame sizes will not overflow. Activate the video track. mHasVideo = mInfo.mVideo.mHasVideo = true; mInfo.mVideo.mDisplay = displaySize; mPicture = pictureRect; mInitialFrame = frameSize; VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); if (container) { container->SetCurrentFrame(gfxIntSize(displaySize.width, displaySize.height), nullptr, mozilla::TimeStamp::Now()); } } if (mOmxDecoder->HasAudio()) { int32_t numChannels, sampleRate; mOmxDecoder->GetAudioParameters(&numChannels, &sampleRate); mHasAudio = mInfo.mAudio.mHasAudio = true; mInfo.mAudio.mChannels = numChannels; mInfo.mAudio.mRate = sampleRate; } *aInfo = mInfo; return NS_OK; }
void MediaEngineTabVideoSource::Draw() { if (!mWindow) { return; } if (mScrollWithPage || mViewportWidth == INT32_MAX) { mWindow->GetInnerWidth(&mViewportWidth); } if (mScrollWithPage || mViewportHeight == INT32_MAX) { mWindow->GetInnerHeight(&mViewportHeight); } if (!mViewportWidth || !mViewportHeight) { return; } IntSize size; { float pixelRatio; mWindow->GetDevicePixelRatio(&pixelRatio); const int32_t deviceWidth = (int32_t)(pixelRatio * mViewportWidth); const int32_t deviceHeight = (int32_t)(pixelRatio * mViewportHeight); if ((deviceWidth <= mBufWidthMax) && (deviceHeight <= mBufHeightMax)) { size = IntSize(deviceWidth, deviceHeight); } else { const float scaleWidth = (float)mBufWidthMax / (float)deviceWidth; const float scaleHeight = (float)mBufHeightMax / (float)deviceHeight; const float scale = scaleWidth < scaleHeight ? scaleWidth : scaleHeight; size = IntSize((int)(scale * deviceWidth), (int)(scale * deviceHeight)); } } gfxImageFormat format = SurfaceFormat::X8R8G8B8_UINT32; uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width); if (mDataSize < static_cast<size_t>(stride * size.height)) { mDataSize = stride * size.height; mData = static_cast<unsigned char*>(malloc(mDataSize)); } if (!mData) { return; } nsCOMPtr<nsIPresShell> presShell; { RefPtr<nsPresContext> presContext; nsIDocShell* docshell = mWindow->GetDocShell(); if (docshell) { docshell->GetPresContext(getter_AddRefs(presContext)); } if (!presContext) { return; } presShell = presContext->PresShell(); } nscolor bgColor = NS_RGB(255, 255, 255); uint32_t renderDocFlags = mScrollWithPage? 0 : (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | nsIPresShell::RENDER_DOCUMENT_RELATIVE); nsRect r(nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetX), nsPresContext::CSSPixelsToAppUnits((float)mViewportOffsetY), nsPresContext::CSSPixelsToAppUnits((float)mViewportWidth), nsPresContext::CSSPixelsToAppUnits((float)mViewportHeight)); RefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer(); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, mData.rwget(), size, stride, SurfaceFormat::B8G8R8X8); if (!dt) { return; } RefPtr<gfxContext> context = new gfxContext(dt); context->SetMatrix(context->CurrentMatrix().Scale((((float) size.width)/mViewportWidth), (((float) size.height)/mViewportHeight))); NS_ENSURE_SUCCESS_VOID(presShell->RenderDocument(r, renderDocFlags, bgColor, context)); RefPtr<SourceSurface> surface = dt->Snapshot(); if (!surface) { return; } RefPtr<layers::SourceSurfaceImage> image = new layers::SourceSurfaceImage(size, surface); MonitorAutoLock mon(mMonitor); mImage = image; }
void AllocPolicyImpl::Dealloc() { ReentrantMonitorAutoEnter mon(mMonitor); ++mDecoderLimit; ResolvePromise(mon); }
double MediaSourceDecoder::GetDuration() { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); return ExplicitDuration(); }
nsresult MediaTaskQueue::Runner::Run() { RefPtr<nsIRunnable> event; { MonitorAutoLock mon(mQueue->mQueueMonitor); MOZ_ASSERT(mQueue->mIsRunning); mQueue->mRunningThread = NS_GetCurrentThread(); if (mQueue->mTasks.size() == 0) { mQueue->mIsRunning = false; mon.NotifyAll(); return NS_OK; } event = mQueue->mTasks.front(); mQueue->mTasks.pop(); } MOZ_ASSERT(event); // Note that dropping the queue monitor before running the task, and // taking the monitor again after the task has run ensures we have memory // fences enforced. This means that if the object we're calling wasn't // designed to be threadsafe, it will be, provided we're only calling it // in this task queue. event->Run(); // Drop the reference to event. The event will hold a reference to the // object it's calling, and we don't want to keep it alive, it may be // making assumptions what holds references to it. This is especially // the case if the object is waiting for us to shutdown, so that it // can shutdown (like in the MediaDecoderStateMachine's SHUTDOWN case). event = nullptr; { MonitorAutoLock mon(mQueue->mQueueMonitor); if (mQueue->mTasks.size() == 0) { // No more events to run. Exit the task runner. mQueue->mIsRunning = false; mon.NotifyAll(); mQueue->mRunningThread = nullptr; return NS_OK; } } // There's at least one more event that we can run. Dispatch this Runner // to the thread pool again to ensure it runs again. Note that we don't just // run in a loop here so that we don't hog the thread pool. This means we may // run on another thread next time, but we rely on the memory fences from // mQueueMonitor for thread safety of non-threadsafe tasks. { MonitorAutoLock mon(mQueue->mQueueMonitor); // Note: Hold the monitor *before* we dispatch, in case we context switch // to another thread pool in the queue immediately and take the lock in the // other thread; mRunningThread could be set to the new thread's value and // then incorrectly anulled below in that case. nsresult rv = mQueue->mPool->Dispatch(this, NS_DISPATCH_NORMAL); if (NS_FAILED(rv)) { // Failed to dispatch, shutdown! mQueue->mIsRunning = false; mQueue->mIsShutdown = true; mon.NotifyAll(); } mQueue->mRunningThread = nullptr; } return NS_OK; }
nsresult MediaTaskQueue::Dispatch(TemporaryRef<nsIRunnable> aRunnable) { MonitorAutoLock mon(mQueueMonitor); return DispatchLocked(aRunnable, AbortIfFlushing); }
void ImageContainer::ClearCurrentImage() { ReentrantMonitorAutoEnter mon(mReentrantMonitor); SetCurrentImageInternal(nullptr); }
nsresult WMFReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); LOG("WMFReader::ReadMetadata()"); HRESULT hr; RefPtr<IMFAttributes> attr; hr = wmf::MFCreateAttributes(byRef(attr), 1); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = attr->SetUnknown(MF_SOURCE_READER_ASYNC_CALLBACK, mSourceReaderCallback); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); if (mUseHwAccel) { hr = attr->SetUnknown(MF_SOURCE_READER_D3D_MANAGER, mDXVA2Manager->GetDXVADeviceManager()); if (FAILED(hr)) { LOG("Failed to set DXVA2 D3D Device manager on source reader attributes"); mUseHwAccel = false; } } hr = wmf::MFCreateSourceReaderFromByteStream(mByteStream, attr, byRef(mSourceReader)); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConfigureVideoDecoder(); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConfigureAudioDecoder(); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); if (mUseHwAccel && mInfo.mVideo.mHasVideo) { RefPtr<IMFTransform> videoDecoder; hr = mSourceReader->GetServiceForStream(MF_SOURCE_READER_FIRST_VIDEO_STREAM, GUID_NULL, IID_IMFTransform, (void**)(IMFTransform**)(byRef(videoDecoder))); if (SUCCEEDED(hr)) { ULONG_PTR manager = ULONG_PTR(mDXVA2Manager->GetDXVADeviceManager()); hr = videoDecoder->ProcessMessage(MFT_MESSAGE_SET_D3D_MANAGER, manager); if (hr == MF_E_TRANSFORM_TYPE_NOT_SET) { // Ignore MF_E_TRANSFORM_TYPE_NOT_SET. Vista returns this here // on some, perhaps all, video cards. This may be because activating // DXVA changes the available output types. It seems to be safe to // ignore this error. hr = S_OK; } } if (FAILED(hr)) { LOG("Failed to set DXVA2 D3D Device manager on decoder hr=0x%x", hr); mUseHwAccel = false; // Re-run the configuration process, so that the output video format // is set correctly to reflect that hardware acceleration is disabled. // Without this, we'd be running with !mUseHwAccel and the output format // set to NV12, which is the format we expect when using hardware // acceleration. This would cause us to misinterpret the frame contents. hr = ConfigureVideoDecoder(); } } if (mInfo.HasVideo()) { LOG("Using DXVA: %s", (mUseHwAccel ? "Yes" : "No")); } // Abort if both video and audio failed to initialize. NS_ENSURE_TRUE(mInfo.HasValidMedia(), NS_ERROR_FAILURE); // Get the duration, and report it to the decoder if we have it. int64_t duration = 0; hr = GetSourceReaderDuration(mSourceReader, duration); if (SUCCEEDED(hr)) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } // We can seek if we get a duration *and* the reader reports that it's // seekable. bool canSeek = false; if (FAILED(hr) || FAILED(GetSourceReaderCanSeek(mSourceReader, canSeek)) || !canSeek) { mDecoder->SetMediaSeekable(false); } *aInfo = mInfo; *aTags = nullptr; // aTags can be retrieved using techniques like used here: // http://blogs.msdn.com/b/mf/archive/2010/01/12/mfmediapropdump.aspx return NS_OK; }
bool MediaSourceReader::IsEnded() { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); return mEnded; }
void dat(char c[20]) { int i, l = 0, k = 0, p = 0,t=0,xa=0; int s = 0; for (i = 0; c[i] != '\0'; i++) { if (c[i] == '-') { k = i; p = p + 1; } if (c[i + 1] == '\0') { k = i + 1; p = p + 1; } if (((k - l) == 2) && (p == 1)) { days(c, l, k); printf("-"); } if (((k - l) == 3) && (p == 2)) { if (c[l + 1] == '0') { s = (int)c[l + 2] - 49; mon(s); } else if (c[l + 1] == '1') { s = (int)c[l + 2] - 49 + 10; mon(s); } printf("-"); } else xa = 1; if (((k - l) == 5) && (p == 3)) { if (c[l + 1] != '0') { s = (int)c[l + 1] - 49; ones(s); printf("thousand "); } if (c[l + 2] != '0') { s = (int)c[l + 2] - 49; ones(s); printf(" hundered "); } if ((c[l + 3] == '0') && (c[l+4]=='0')) { } else { printf("and "); days(c, l + 3, k); } } if ((p > 2) && (k - l) != 5) printf("invalid year"); l = k; } if (p != 3)printf("invalid format"); }
/* static */ bool SharedThreadPool::IsEmpty() { ReentrantMonitorAutoEnter mon(*sMonitor); return !sPools->Count(); }
bool GStreamerReader::DecodeVideoFrame(bool &aKeyFrameSkip, int64_t aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); GstBuffer *buffer = nullptr; { ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); if (mReachedVideoEos && !mVideoSinkBufferCount) { return false; } /* Wait something to be decoded before return or continue */ if (!mVideoSinkBufferCount) { if (!mAudioSinkBufferCount) { /* We have nothing decoded so it makes no sense to return to the state machine * as it will call us back immediately, we'll return again and so on, wasting * CPU cycles for no job done. So, block here until there is either video or * audio data available */ mon.Wait(); if (!mVideoSinkBufferCount) { /* There is still no video data available, so either there is audio data or * something else has happened (Eos, etc...). Return to the state machine * to process it */ return true; } } else { return true; } } mDecoder->NotifyDecodedFrames(0, 1); #if GST_VERSION_MAJOR >= 1 GstSample *sample = gst_app_sink_pull_sample(mVideoAppSink); buffer = gst_buffer_ref(gst_sample_get_buffer(sample)); gst_sample_unref(sample); #else buffer = gst_app_sink_pull_buffer(mVideoAppSink); #endif mVideoSinkBufferCount--; } bool isKeyframe = !GST_BUFFER_FLAG_IS_SET(buffer, GST_BUFFER_FLAG_DELTA_UNIT); if ((aKeyFrameSkip && !isKeyframe)) { gst_buffer_unref(buffer); return true; } int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); { ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); timestamp = gst_segment_to_stream_time(&mVideoSegment, GST_FORMAT_TIME, timestamp); } NS_ASSERTION(GST_CLOCK_TIME_IS_VALID(timestamp), "frame has invalid timestamp"); timestamp = GST_TIME_AS_USECONDS(timestamp); int64_t duration = 0; if (GST_CLOCK_TIME_IS_VALID(GST_BUFFER_DURATION(buffer))) duration = GST_TIME_AS_USECONDS(GST_BUFFER_DURATION(buffer)); else if (fpsNum && fpsDen) /* add 1-frame duration */ duration = gst_util_uint64_scale(GST_USECOND, fpsDen, fpsNum); if (timestamp < aTimeThreshold) { LOG(PR_LOG_DEBUG, "skipping frame %" GST_TIME_FORMAT " threshold %" GST_TIME_FORMAT, GST_TIME_ARGS(timestamp * 1000), GST_TIME_ARGS(aTimeThreshold * 1000)); gst_buffer_unref(buffer); return true; } if (!buffer) /* no more frames */ return true; #if GST_VERSION_MAJOR >= 1 if (mConfigureAlignment && buffer->pool) { GstStructure *config = gst_buffer_pool_get_config(buffer->pool); GstVideoAlignment align; if (gst_buffer_pool_config_get_video_alignment(config, &align)) gst_video_info_align(&mVideoInfo, &align); gst_structure_free(config); mConfigureAlignment = false; } #endif nsRefPtr<PlanarYCbCrImage> image = GetImageFromBuffer(buffer); if (!image) { /* Ugh, upstream is not calling gst_pad_alloc_buffer(). Fallback to * allocating a PlanarYCbCrImage backed GstBuffer here and memcpy. */ GstBuffer* tmp = nullptr; CopyIntoImageBuffer(buffer, &tmp, image); gst_buffer_unref(buffer); buffer = tmp; } int64_t offset = mDecoder->GetResource()->Tell(); // Estimate location in media. VideoData* video = VideoData::CreateFromImage(mInfo.mVideo, mDecoder->GetImageContainer(), offset, timestamp, duration, static_cast<Image*>(image.get()), isKeyframe, -1, mPicture); mVideoQueue.Push(video); gst_buffer_unref(buffer); return true; }
nsresult GStreamerReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); nsresult ret = NS_OK; /* * Parse MP3 headers before we kick off the GStreamer pipeline otherwise there * might be concurrent stream operations happening on both decoding and gstreamer * threads which will screw the GStreamer state machine. */ bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3); if (isMP3) { ParseMP3Headers(); } /* We do 3 attempts here: decoding audio and video, decoding video only, * decoding audio only. This allows us to play streams that have one broken * stream but that are otherwise decodeable. */ guint flags[3] = {GST_PLAY_FLAG_VIDEO|GST_PLAY_FLAG_AUDIO, static_cast<guint>(~GST_PLAY_FLAG_AUDIO), static_cast<guint>(~GST_PLAY_FLAG_VIDEO)}; guint default_flags, current_flags; g_object_get(mPlayBin, "flags", &default_flags, nullptr); GstMessage* message = nullptr; for (unsigned int i = 0; i < G_N_ELEMENTS(flags); i++) { current_flags = default_flags & flags[i]; g_object_set(G_OBJECT(mPlayBin), "flags", current_flags, nullptr); /* reset filter caps to ANY */ GstCaps* caps = gst_caps_new_any(); GstElement* filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter"); g_object_set(filter, "caps", caps, nullptr); gst_object_unref(filter); filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter"); g_object_set(filter, "caps", caps, nullptr); gst_object_unref(filter); gst_caps_unref(caps); filter = nullptr; if (!(current_flags & GST_PLAY_FLAG_AUDIO)) filter = gst_bin_get_by_name(GST_BIN(mAudioSink), "filter"); else if (!(current_flags & GST_PLAY_FLAG_VIDEO)) filter = gst_bin_get_by_name(GST_BIN(mVideoSink), "filter"); if (filter) { /* Little trick: set the target caps to "skip" so that playbin2 fails to * find a decoder for the stream we want to skip. */ GstCaps* filterCaps = gst_caps_new_simple ("skip", nullptr, nullptr); g_object_set(filter, "caps", filterCaps, nullptr); gst_caps_unref(filterCaps); gst_object_unref(filter); } LOG(PR_LOG_DEBUG, "starting metadata pipeline"); if (gst_element_set_state(mPlayBin, GST_STATE_PAUSED) == GST_STATE_CHANGE_FAILURE) { LOG(PR_LOG_DEBUG, "metadata pipeline state change failed"); ret = NS_ERROR_FAILURE; continue; } /* Wait for ASYNC_DONE, which is emitted when the pipeline is built, * prerolled and ready to play. Also watch for errors. */ message = gst_bus_timed_pop_filtered(mBus, GST_CLOCK_TIME_NONE, (GstMessageType)(GST_MESSAGE_ASYNC_DONE | GST_MESSAGE_ERROR | GST_MESSAGE_EOS)); if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ASYNC_DONE) { LOG(PR_LOG_DEBUG, "read metadata pipeline prerolled"); gst_message_unref(message); ret = NS_OK; break; } else { LOG(PR_LOG_DEBUG, "read metadata pipeline failed to preroll: %s", gst_message_type_get_name (GST_MESSAGE_TYPE (message))); if (GST_MESSAGE_TYPE(message) == GST_MESSAGE_ERROR) { GError* error; gchar* debug; gst_message_parse_error(message, &error, &debug); LOG(PR_LOG_ERROR, "read metadata error: %s: %s", error->message, debug); g_error_free(error); g_free(debug); } /* Unexpected stream close/EOS or other error. We'll give up if all * streams are in error/eos. */ gst_element_set_state(mPlayBin, GST_STATE_NULL); gst_message_unref(message); ret = NS_ERROR_FAILURE; } } if (NS_SUCCEEDED(ret)) ret = CheckSupportedFormats(); if (NS_FAILED(ret)) /* we couldn't get this to play */ return ret; /* report the duration */ gint64 duration; if (isMP3 && mMP3FrameParser.IsMP3()) { // The MP3FrameParser has reported a duration; use that over the gstreamer // reported duration for inter-platform consistency. ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mUseParserDuration = true; mLastParserDuration = mMP3FrameParser.GetDuration(); mDecoder->SetMediaDuration(mLastParserDuration); } else { LOG(PR_LOG_DEBUG, "querying duration"); // Otherwise use the gstreamer duration. #if GST_VERSION_MAJOR >= 1 if (gst_element_query_duration(GST_ELEMENT(mPlayBin), GST_FORMAT_TIME, &duration)) { #else GstFormat format = GST_FORMAT_TIME; if (gst_element_query_duration(GST_ELEMENT(mPlayBin), &format, &duration) && format == GST_FORMAT_TIME) { #endif ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); LOG(PR_LOG_DEBUG, "have duration %" GST_TIME_FORMAT, GST_TIME_ARGS(duration)); duration = GST_TIME_AS_USECONDS (duration); mDecoder->SetMediaDuration(duration); } else { mDecoder->SetMediaSeekable(false); } } int n_video = 0, n_audio = 0; g_object_get(mPlayBin, "n-video", &n_video, "n-audio", &n_audio, nullptr); mInfo.mVideo.mHasVideo = n_video != 0; mInfo.mAudio.mHasAudio = n_audio != 0; *aInfo = mInfo; *aTags = nullptr; // Watch the pipeline for fatal errors #if GST_VERSION_MAJOR >= 1 gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this, nullptr); #else gst_bus_set_sync_handler(mBus, GStreamerReader::ErrorCb, this); #endif /* set the pipeline to PLAYING so that it starts decoding and queueing data in * the appsinks */ gst_element_set_state(mPlayBin, GST_STATE_PLAYING); return NS_OK; } nsresult GStreamerReader::CheckSupportedFormats() { bool done = false; bool unsupported = false; GstIterator* it = gst_bin_iterate_recurse(GST_BIN(mPlayBin)); while (!done) { GstIteratorResult res; GstElement* element; #if GST_VERSION_MAJOR >= 1 GValue value = {0,}; res = gst_iterator_next(it, &value); #else res = gst_iterator_next(it, (void **) &element); #endif switch(res) { case GST_ITERATOR_OK: { #if GST_VERSION_MAJOR >= 1 element = GST_ELEMENT (g_value_get_object (&value)); #endif GstElementFactory* factory = gst_element_get_factory(element); if (factory) { const char* klass = gst_element_factory_get_klass(factory); GstPad* pad = gst_element_get_static_pad(element, "sink"); if (pad) { GstCaps* caps; #if GST_VERSION_MAJOR >= 1 caps = gst_pad_get_current_caps(pad); #else caps = gst_pad_get_negotiated_caps(pad); #endif if (caps) { /* check for demuxers but ignore elements like id3demux */ if (strstr (klass, "Demuxer") && !strstr(klass, "Metadata")) unsupported = !GStreamerFormatHelper::Instance()->CanHandleContainerCaps(caps); else if (strstr (klass, "Decoder") && !strstr(klass, "Generic")) unsupported = !GStreamerFormatHelper::Instance()->CanHandleCodecCaps(caps); gst_caps_unref(caps); } gst_object_unref(pad); } } #if GST_VERSION_MAJOR >= 1 g_value_unset (&value); #else gst_object_unref(element); #endif done = unsupported; break; } case GST_ITERATOR_RESYNC: unsupported = false; done = false; break; case GST_ITERATOR_ERROR: done = true; break; case GST_ITERATOR_DONE: done = true; break; } } return unsupported ? NS_ERROR_FAILURE : NS_OK; } nsresult GStreamerReader::ResetDecode() { nsresult res = NS_OK; LOG(PR_LOG_DEBUG, "reset decode"); if (NS_FAILED(MediaDecoderReader::ResetDecode())) { res = NS_ERROR_FAILURE; } mVideoQueue.Reset(); mAudioQueue.Reset(); mVideoSinkBufferCount = 0; mAudioSinkBufferCount = 0; mReachedAudioEos = false; mReachedVideoEos = false; #if GST_VERSION_MAJOR >= 1 mConfigureAlignment = true; #endif LOG(PR_LOG_DEBUG, "reset decode done"); return res; } bool GStreamerReader::DecodeAudioData() { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); GstBuffer *buffer = nullptr; { ReentrantMonitorAutoEnter mon(mGstThreadsMonitor); if (mReachedAudioEos && !mAudioSinkBufferCount) { return false; } /* Wait something to be decoded before return or continue */ if (!mAudioSinkBufferCount) { if(!mVideoSinkBufferCount) { /* We have nothing decoded so it makes no sense to return to the state machine * as it will call us back immediately, we'll return again and so on, wasting * CPU cycles for no job done. So, block here until there is either video or * audio data available */ mon.Wait(); if (!mAudioSinkBufferCount) { /* There is still no audio data available, so either there is video data or * something else has happened (Eos, etc...). Return to the state machine * to process it. */ return true; } } else { return true; } } #if GST_VERSION_MAJOR >= 1 GstSample *sample = gst_app_sink_pull_sample(mAudioAppSink); buffer = gst_buffer_ref(gst_sample_get_buffer(sample)); gst_sample_unref(sample); #else buffer = gst_app_sink_pull_buffer(mAudioAppSink); #endif mAudioSinkBufferCount--; } int64_t timestamp = GST_BUFFER_TIMESTAMP(buffer); timestamp = gst_segment_to_stream_time(&mAudioSegment, GST_FORMAT_TIME, timestamp); timestamp = GST_TIME_AS_USECONDS(timestamp); int64_t offset = GST_BUFFER_OFFSET(buffer); guint8* data; #if GST_VERSION_MAJOR >= 1 GstMapInfo info; gst_buffer_map(buffer, &info, GST_MAP_READ); unsigned int size = info.size; data = info.data; #else unsigned int size = GST_BUFFER_SIZE(buffer); data = GST_BUFFER_DATA(buffer); #endif int32_t frames = (size / sizeof(AudioDataValue)) / mInfo.mAudio.mChannels; typedef AudioCompactor::NativeCopy GstCopy; mAudioCompactor.Push(offset, timestamp, mInfo.mAudio.mRate, frames, mInfo.mAudio.mChannels, GstCopy(data, size, mInfo.mAudio.mChannels)); #if GST_VERSION_MAJOR >= 1 gst_buffer_unmap(buffer, &info); #endif gst_buffer_unref(buffer); return true; }
void MediaTaskQueue::AwaitIdle() { MonitorAutoLock mon(mQueueMonitor); AwaitIdleLocked(); }
void MediaSourceDecoder::NotifyTimeRangesChanged() { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mon.NotifyAll(); }
bool MediaTaskQueue::IsEmpty() { MonitorAutoLock mon(mQueueMonitor); return mTasks.empty(); }
NS_IMETHOD Run() override { nsresult res; MOZ_ASSERT(!NS_IsMainThread()); { mozilla::MonitorAutoLock mon(mDict->mMonitorSave); nsCOMPtr<nsIOutputStream> outStream; NS_NewSafeLocalFileOutputStream(getter_AddRefs(outStream), mFile, PR_CREATE_FILE | PR_WRONLY | PR_TRUNCATE, 0664); // Get a buffered output stream 4096 bytes big, to optimize writes. nsCOMPtr<nsIOutputStream> bufferedOutputStream; res = NS_NewBufferedOutputStream(getter_AddRefs(bufferedOutputStream), outStream, 4096); if (NS_FAILED(res)) { return res; } uint32_t bytesWritten; nsAutoCString utf8Key; for (uint32_t i = 0; i < mDictWords.Length(); ++i) { CopyUTF16toUTF8(mDictWords[i], utf8Key); bufferedOutputStream->Write(utf8Key.get(), utf8Key.Length(), &bytesWritten); bufferedOutputStream->Write("\n", 1, &bytesWritten); } nsCOMPtr<nsISafeOutputStream> safeStream = do_QueryInterface(bufferedOutputStream); NS_ASSERTION(safeStream, "expected a safe output stream!"); if (safeStream) { res = safeStream->Finish(); if (NS_FAILED(res)) { NS_WARNING("failed to save personal dictionary file! possible data loss"); } } // Save is done, reset the state variable and notify those who are waiting. mDict->mSavePending = false; mon.Notify(); // Leaving the block where 'mon' was declared will call the destructor // and unlock. } // Release the dictionary on the main thread. mozPersonalDictionary *dict; mDict.forget(&dict); nsCOMPtr<nsIThread> mainThread = do_GetMainThread(); if (mainThread) { NS_ProxyRelease(mainThread, static_cast<mozIPersonalDictionary *>(dict)); } else { // It's better to leak the dictionary than to release it on a wrong thread. NS_WARNING("Cannot get main thread, leaking mozPersonalDictionary."); } return NS_OK; }
MediaTaskQueue::~MediaTaskQueue() { MonitorAutoLock mon(mQueueMonitor); MOZ_ASSERT(mIsShutdown); MOZ_COUNT_DTOR(MediaTaskQueue); }
void MediaEngineTabVideoSource::Draw() { IntSize size(mBufW, mBufH); nsresult rv; float scale = 1.0; nsCOMPtr<nsPIDOMWindow> win = do_QueryInterface(mWindow); if (!win) { return; } // take a screenshot, as wide as possible, proportional to the destination size nsCOMPtr<nsIDOMWindowUtils> utils = do_GetInterface(win); if (!utils) { return; } nsCOMPtr<nsIDOMClientRect> rect; rv = utils->GetRootBounds(getter_AddRefs(rect)); NS_ENSURE_SUCCESS_VOID(rv); if (!rect) { return; } float left, top, width, height; rect->GetLeft(&left); rect->GetTop(&top); rect->GetWidth(&width); rect->GetHeight(&height); if (width == 0 || height == 0) { return; } int32_t srcX = left; int32_t srcY = top; int32_t srcW; int32_t srcH; float aspectRatio = ((float) size.width) / size.height; if (width / aspectRatio < height) { srcW = width; srcH = width / aspectRatio; } else { srcW = height * aspectRatio; srcH = height; } nsRefPtr<nsPresContext> presContext; nsIDocShell* docshell = win->GetDocShell(); if (docshell) { docshell->GetPresContext(getter_AddRefs(presContext)); } if (!presContext) { return; } nscolor bgColor = NS_RGB(255, 255, 255); nsCOMPtr<nsIPresShell> presShell = presContext->PresShell(); uint32_t renderDocFlags = (nsIPresShell::RENDER_IGNORE_VIEWPORT_SCROLLING | nsIPresShell::RENDER_DOCUMENT_RELATIVE); nsRect r(nsPresContext::CSSPixelsToAppUnits(srcX / scale), nsPresContext::CSSPixelsToAppUnits(srcY / scale), nsPresContext::CSSPixelsToAppUnits(srcW / scale), nsPresContext::CSSPixelsToAppUnits(srcH / scale)); gfxImageFormat format = gfxImageFormat::RGB24; uint32_t stride = gfxASurface::FormatStrideForWidth(format, size.width); nsRefPtr<layers::ImageContainer> container = layers::LayerManager::CreateImageContainer(); RefPtr<DrawTarget> dt = Factory::CreateDrawTargetForData(BackendType::CAIRO, mData.rwget(), size, stride, SurfaceFormat::B8G8R8X8); if (!dt) { return; } nsRefPtr<gfxContext> context = new gfxContext(dt); gfxPoint pt(0, 0); context->Translate(pt); context->Scale(scale * size.width / srcW, scale * size.height / srcH); rv = presShell->RenderDocument(r, renderDocFlags, bgColor, context); NS_ENSURE_SUCCESS_VOID(rv); RefPtr<SourceSurface> surface = dt->Snapshot(); if (!surface) { return; } layers::CairoImage::Data cairoData; cairoData.mSize = size; cairoData.mSourceSurface = surface; nsRefPtr<layers::CairoImage> image = new layers::CairoImage(); image->SetData(cairoData); MonitorAutoLock mon(mMonitor); mImage = image; }
void MediaOmxDecoder::SetCanOffloadAudio(bool aCanOffloadAudio) { ReentrantMonitorAutoEnter mon(GetReentrantMonitor()); mCanOffloadAudio = aCanOffloadAudio; }
void WaitUntilDone() { MonitorAutoLock mon(mMonitor); while (!mDone) { mon.Wait(); } }
int AudioStream::InvokeCubeb(Function aFunction, Args&&... aArgs) { MonitorAutoUnlock mon(mMonitor); return aFunction(mCubebStream.get(), std::forward<Args>(aArgs)...); }
nsresult nsDASHReader::GetBuffered(nsTimeRanges* aBuffered, int64_t aStartTime) { NS_ENSURE_ARG(aBuffered); MediaResource* resource = nullptr; nsBuiltinDecoder* decoder = nullptr; // Need to find intersect of |nsTimeRanges| for audio and video. nsTimeRanges audioBuffered, videoBuffered; uint32_t audioRangeCount, videoRangeCount; nsresult rv = NS_OK; // First, get buffered ranges for sub-readers. ReentrantMonitorConditionallyEnter mon(!mDecoder->OnDecodeThread(), mDecoder->GetReentrantMonitor()); if (mAudioReader) { decoder = mAudioReader->GetDecoder(); NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER); resource = decoder->GetResource(); NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER); resource->Pin(); rv = mAudioReader->GetBuffered(&audioBuffered, aStartTime); NS_ENSURE_SUCCESS(rv, rv); resource->Unpin(); rv = audioBuffered.GetLength(&audioRangeCount); NS_ENSURE_SUCCESS(rv, rv); } if (mVideoReader) { decoder = mVideoReader->GetDecoder(); NS_ENSURE_TRUE(decoder, NS_ERROR_NULL_POINTER); resource = decoder->GetResource(); NS_ENSURE_TRUE(resource, NS_ERROR_NULL_POINTER); resource->Pin(); rv = mVideoReader->GetBuffered(&videoBuffered, aStartTime); NS_ENSURE_SUCCESS(rv, rv); resource->Unpin(); rv = videoBuffered.GetLength(&videoRangeCount); NS_ENSURE_SUCCESS(rv, rv); } // Now determine buffered data for available sub-readers. if (mAudioReader && mVideoReader) { // Calculate intersecting ranges. for (uint32_t i = 0; i < audioRangeCount; i++) { // |A|udio, |V|ideo, |I|ntersect. double startA, startV, startI; double endA, endV, endI; rv = audioBuffered.Start(i, &startA); NS_ENSURE_SUCCESS(rv, rv); rv = audioBuffered.End(i, &endA); NS_ENSURE_SUCCESS(rv, rv); for (uint32_t j = 0; j < videoRangeCount; j++) { rv = videoBuffered.Start(i, &startV); NS_ENSURE_SUCCESS(rv, rv); rv = videoBuffered.End(i, &endV); NS_ENSURE_SUCCESS(rv, rv); // If video block is before audio block, compare next video block. if (startA > endV) { continue; // If video block is after audio block, all of them are; compare next // audio block. } else if (endA < startV) { break; } // Calculate intersections of current audio and video blocks. startI = (startA > startV) ? startA : startV; endI = (endA > endV) ? endV : endA; aBuffered->Add(startI, endI); } } } else if (mAudioReader) { *aBuffered = audioBuffered; } else if (mVideoReader) { *aBuffered = videoBuffered; } else { return NS_ERROR_NOT_INITIALIZED; } return NS_OK; }
nsresult DirectShowReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { MOZ_ASSERT(OnTaskQueue()); HRESULT hr; nsresult rv; // Create the filter graph, reference it by the GraphBuilder interface, // to make graph building more convenient. hr = CoCreateInstance(CLSID_FilterGraph, nullptr, CLSCTX_INPROC_SERVER, IID_IGraphBuilder, reinterpret_cast<void**>(static_cast<IGraphBuilder**>(byRef(mGraph)))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mGraph, NS_ERROR_FAILURE); rv = ParseMP3Headers(&mMP3FrameParser, mDecoder->GetResource()); NS_ENSURE_SUCCESS(rv, rv); #ifdef DEBUG // Add the graph to the Running Object Table so that we can connect // to this graph with GraphEdit/GraphStudio. Note: on Vista and up you must // also regsvr32 proppage.dll from the Windows SDK. // See: http://msdn.microsoft.com/en-us/library/ms787252(VS.85).aspx hr = AddGraphToRunningObjectTable(mGraph, &mRotRegister); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); #endif // Extract the interface pointers we'll need from the filter graph. hr = mGraph->QueryInterface(static_cast<IMediaControl**>(byRef(mControl))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mControl, NS_ERROR_FAILURE); hr = mGraph->QueryInterface(static_cast<IMediaSeeking**>(byRef(mMediaSeeking))); NS_ENSURE_TRUE(SUCCEEDED(hr) && mMediaSeeking, NS_ERROR_FAILURE); // Build the graph. Create the filters we need, and connect them. We // build the entire graph ourselves to prevent other decoders installed // on the system being created and used. // Our source filters, wraps the MediaResource. mSourceFilter = new SourceFilter(MEDIATYPE_Stream, MEDIASUBTYPE_MPEG1Audio); NS_ENSURE_TRUE(mSourceFilter, NS_ERROR_FAILURE); rv = mSourceFilter->Init(mDecoder->GetResource(), mMP3FrameParser.GetMP3Offset()); NS_ENSURE_SUCCESS(rv, rv); hr = mGraph->AddFilter(mSourceFilter, L"MozillaDirectShowSource"); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // The MPEG demuxer. RefPtr<IBaseFilter> demuxer; hr = CreateAndAddFilter(mGraph, CLSID_MPEG1Splitter, L"MPEG1Splitter", byRef(demuxer)); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // Platform MP3 decoder. RefPtr<IBaseFilter> decoder; // Firstly try to create the MP3 decoder filter that ships with WinXP // directly. This filter doesn't normally exist on later versions of // Windows. hr = CreateAndAddFilter(mGraph, CLSID_MPEG_LAYER_3_DECODER_FILTER, L"MPEG Layer 3 Decoder", byRef(decoder)); if (FAILED(hr)) { // Failed to create MP3 decoder filter. Try to instantiate // the MP3 decoder DMO. hr = AddMP3DMOWrapperFilter(mGraph, byRef(decoder)); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); } // Sink, captures audio samples and inserts them into our pipeline. static const wchar_t* AudioSinkFilterName = L"MozAudioSinkFilter"; mAudioSinkFilter = new AudioSinkFilter(AudioSinkFilterName, &hr); NS_ENSURE_TRUE(mAudioSinkFilter && SUCCEEDED(hr), NS_ERROR_FAILURE); hr = mGraph->AddFilter(mAudioSinkFilter, AudioSinkFilterName); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); // Join the filters. hr = ConnectFilters(mGraph, mSourceFilter, demuxer); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConnectFilters(mGraph, demuxer, decoder); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); hr = ConnectFilters(mGraph, decoder, mAudioSinkFilter); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); WAVEFORMATEX format; mAudioSinkFilter->GetSampleSink()->GetAudioFormat(&format); NS_ENSURE_TRUE(format.wFormatTag == WAVE_FORMAT_PCM, NS_ERROR_FAILURE); mInfo.mAudio.mChannels = mNumChannels = format.nChannels; mInfo.mAudio.mRate = mAudioRate = format.nSamplesPerSec; mInfo.mAudio.mBitDepth = format.wBitsPerSample; mBytesPerSample = format.wBitsPerSample / 8; *aInfo = mInfo; // Note: The SourceFilter strips ID3v2 tags out of the stream. *aTags = nullptr; // Begin decoding! hr = mControl->Run(); NS_ENSURE_TRUE(SUCCEEDED(hr), NS_ERROR_FAILURE); DWORD seekCaps = 0; hr = mMediaSeeking->GetCapabilities(&seekCaps); int64_t duration = mMP3FrameParser.GetDuration(); if (SUCCEEDED(hr)) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(duration); } LOG("Successfully initialized DirectShow MP3 decoder."); LOG("Channels=%u Hz=%u duration=%lld bytesPerSample=%d", mInfo.mAudio.mChannels, mInfo.mAudio.mRate, RefTimeToUsecs(duration), mBytesPerSample); return NS_OK; }
bool GonkAudioDecoderManager::HasQueuedSample() { MonitorAutoLock mon(mMonitor); return mQueueSample.Length(); }
// Copy and return a decoded frame. nsresult AppleVDADecoder::OutputFrame(CVPixelBufferRef aImage, AppleVDADecoder::AppleFrameRef aFrameRef) { if (mIsShutDown || mIsFlushing) { // We are in the process of flushing or shutting down; ignore frame. return NS_OK; } LOG("mp4 output frame %lld dts %lld pts %lld duration %lld us%s", aFrameRef.byte_offset, aFrameRef.decode_timestamp.ToMicroseconds(), aFrameRef.composition_timestamp.ToMicroseconds(), aFrameRef.duration.ToMicroseconds(), aFrameRef.is_sync_point ? " keyframe" : "" ); if (mQueuedSamples > mMaxRefFrames) { // We had stopped requesting more input because we had received too much at // the time. We can ask for more once again. mCallback->InputExhausted(); } MOZ_ASSERT(mQueuedSamples); mQueuedSamples--; if (!aImage) { // Image was dropped by decoder. return NS_OK; } // Where our resulting image will end up. RefPtr<VideoData> data; // Bounds. VideoInfo info; info.mDisplay = nsIntSize(mDisplayWidth, mDisplayHeight); gfx::IntRect visible = gfx::IntRect(0, 0, mPictureWidth, mPictureHeight); if (mUseSoftwareImages) { size_t width = CVPixelBufferGetWidth(aImage); size_t height = CVPixelBufferGetHeight(aImage); DebugOnly<size_t> planes = CVPixelBufferGetPlaneCount(aImage); MOZ_ASSERT(planes == 2, "Likely not NV12 format and it must be."); VideoData::YCbCrBuffer buffer; // Lock the returned image data. CVReturn rv = CVPixelBufferLockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly); if (rv != kCVReturnSuccess) { NS_ERROR("error locking pixel data"); mCallback->Error(); return NS_ERROR_FAILURE; } // Y plane. buffer.mPlanes[0].mData = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(aImage, 0)); buffer.mPlanes[0].mStride = CVPixelBufferGetBytesPerRowOfPlane(aImage, 0); buffer.mPlanes[0].mWidth = width; buffer.mPlanes[0].mHeight = height; buffer.mPlanes[0].mOffset = 0; buffer.mPlanes[0].mSkip = 0; // Cb plane. buffer.mPlanes[1].mData = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(aImage, 1)); buffer.mPlanes[1].mStride = CVPixelBufferGetBytesPerRowOfPlane(aImage, 1); buffer.mPlanes[1].mWidth = (width+1) / 2; buffer.mPlanes[1].mHeight = (height+1) / 2; buffer.mPlanes[1].mOffset = 0; buffer.mPlanes[1].mSkip = 1; // Cr plane. buffer.mPlanes[2].mData = static_cast<uint8_t*>(CVPixelBufferGetBaseAddressOfPlane(aImage, 1)); buffer.mPlanes[2].mStride = CVPixelBufferGetBytesPerRowOfPlane(aImage, 1); buffer.mPlanes[2].mWidth = (width+1) / 2; buffer.mPlanes[2].mHeight = (height+1) / 2; buffer.mPlanes[2].mOffset = 1; buffer.mPlanes[2].mSkip = 1; // Copy the image data into our own format. data = VideoData::Create(info, mImageContainer, nullptr, aFrameRef.byte_offset, aFrameRef.composition_timestamp.ToMicroseconds(), aFrameRef.duration.ToMicroseconds(), buffer, aFrameRef.is_sync_point, aFrameRef.decode_timestamp.ToMicroseconds(), visible); // Unlock the returned image data. CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly); } else { #ifndef MOZ_WIDGET_UIKIT IOSurfacePtr surface = MacIOSurfaceLib::CVPixelBufferGetIOSurface(aImage); MOZ_ASSERT(surface, "Decoder didn't return an IOSurface backed buffer"); RefPtr<MacIOSurface> macSurface = new MacIOSurface(surface); RefPtr<layers::Image> image = mImageContainer->CreateImage(ImageFormat::MAC_IOSURFACE); layers::MacIOSurfaceImage* videoImage = static_cast<layers::MacIOSurfaceImage*>(image.get()); videoImage->SetSurface(macSurface); data = VideoData::CreateFromImage(info, mImageContainer, aFrameRef.byte_offset, aFrameRef.composition_timestamp.ToMicroseconds(), aFrameRef.duration.ToMicroseconds(), image.forget(), aFrameRef.is_sync_point, aFrameRef.decode_timestamp.ToMicroseconds(), visible); #else MOZ_ASSERT_UNREACHABLE("No MacIOSurface on iOS"); #endif } if (!data) { NS_ERROR("Couldn't create VideoData for frame"); mCallback->Error(); return NS_ERROR_FAILURE; } // Frames come out in DTS order but we need to output them // in composition order. MonitorAutoLock mon(mMonitor); mReorderQueue.Push(data); while (mReorderQueue.Length() > mMaxRefFrames) { mCallback->Output(mReorderQueue.Pop().get()); } LOG("%llu decoded frames queued", static_cast<unsigned long long>(mReorderQueue.Length())); return NS_OK; }
NS_IMETHODIMP nsInputStreamPump::AsyncRead(nsIStreamListener *listener, nsISupports *ctxt) { ReentrantMonitorAutoEnter mon(mMonitor); NS_ENSURE_TRUE(mState == STATE_IDLE, NS_ERROR_IN_PROGRESS); NS_ENSURE_ARG_POINTER(listener); MOZ_ASSERT(NS_IsMainThread(), "nsInputStreamPump should be read from the " "main thread only."); // // OK, we need to use the stream transport service if // // (1) the stream is blocking // (2) the stream does not support nsIAsyncInputStream // bool nonBlocking; nsresult rv = mStream->IsNonBlocking(&nonBlocking); if (NS_FAILED(rv)) return rv; if (nonBlocking) { mAsyncStream = do_QueryInterface(mStream); // // if the stream supports nsIAsyncInputStream, and if we need to seek // to a starting offset, then we must do so here. in the non-async // stream case, the stream transport service will take care of seeking // for us. // if (mAsyncStream && (mStreamOffset != UINT64_MAX)) { nsCOMPtr<nsISeekableStream> seekable = do_QueryInterface(mStream); if (seekable) seekable->Seek(nsISeekableStream::NS_SEEK_SET, mStreamOffset); } } if (!mAsyncStream) { // ok, let's use the stream transport service to read this stream. nsCOMPtr<nsIStreamTransportService> sts = do_GetService(kStreamTransportServiceCID, &rv); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsITransport> transport; rv = sts->CreateInputTransport(mStream, mStreamOffset, mStreamLength, mCloseWhenDone, getter_AddRefs(transport)); if (NS_FAILED(rv)) return rv; nsCOMPtr<nsIInputStream> wrapper; rv = transport->OpenInputStream(0, mSegSize, mSegCount, getter_AddRefs(wrapper)); if (NS_FAILED(rv)) return rv; mAsyncStream = do_QueryInterface(wrapper, &rv); if (NS_FAILED(rv)) return rv; } // release our reference to the original stream. from this point forward, // we only reference the "stream" via mAsyncStream. mStream = 0; // mStreamOffset now holds the number of bytes currently read. we use this // to enforce the mStreamLength restriction. mStreamOffset = 0; // grab event queue (we must do this here by contract, since all notifications // must go to the thread which called AsyncRead) mTargetThread = do_GetCurrentThread(); NS_ENSURE_STATE(mTargetThread); rv = EnsureWaiting(); if (NS_FAILED(rv)) return rv; if (mLoadGroup) mLoadGroup->AddRequest(this, nullptr); mState = STATE_START; mListener = listener; mListenerContext = ctxt; return NS_OK; }
void ClosingService::ThreadFunc() { PR_SetCurrentThreadName("Closing Service"); #ifdef MOZ_NUWA_PROCESS if (IsNuwaProcess()) { NuwaMarkCurrentThread(nullptr, nullptr); } #endif for (;;) { PRFileDesc *fd; { mozilla::MonitorAutoLock mon(mMonitor); while (!mShutdown && (mQueue.Length() == 0)) { mon.Wait(); } if (mShutdown) { // If we are in shutdown leak the rest of the sockets. for (uint32_t i = 0; i < mQueue.Length(); i++) { fd = mQueue[i]; // If the ClosingService layer is the first layer above // PR_NSPR_IO_LAYER we are not going to leak anything, but PR_Close // will not be called. PR_Free(fd); } mQueue.Clear(); return; } fd = mQueue[0]; mQueue.RemoveElementAt(0); } // Leave lock before closing socket. It can block for a long time and in // case we accidentally attach this layer twice this would cause deadlock. bool tcp = (PR_GetDescType(PR_GetIdentitiesLayer(fd, PR_NSPR_IO_LAYER)) == PR_DESC_SOCKET_TCP); PRIntervalTime closeStarted = PR_IntervalNow(); fd->methods->close(fd); // Post telemetry. if (tcp) { SendPRCloseTelemetry(closeStarted, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_NORMAL, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCLOSE_TCP_BLOCKING_TIME_OFFLINE); } else { SendPRCloseTelemetry(closeStarted, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_NORMAL, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_SHUTDOWN, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_CONNECTIVITY_CHANGE, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_LINK_CHANGE, Telemetry::PRCLOSE_UDP_BLOCKING_TIME_OFFLINE); } } }
nsresult MediaOmxReader::ReadMetadata(MediaInfo* aInfo, MetadataTags** aTags) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); *aTags = nullptr; // Initialize the internal OMX Decoder. nsresult rv = InitOmxDecoder(); if (NS_FAILED(rv)) { return rv; } bool isMP3 = mDecoder->GetResource()->GetContentType().EqualsASCII(AUDIO_MP3); if (isMP3) { // When read sdcard's file on b2g platform at constructor, // the mDecoder->GetResource()->GetLength() would return -1. // Delay set the total duration on this function. mMP3FrameParser.SetLength(mDecoder->GetResource()->GetLength()); ProcessCachedData(0, true); } if (!mOmxDecoder->AllocateMediaResources()) { return NS_ERROR_FAILURE; } // Bug 1050667, both MediaDecoderStateMachine and MediaOmxReader // relies on IsWaitingMediaResources() function. And the waiting state will be // changed by binder thread, so we store the waiting state in a cache value to // make them in consistent state. UpdateIsWaitingMediaResources(); if (IsWaitingMediaResources()) { return NS_OK; } // After resources are available, set the metadata. if (!mOmxDecoder->EnsureMetadata()) { return NS_ERROR_FAILURE; } if (isMP3 && mMP3FrameParser.IsMP3()) { int64_t duration = mMP3FrameParser.GetDuration(); // The MP3FrameParser may reported a duration; // return -1 if no frame has been parsed. if (duration >= 0) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mUseParserDuration = true; mLastParserDuration = duration; mDecoder->SetMediaDuration(mLastParserDuration); } } else { // Set the total duration (the max of the audio and video track). int64_t durationUs; mOmxDecoder->GetDuration(&durationUs); if (durationUs) { ReentrantMonitorAutoEnter mon(mDecoder->GetReentrantMonitor()); mDecoder->SetMediaDuration(durationUs); } } if (mOmxDecoder->HasVideo()) { int32_t displayWidth, displayHeight, width, height; mOmxDecoder->GetVideoParameters(&displayWidth, &displayHeight, &width, &height); nsIntRect pictureRect(0, 0, width, height); // Validate the container-reported frame and pictureRect sizes. This ensures // that our video frame creation code doesn't overflow. nsIntSize displaySize(displayWidth, displayHeight); nsIntSize frameSize(width, height); if (!IsValidVideoRegion(frameSize, pictureRect, displaySize)) { return NS_ERROR_FAILURE; } // Video track's frame sizes will not overflow. Activate the video track. mHasVideo = mInfo.mVideo.mHasVideo = true; mInfo.mVideo.mDisplay = displaySize; mPicture = pictureRect; mInitialFrame = frameSize; VideoFrameContainer* container = mDecoder->GetVideoFrameContainer(); if (container) { container->SetCurrentFrame(gfxIntSize(displaySize.width, displaySize.height), nullptr, mozilla::TimeStamp::Now()); } } if (mOmxDecoder->HasAudio()) { int32_t numChannels, sampleRate; mOmxDecoder->GetAudioParameters(&numChannels, &sampleRate); mHasAudio = mInfo.mAudio.mHasAudio = true; mInfo.mAudio.mChannels = numChannels; mInfo.mAudio.mRate = sampleRate; } *aInfo = mInfo; #ifdef MOZ_AUDIO_OFFLOAD CheckAudioOffload(); #endif return NS_OK; }