Loading drm/libmediadrm/DrmHal.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -68,10 +68,12 @@ constexpr char kEqualsSign[] = "="; template<typename T> std::string toBase64StringNoPad(const T* data, size_t size) { if (size == 0) { // Note that the base 64 conversion only works with arrays of single-byte // values. If the source is empty or is not an array of single-byte values, // return empty string. if (size == 0 || sizeof(data[0]) != 1) { return ""; } CHECK(sizeof(data[0] == 1)); android::AString outputString; encodeBase64(data, size, &outputString); Loading include/private/media/VideoFrame.h +4 −0 Original line number Diff line number Diff line Loading @@ -37,9 +37,11 @@ public: // will calculate frame buffer size if |hasData| is set to true. VideoFrame(uint32_t width, uint32_t height, uint32_t displayWidth, uint32_t displayHeight, uint32_t tileWidth, uint32_t tileHeight, uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize): mWidth(width), mHeight(height), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight), mTileWidth(tileWidth), mTileHeight(tileHeight), mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width), mSize(hasData ? (bpp * width * height) : 0), mIccSize(iccSize), mReserved(0) { Loading Loading @@ -74,6 +76,8 @@ public: uint32_t mHeight; // Decoded image height before rotation uint32_t mDisplayWidth; // Display width before rotation uint32_t mDisplayHeight; // Display height before rotation uint32_t mTileWidth; // Tile width (0 if image doesn't have grid) uint32_t mTileHeight; // Tile height (0 if image doesn't have grid) int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90 uint32_t mBytesPerPixel; // Number of bytes per pixel uint32_t mRowBytes; // Number of bytes per row before rotation Loading media/libaudioclient/IAudioPolicyService.cpp +1 −14 Original line number Diff line number Diff line Loading @@ -895,20 +895,7 @@ status_t BnAudioPolicyService::onTransact( break; } // FIXME: extend timeout for SET_DEVICE_CONNECTION_STATE and HANDLE_DEVICE_CONFIG_CHANGE // while we investigate why BT A2DP device connection/disconnection can sometimes // take more than 5 seconds uint32_t timeoutMs = TimeCheck::kDefaultTimeOutMs; switch (code) { case SET_DEVICE_CONNECTION_STATE: case HANDLE_DEVICE_CONFIG_CHANGE: timeoutMs *= 2; break; default: break; } TimeCheck check("IAudioPolicyService", timeoutMs); TimeCheck check("IAudioPolicyService"); switch (code) { case SET_DEVICE_CONNECTION_STATE: { Loading media/libaudioprocessing/AudioMixer.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -204,15 +204,14 @@ bool AudioMixer::setChannelMasks(int name, // channel masks have changed, does this track need a downmixer? // update to try using our desired format (if we aren't already using it) const audio_format_t prevDownmixerFormat = track->mDownmixRequiresFormat; const status_t status = track->prepareForDownmix(); ALOGE_IF(status != OK, "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x", status, track->channelMask, track->mMixerChannelMask); if (prevDownmixerFormat != track->mDownmixRequiresFormat) { track->prepareForReformat(); // because of downmixer, track format may change! } // always do reformat since channel mask changed, // do it after downmix since track format may change! track->prepareForReformat(); if (track->mResampler.get() != nullptr && mixerChannelCountChanged) { // resampler channels may have changed. Loading media/libheif/HeifDecoderImpl.cpp +134 −19 Original line number Diff line number Diff line Loading @@ -271,17 +271,43 @@ status_t HeifDataSource::getSize(off64_t* size) { ///////////////////////////////////////////////////////////////////////// struct HeifDecoderImpl::DecodeThread : public Thread { explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {} private: HeifDecoderImpl* mDecoder; bool threadLoop(); DISALLOW_EVIL_CONSTRUCTORS(DecodeThread); }; bool HeifDecoderImpl::DecodeThread::threadLoop() { return mDecoder->decodeAsync(); } ///////////////////////////////////////////////////////////////////////// HeifDecoderImpl::HeifDecoderImpl() : // output color format should always be set via setOutputColor(), in case // it's not, default to HAL_PIXEL_FORMAT_RGB_565. mOutputColor(HAL_PIXEL_FORMAT_RGB_565), mCurScanline(0), mWidth(0), mHeight(0), mFrameDecoded(false), mHasImage(false), mHasVideo(false) { mHasVideo(false), mAvailableLines(0), mNumSlices(1), mSliceHeight(0), mAsyncDecodeDone(false) { } HeifDecoderImpl::~HeifDecoderImpl() { if (mThread != nullptr) { mThread->join(); } } bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { Loading Loading @@ -310,22 +336,23 @@ bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { mHasImage = hasImage && !strcasecmp(hasImage, "yes"); mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes"); sp<IMemory> sharedMem; if (mHasImage) { // image index < 0 to retrieve primary image mFrameMemory = mRetriever->getImageAtIndex( sharedMem = mRetriever->getImageAtIndex( -1, mOutputColor, true /*metaOnly*/); } else if (mHasVideo) { mFrameMemory = mRetriever->getFrameAtTime(0, sharedMem = mRetriever->getFrameAtTime(0, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor, true /*metaOnly*/); } if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { if (sharedMem == nullptr || sharedMem->pointer() == nullptr) { ALOGE("getFrameAtTime: videoFrame is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer()); ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d", videoFrame->mWidth, Loading @@ -344,6 +371,14 @@ bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { videoFrame->mIccSize, videoFrame->getFlattenedIccData()); } mWidth = videoFrame->mWidth; mHeight = videoFrame->mHeight; if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) { // Try decoding in slices only if the image has tiles and is big enough. mSliceHeight = videoFrame->mTileHeight; mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight; ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices); } return true; } Loading Loading @@ -376,6 +411,36 @@ bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) { return false; } bool HeifDecoderImpl::decodeAsync() { for (size_t i = 1; i < mNumSlices; i++) { ALOGV("decodeAsync(): decoding slice %zu", i); size_t top = i * mSliceHeight; size_t bottom = (i + 1) * mSliceHeight; if (bottom > mHeight) { bottom = mHeight; } sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex( -1, mOutputColor, 0, top, mWidth, bottom); { Mutex::Autolock autolock(mLock); if (frameMemory == nullptr || frameMemory->pointer() == nullptr) { mAsyncDecodeDone = true; mScanlineReady.signal(); break; } mFrameMemory = frameMemory; mAvailableLines = bottom; ALOGV("decodeAsync(): available lines %zu", mAvailableLines); mScanlineReady.signal(); } } // Aggressive clear to avoid holding on to resources mRetriever.clear(); mDataSource.clear(); return false; } bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { // reset scanline pointer mCurScanline = 0; Loading @@ -384,6 +449,47 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { return true; } // See if we want to decode in slices to allow client to start // scanline processing in parallel with decode. If this fails // we fallback to decoding the full frame. if (mHasImage && mNumSlices > 1) { // get first slice and metadata sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex( -1, mOutputColor, 0, 0, mWidth, mSliceHeight); if (frameMemory == nullptr || frameMemory->pointer() == nullptr) { ALOGE("decode: metadata is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer()); if (frameInfo != nullptr) { frameInfo->set( videoFrame->mWidth, videoFrame->mHeight, videoFrame->mRotationAngle, videoFrame->mBytesPerPixel, videoFrame->mIccSize, videoFrame->getFlattenedIccData()); } mFrameMemory = frameMemory; mAvailableLines = mSliceHeight; mThread = new DecodeThread(this); if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) { mFrameDecoded = true; return true; } // Fallback to decode without slicing mThread.clear(); mNumSlices = 1; mSliceHeight = 0; mAvailableLines = 0; mFrameMemory.clear(); } if (mHasImage) { // image index < 0 to retrieve primary image mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor); Loading @@ -393,14 +499,14 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { } if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { ALOGE("getFrameAtTime: videoFrame is a nullptr"); ALOGE("decode: videoFrame is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); if (videoFrame->mSize == 0 || mFrameMemory->size() < videoFrame->getFlattenedSize()) { ALOGE("getFrameAtTime: videoFrame size is invalid"); ALOGE("decode: videoFrame size is invalid"); return false; } Loading @@ -424,36 +530,45 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { } mFrameDecoded = true; // Aggressive clear to avoid holding on to resources // Aggressively clear to avoid holding on to resources mRetriever.clear(); mDataSource.clear(); return true; } bool HeifDecoderImpl::getScanline(uint8_t* dst) { bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) { if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); if (mCurScanline >= videoFrame->mHeight) { ALOGE("no more scanline available"); return false; } uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++; memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth); return true; } size_t HeifDecoderImpl::skipScanlines(size_t count) { if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { return 0; bool HeifDecoderImpl::getScanline(uint8_t* dst) { if (mCurScanline >= mHeight) { ALOGE("no more scanline available"); return false; } if (mNumSlices > 1) { Mutex::Autolock autolock(mLock); while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) { mScanlineReady.wait(mLock); } return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false; } return getScanlineInner(dst); } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); size_t HeifDecoderImpl::skipScanlines(size_t count) { uint32_t oldScanline = mCurScanline; mCurScanline += count; if (mCurScanline > videoFrame->mHeight) { mCurScanline = videoFrame->mHeight; if (mCurScanline > mHeight) { mCurScanline = mHeight; } return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0; } Loading Loading
drm/libmediadrm/DrmHal.cpp +4 −2 Original line number Diff line number Diff line Loading @@ -68,10 +68,12 @@ constexpr char kEqualsSign[] = "="; template<typename T> std::string toBase64StringNoPad(const T* data, size_t size) { if (size == 0) { // Note that the base 64 conversion only works with arrays of single-byte // values. If the source is empty or is not an array of single-byte values, // return empty string. if (size == 0 || sizeof(data[0]) != 1) { return ""; } CHECK(sizeof(data[0] == 1)); android::AString outputString; encodeBase64(data, size, &outputString); Loading
include/private/media/VideoFrame.h +4 −0 Original line number Diff line number Diff line Loading @@ -37,9 +37,11 @@ public: // will calculate frame buffer size if |hasData| is set to true. VideoFrame(uint32_t width, uint32_t height, uint32_t displayWidth, uint32_t displayHeight, uint32_t tileWidth, uint32_t tileHeight, uint32_t angle, uint32_t bpp, bool hasData, size_t iccSize): mWidth(width), mHeight(height), mDisplayWidth(displayWidth), mDisplayHeight(displayHeight), mTileWidth(tileWidth), mTileHeight(tileHeight), mRotationAngle(angle), mBytesPerPixel(bpp), mRowBytes(bpp * width), mSize(hasData ? (bpp * width * height) : 0), mIccSize(iccSize), mReserved(0) { Loading Loading @@ -74,6 +76,8 @@ public: uint32_t mHeight; // Decoded image height before rotation uint32_t mDisplayWidth; // Display width before rotation uint32_t mDisplayHeight; // Display height before rotation uint32_t mTileWidth; // Tile width (0 if image doesn't have grid) uint32_t mTileHeight; // Tile height (0 if image doesn't have grid) int32_t mRotationAngle; // Rotation angle, clockwise, should be multiple of 90 uint32_t mBytesPerPixel; // Number of bytes per pixel uint32_t mRowBytes; // Number of bytes per row before rotation Loading
media/libaudioclient/IAudioPolicyService.cpp +1 −14 Original line number Diff line number Diff line Loading @@ -895,20 +895,7 @@ status_t BnAudioPolicyService::onTransact( break; } // FIXME: extend timeout for SET_DEVICE_CONNECTION_STATE and HANDLE_DEVICE_CONFIG_CHANGE // while we investigate why BT A2DP device connection/disconnection can sometimes // take more than 5 seconds uint32_t timeoutMs = TimeCheck::kDefaultTimeOutMs; switch (code) { case SET_DEVICE_CONNECTION_STATE: case HANDLE_DEVICE_CONFIG_CHANGE: timeoutMs *= 2; break; default: break; } TimeCheck check("IAudioPolicyService", timeoutMs); TimeCheck check("IAudioPolicyService"); switch (code) { case SET_DEVICE_CONNECTION_STATE: { Loading
media/libaudioprocessing/AudioMixer.cpp +3 −4 Original line number Diff line number Diff line Loading @@ -204,15 +204,14 @@ bool AudioMixer::setChannelMasks(int name, // channel masks have changed, does this track need a downmixer? // update to try using our desired format (if we aren't already using it) const audio_format_t prevDownmixerFormat = track->mDownmixRequiresFormat; const status_t status = track->prepareForDownmix(); ALOGE_IF(status != OK, "prepareForDownmix error %d, track channel mask %#x, mixer channel mask %#x", status, track->channelMask, track->mMixerChannelMask); if (prevDownmixerFormat != track->mDownmixRequiresFormat) { track->prepareForReformat(); // because of downmixer, track format may change! } // always do reformat since channel mask changed, // do it after downmix since track format may change! track->prepareForReformat(); if (track->mResampler.get() != nullptr && mixerChannelCountChanged) { // resampler channels may have changed. Loading
media/libheif/HeifDecoderImpl.cpp +134 −19 Original line number Diff line number Diff line Loading @@ -271,17 +271,43 @@ status_t HeifDataSource::getSize(off64_t* size) { ///////////////////////////////////////////////////////////////////////// struct HeifDecoderImpl::DecodeThread : public Thread { explicit DecodeThread(HeifDecoderImpl *decoder) : mDecoder(decoder) {} private: HeifDecoderImpl* mDecoder; bool threadLoop(); DISALLOW_EVIL_CONSTRUCTORS(DecodeThread); }; bool HeifDecoderImpl::DecodeThread::threadLoop() { return mDecoder->decodeAsync(); } ///////////////////////////////////////////////////////////////////////// HeifDecoderImpl::HeifDecoderImpl() : // output color format should always be set via setOutputColor(), in case // it's not, default to HAL_PIXEL_FORMAT_RGB_565. mOutputColor(HAL_PIXEL_FORMAT_RGB_565), mCurScanline(0), mWidth(0), mHeight(0), mFrameDecoded(false), mHasImage(false), mHasVideo(false) { mHasVideo(false), mAvailableLines(0), mNumSlices(1), mSliceHeight(0), mAsyncDecodeDone(false) { } HeifDecoderImpl::~HeifDecoderImpl() { if (mThread != nullptr) { mThread->join(); } } bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { Loading Loading @@ -310,22 +336,23 @@ bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { mHasImage = hasImage && !strcasecmp(hasImage, "yes"); mHasVideo = hasVideo && !strcasecmp(hasVideo, "yes"); sp<IMemory> sharedMem; if (mHasImage) { // image index < 0 to retrieve primary image mFrameMemory = mRetriever->getImageAtIndex( sharedMem = mRetriever->getImageAtIndex( -1, mOutputColor, true /*metaOnly*/); } else if (mHasVideo) { mFrameMemory = mRetriever->getFrameAtTime(0, sharedMem = mRetriever->getFrameAtTime(0, MediaSource::ReadOptions::SEEK_PREVIOUS_SYNC, mOutputColor, true /*metaOnly*/); } if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { if (sharedMem == nullptr || sharedMem->pointer() == nullptr) { ALOGE("getFrameAtTime: videoFrame is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); VideoFrame* videoFrame = static_cast<VideoFrame*>(sharedMem->pointer()); ALOGV("Meta dimension %dx%d, display %dx%d, angle %d, iccSize %d", videoFrame->mWidth, Loading @@ -344,6 +371,14 @@ bool HeifDecoderImpl::init(HeifStream* stream, HeifFrameInfo* frameInfo) { videoFrame->mIccSize, videoFrame->getFlattenedIccData()); } mWidth = videoFrame->mWidth; mHeight = videoFrame->mHeight; if (mHasImage && videoFrame->mTileHeight >= 512 && mWidth >= 3000 && mHeight >= 2000 ) { // Try decoding in slices only if the image has tiles and is big enough. mSliceHeight = videoFrame->mTileHeight; mNumSlices = (videoFrame->mHeight + mSliceHeight - 1) / mSliceHeight; ALOGV("mSliceHeight %u, mNumSlices %zu", mSliceHeight, mNumSlices); } return true; } Loading Loading @@ -376,6 +411,36 @@ bool HeifDecoderImpl::setOutputColor(HeifColorFormat heifColor) { return false; } bool HeifDecoderImpl::decodeAsync() { for (size_t i = 1; i < mNumSlices; i++) { ALOGV("decodeAsync(): decoding slice %zu", i); size_t top = i * mSliceHeight; size_t bottom = (i + 1) * mSliceHeight; if (bottom > mHeight) { bottom = mHeight; } sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex( -1, mOutputColor, 0, top, mWidth, bottom); { Mutex::Autolock autolock(mLock); if (frameMemory == nullptr || frameMemory->pointer() == nullptr) { mAsyncDecodeDone = true; mScanlineReady.signal(); break; } mFrameMemory = frameMemory; mAvailableLines = bottom; ALOGV("decodeAsync(): available lines %zu", mAvailableLines); mScanlineReady.signal(); } } // Aggressive clear to avoid holding on to resources mRetriever.clear(); mDataSource.clear(); return false; } bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { // reset scanline pointer mCurScanline = 0; Loading @@ -384,6 +449,47 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { return true; } // See if we want to decode in slices to allow client to start // scanline processing in parallel with decode. If this fails // we fallback to decoding the full frame. if (mHasImage && mNumSlices > 1) { // get first slice and metadata sp<IMemory> frameMemory = mRetriever->getImageRectAtIndex( -1, mOutputColor, 0, 0, mWidth, mSliceHeight); if (frameMemory == nullptr || frameMemory->pointer() == nullptr) { ALOGE("decode: metadata is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(frameMemory->pointer()); if (frameInfo != nullptr) { frameInfo->set( videoFrame->mWidth, videoFrame->mHeight, videoFrame->mRotationAngle, videoFrame->mBytesPerPixel, videoFrame->mIccSize, videoFrame->getFlattenedIccData()); } mFrameMemory = frameMemory; mAvailableLines = mSliceHeight; mThread = new DecodeThread(this); if (mThread->run("HeifDecode", ANDROID_PRIORITY_FOREGROUND) == OK) { mFrameDecoded = true; return true; } // Fallback to decode without slicing mThread.clear(); mNumSlices = 1; mSliceHeight = 0; mAvailableLines = 0; mFrameMemory.clear(); } if (mHasImage) { // image index < 0 to retrieve primary image mFrameMemory = mRetriever->getImageAtIndex(-1, mOutputColor); Loading @@ -393,14 +499,14 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { } if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { ALOGE("getFrameAtTime: videoFrame is a nullptr"); ALOGE("decode: videoFrame is a nullptr"); return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); if (videoFrame->mSize == 0 || mFrameMemory->size() < videoFrame->getFlattenedSize()) { ALOGE("getFrameAtTime: videoFrame size is invalid"); ALOGE("decode: videoFrame size is invalid"); return false; } Loading @@ -424,36 +530,45 @@ bool HeifDecoderImpl::decode(HeifFrameInfo* frameInfo) { } mFrameDecoded = true; // Aggressive clear to avoid holding on to resources // Aggressively clear to avoid holding on to resources mRetriever.clear(); mDataSource.clear(); return true; } bool HeifDecoderImpl::getScanline(uint8_t* dst) { bool HeifDecoderImpl::getScanlineInner(uint8_t* dst) { if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { return false; } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); if (mCurScanline >= videoFrame->mHeight) { ALOGE("no more scanline available"); return false; } uint8_t* src = videoFrame->getFlattenedData() + videoFrame->mRowBytes * mCurScanline++; memcpy(dst, src, videoFrame->mBytesPerPixel * videoFrame->mWidth); return true; } size_t HeifDecoderImpl::skipScanlines(size_t count) { if (mFrameMemory == nullptr || mFrameMemory->pointer() == nullptr) { return 0; bool HeifDecoderImpl::getScanline(uint8_t* dst) { if (mCurScanline >= mHeight) { ALOGE("no more scanline available"); return false; } if (mNumSlices > 1) { Mutex::Autolock autolock(mLock); while (!mAsyncDecodeDone && mCurScanline >= mAvailableLines) { mScanlineReady.wait(mLock); } return (mCurScanline < mAvailableLines) ? getScanlineInner(dst) : false; } return getScanlineInner(dst); } VideoFrame* videoFrame = static_cast<VideoFrame*>(mFrameMemory->pointer()); size_t HeifDecoderImpl::skipScanlines(size_t count) { uint32_t oldScanline = mCurScanline; mCurScanline += count; if (mCurScanline > videoFrame->mHeight) { mCurScanline = videoFrame->mHeight; if (mCurScanline > mHeight) { mCurScanline = mHeight; } return (mCurScanline > oldScanline) ? (mCurScanline - oldScanline) : 0; } Loading