PRInt64 nsTheoraState::StartTime(PRInt64 granulepos) { if (granulepos < 0 || !mActive || mInfo.fps_numerator == 0) { return -1; } PRInt64 t = 0; PRInt64 frameno = th_granule_frame(mCtx, granulepos); if (!MulOverflow(frameno, 1000, t)) return -1; if (!MulOverflow(t, mInfo.fps_denominator, t)) return -1; return t / mInfo.fps_numerator; }
// Converts from microseconds to number of audio samples, given the specified // audio rate. PRBool UsecsToSamples(PRInt64 aUsecs, PRUint32 aRate, PRInt64& aOutSamples) { PRInt64 x; if (!MulOverflow(aUsecs, aRate, x)) return PR_FALSE; aOutSamples = x / USECS_PER_S; return PR_TRUE; }
// Converts from number of audio samples to microseconds, given the specified // audio rate. PRBool SamplesToUsecs(PRInt64 aSamples, PRUint32 aRate, PRInt64& aOutUsecs) { PRInt64 x; if (!MulOverflow(aSamples, USECS_PER_S, x)) return PR_FALSE; aOutUsecs = x / aRate; return PR_TRUE; }
PRInt64 nsVorbisState::Time(vorbis_info* aInfo, PRInt64 aGranulepos) { if (aGranulepos == -1 || aInfo->rate == 0) { return -1; } PRInt64 t = 0; MulOverflow(1000, aGranulepos, t); return t / aInfo->rate; }
PRInt64 nsVorbisState::Time(PRInt64 granulepos) { if (granulepos == -1 || !mActive || mDsp.vi->rate == 0) { return -1; } PRInt64 t = 0; MulOverflow(1000, granulepos, t); return t / mDsp.vi->rate; }
PRInt64 nsTheoraState::Time(th_info* aInfo, PRInt64 aGranulepos) { if (aGranulepos < 0 || aInfo->fps_numerator == 0) { return -1; } PRInt64 t = 0; // Implementation of th_granule_frame inlined here to operate // on the th_info structure instead of the theora_state. int shift = aInfo->keyframe_granule_shift; ogg_int64_t iframe = aGranulepos >> shift; ogg_int64_t pframe = aGranulepos - (iframe << shift); PRInt64 frameno = iframe + pframe - TH_VERSION_CHECK(aInfo, 3, 2, 1); if (!AddOverflow(frameno, 1, t)) return -1; if (!MulOverflow(t, 1000, t)) return -1; if (!MulOverflow(t, aInfo->fps_denominator, t)) return -1; return t / aInfo->fps_numerator; }
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; }
PRInt64 nsTheoraState::MaxKeyframeOffset() { // Determine the maximum time in microseconds by which a key frame could // offset for the theora bitstream. Theora granulepos encode time as: // ((key_frame_number << granule_shift) + frame_offset). // Therefore the maximum possible time by which any frame could be offset // from a keyframe is the duration of (1 << granule_shift) - 1) frames. PRInt64 frameDuration; // Max number of frames keyframe could possibly be offset. PRInt64 keyframeDiff = (1 << mInfo.keyframe_granule_shift) - 1; // Length of frame in usecs. PRInt64 d = 0; // d will be 0 if multiplication overflows. MulOverflow(USECS_PER_S, mInfo.fps_denominator, d); frameDuration = d / mInfo.fps_numerator; // Total time in usecs keyframe can be offset from any given frame. return frameDuration * keyframeDiff; }
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 and picture regions aren't larger than our prescribed // maximum, or zero sized. nsIntSize frame(mInfo.frame_width, mInfo.frame_height); nsIntRect picture(mInfo.pic_x, mInfo.pic_y, mInfo.pic_width, mInfo.pic_height); if (!nsVideoInfo::ValidateVideoRegion(frame, picture, frame)) { return mActive = PR_FALSE; } mCtx = th_decode_alloc(&mInfo, mSetup); if (mCtx == NULL) { return mActive = PR_FALSE; } return PR_TRUE; }
PRBool nsSkeletonState::DecodeIndex(ogg_packet* aPacket) { NS_ASSERTION(aPacket->bytes >= SKELETON_4_0_MIN_INDEX_LEN, "Index must be at least minimum size"); if (!mActive) { return PR_FALSE; } PRUint32 serialno = LEUint32(aPacket->packet + INDEX_SERIALNO_OFFSET); PRInt64 numKeyPoints = LEInt64(aPacket->packet + INDEX_NUM_KEYPOINTS_OFFSET); PRInt64 n = 0; PRInt64 endTime = 0, startTime = 0; const unsigned char* p = aPacket->packet; PRInt64 timeDenom = LEInt64(aPacket->packet + INDEX_TIME_DENOM_OFFSET); if (timeDenom == 0) { LOG(PR_LOG_DEBUG, ("Ogg Skeleton Index packet for stream %u has 0 " "timestamp denominator.", serialno)); return (mActive = PR_FALSE); } // Extract the start time. n = LEInt64(p + INDEX_FIRST_NUMER_OFFSET); PRInt64 t; if (!MulOverflow(n, 1000, t)) { return (mActive = PR_FALSE); } else { startTime = t / timeDenom; } // Extract the end time. n = LEInt64(p + INDEX_LAST_NUMER_OFFSET); if (!MulOverflow(n, 1000, t)) { return (mActive = PR_FALSE); } else { endTime = t / timeDenom; } // Check the numKeyPoints value read, ensure we're not going to run out of // memory while trying to decode the index packet. PRInt64 minPacketSize; if (!MulOverflow(numKeyPoints, MIN_KEY_POINT_SIZE, minPacketSize) || !AddOverflow(INDEX_KEYPOINT_OFFSET, minPacketSize, minPacketSize)) { return (mActive = PR_FALSE); } PRInt64 sizeofIndex = aPacket->bytes - INDEX_KEYPOINT_OFFSET; PRInt64 maxNumKeyPoints = sizeofIndex / MIN_KEY_POINT_SIZE; if (aPacket->bytes < minPacketSize || numKeyPoints > maxNumKeyPoints || numKeyPoints < 0) { // Packet size is less than the theoretical minimum size, or the packet is // claiming to store more keypoints than it's capable of storing. This means // that the numKeyPoints field is too large or small for the packet to // possibly contain as many packets as it claims to, so the numKeyPoints // field is possibly malicious. Don't try decoding this index, we may run // out of memory. LOG(PR_LOG_DEBUG, ("Possibly malicious number of key points reported " "(%lld) in index packet for stream %u.", numKeyPoints, serialno)); return (mActive = PR_FALSE); } nsAutoPtr<nsKeyFrameIndex> keyPoints(new nsKeyFrameIndex(startTime, endTime)); p = aPacket->packet + INDEX_KEYPOINT_OFFSET; const unsigned char* limit = aPacket->packet + aPacket->bytes; PRInt64 numKeyPointsRead = 0; PRInt64 offset = 0; PRInt64 time = 0; while (p < limit && numKeyPointsRead < numKeyPoints) { PRInt64 delta = 0; p = ReadVariableLengthInt(p, limit, delta); if (p == limit || !AddOverflow(offset, delta, offset) || offset > mLength || offset < 0) { return (mActive = PR_FALSE); } p = ReadVariableLengthInt(p, limit, delta); if (!AddOverflow(time, delta, time) || time > endTime || time < startTime) { return (mActive = PR_FALSE); } PRInt64 timeMs = 0; if (!MulOverflow(time, 1000, timeMs)) return mActive = PR_FALSE; timeMs /= timeDenom; keyPoints->Add(offset, timeMs); numKeyPointsRead++; } PRInt32 keyPointsRead = keyPoints->Length(); if (keyPointsRead > 0) { mIndex.Put(serialno, keyPoints.forget()); } LOG(PR_LOG_DEBUG, ("Loaded %d keypoints for Skeleton on stream %u", keyPointsRead, serialno)); return PR_TRUE; }