PRBool nsTheoraState::Init() { if (!mActive) return PR_FALSE; PRInt64 n = mInfo.fps_numerator; PRInt64 d = mInfo.fps_denominator; PRInt64 f; if (!MulOverflow(1000, d, f)) { return mActive = PR_FALSE; } f /= n; if (f > PR_UINT32_MAX) { return mActive = PR_FALSE; } mFrameDuration = static_cast<PRUint32>(f); n = mInfo.aspect_numerator; d = mInfo.aspect_denominator; mPixelAspectRatio = (n == 0 || d == 0) ? 1.0f : static_cast<float>(n) / static_cast<float>(d); // Ensure the frame region isn't larger than our prescribed maximum. PRUint32 pixels; if (!MulOverflow32(mInfo.frame_width, mInfo.frame_height, pixels) || pixels > MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT || pixels == 0) { return mActive = PR_FALSE; } // Ensure the picture region isn't larger than our prescribed maximum. if (!MulOverflow32(mInfo.pic_width, mInfo.pic_height, pixels) || pixels > MAX_VIDEO_WIDTH * MAX_VIDEO_HEIGHT || pixels == 0) { return mActive = PR_FALSE; } mCtx = th_decode_alloc(&mInfo, mSetup); if (mCtx == NULL) { return mActive = PR_FALSE; } return PR_TRUE; }
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; }
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; }