OCEntityHandlerResult RCSResourceObject::handleRequestSet( std::shared_ptr< OC::OCResourceRequest > request) { assert(request != nullptr); auto attrs = getAttributesFromOCRequest(request); auto response = invokeHandler(attrs, request, m_setRequestHandler); auto requestHandler = response.getHandler(); assert(requestHandler != nullptr); AttrKeyValuePairs replaced = requestHandler->applyAcceptanceMethod( response.getAcceptanceMethod(), *this, attrs); for (const auto& attrKeyValPair : replaced) { std::lock_guard<std::mutex> lock(m_mutexKeyAttributeUpdate); auto keyAttrListener = m_keyAttributesUpdatedListeners.find(attrKeyValPair.first); if(keyAttrListener != m_keyAttributesUpdatedListeners.end()) { keyAttrListener-> second(attrKeyValPair.second, attrs[attrKeyValPair.first]); } } autoNotify(!replaced.empty(), m_autoNotifyPolicy); return sendResponse(*this, request, response); }
bool RCSResourceObject::removeAttribute(const std::string& key) { bool needToNotify = false; bool erased = false; { WeakGuard lock(*this); if (m_resourceAttributes.erase(key)) { erased = true; needToNotify = lock.hasLocked(); } } if (needToNotify) autoNotify(true); return erased; }
OCEntityHandlerResult RCSResourceObject::handleRequestSet( std::shared_ptr< OC::OCResourceRequest > request) { assert(request != nullptr); auto attrs = getAttributesFromOCRequest(request); auto response = invokeHandler(attrs, request, m_setRequestHandler); auto attrsChanged = applyAcceptanceMethod(response, attrs); try { autoNotify(attrsChanged, m_autoNotifyPolicy); return sendResponse(*this, request, response); } catch (const RCSPlatformException& e) { OC_LOG_V(ERROR, LOG_TAG, "Error : %s ", e.what()); return OC_EH_ERROR; } }
void RCSResourceObject::setAttributeInternal(K&& key, V&& value) { bool needToNotify = false; bool valueUpdated = false; { WeakGuard lock(*this); if (lock.hasLocked()) { needToNotify = true; valueUpdated = testValueUpdated(key, value); } m_resourceAttributes[std::forward< K >(key)] = std::forward< V >(value); } if (needToNotify) autoNotify(valueUpdated); }
void RCSResourceObject::autoNotify(bool isAttributesChanged) const { autoNotify(isAttributesChanged, m_autoNotifyPolicy); }
bool nsRawReader::DecodeVideoFrame(bool &aKeyframeSkip, PRInt64 aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. PRUint32 parsed = 0, decoded = 0; nsMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); if (!mFrameSize) return false; // Metadata read failed. We should refuse to play. PRInt64 currentFrameTime = USECS_PER_S * mCurrentFrame / mFrameRate; PRUint32 length = mFrameSize - sizeof(nsRawPacketHeader); nsAutoArrayPtr<PRUint8> buffer(new PRUint8[length]); nsMediaStream* stream = mDecoder->GetCurrentStream(); NS_ASSERTION(stream, "Decoder has no media stream"); // We're always decoding one frame when called while(true) { nsRawPacketHeader header; // Read in a packet header and validate if (!(ReadFromStream(stream, reinterpret_cast<PRUint8*>(&header), sizeof(header))) || !(header.packetID == 0xFF && header.codecID == RAW_ID /* "YUV" */)) { return false; } if (!ReadFromStream(stream, buffer, length)) { return false; } parsed++; if (currentFrameTime >= aTimeThreshold) break; mCurrentFrame++; currentFrameTime += static_cast<double>(USECS_PER_S) / mFrameRate; } VideoData::YCbCrBuffer b; b.mPlanes[0].mData = buffer; b.mPlanes[0].mStride = mMetadata.frameWidth * mMetadata.lumaChannelBpp / 8.0; b.mPlanes[0].mHeight = mMetadata.frameHeight; b.mPlanes[0].mWidth = mMetadata.frameWidth; PRUint32 cbcrStride = mMetadata.frameWidth * mMetadata.chromaChannelBpp / 8.0; b.mPlanes[1].mData = buffer + mMetadata.frameHeight * b.mPlanes[0].mStride; b.mPlanes[1].mStride = cbcrStride; b.mPlanes[1].mHeight = mMetadata.frameHeight / 2; b.mPlanes[1].mWidth = mMetadata.frameWidth / 2; b.mPlanes[2].mData = b.mPlanes[1].mData + mMetadata.frameHeight * cbcrStride / 2; b.mPlanes[2].mStride = cbcrStride; b.mPlanes[2].mHeight = mMetadata.frameHeight / 2; b.mPlanes[2].mWidth = mMetadata.frameWidth / 2; VideoData *v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), -1, currentFrameTime, currentFrameTime + (USECS_PER_S / mFrameRate), b, 1, // In raw video every frame is a keyframe -1, mPicture); if (!v) return false; mVideoQueue.Push(v); mCurrentFrame++; decoded++; currentFrameTime += USECS_PER_S / mFrameRate; return true; }
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); EnsureActive(); // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. uint32_t parsed = 0, decoded = 0; AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); bool doSeek = mVideoSeekTimeUs != -1; if (doSeek) { aTimeThreshold = mVideoSeekTimeUs; } TimeStamp start = TimeStamp::Now(); // Read next frame. Don't let this loop run for too long. while ((TimeStamp::Now() - start) < TimeDuration::FromSeconds(MAX_VIDEO_DECODE_SECONDS)) { MPAPI::VideoFrame frame; frame.mGraphicBuffer = nullptr; frame.mShouldSkip = false; if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) { return false; } doSeek = false; mVideoSeekTimeUs = -1; // Ignore empty buffer which stagefright media read will sporadically return if (frame.mSize == 0 && !frame.mGraphicBuffer) { continue; } parsed++; if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { mSkipCount++; continue; } mSkipCount = 0; aKeyframeSkip = false; IntRect picture = ToIntRect(mPicture); if (frame.Y.mWidth != mInitialFrame.width || frame.Y.mHeight != mInitialFrame.height) { // Frame size is different from what the container reports. This is legal, // and we will preserve the ratio of the crop rectangle as it // was reported relative to the picture size reported by the container. picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; } // This is the approximate byte position in the stream. int64_t pos = mDecoder->GetResource()->Tell(); nsRefPtr<VideoData> v; if (!frame.mGraphicBuffer) { VideoData::YCbCrBuffer b; b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData); b.mPlanes[0].mStride = frame.Y.mStride; b.mPlanes[0].mHeight = frame.Y.mHeight; b.mPlanes[0].mWidth = frame.Y.mWidth; b.mPlanes[0].mOffset = frame.Y.mOffset; b.mPlanes[0].mSkip = frame.Y.mSkip; b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData); b.mPlanes[1].mStride = frame.Cb.mStride; b.mPlanes[1].mHeight = frame.Cb.mHeight; b.mPlanes[1].mWidth = frame.Cb.mWidth; b.mPlanes[1].mOffset = frame.Cb.mOffset; b.mPlanes[1].mSkip = frame.Cb.mSkip; b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData); b.mPlanes[2].mStride = frame.Cr.mStride; b.mPlanes[2].mHeight = frame.Cr.mHeight; b.mPlanes[2].mWidth = frame.Cr.mWidth; b.mPlanes[2].mOffset = frame.Cr.mOffset; b.mPlanes[2].mSkip = frame.Cr.mSkip; v = VideoData::Create(mInfo.mVideo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, 1, // We don't know the duration. b, frame.mKeyFrame, -1, picture); } else { v = VideoData::Create(mInfo.mVideo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, 1, // We don't know the duration. frame.mGraphicBuffer, frame.mKeyFrame, -1, picture); } if (!v) { NS_WARNING("Unable to create VideoData"); return false; } decoded++; NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in OMX decoder..."); mVideoQueue.Push(v); break; } return true; }
bool MediaPluginReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. uint32_t parsed = 0, decoded = 0; AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); // Throw away the currently buffered frame if we are seeking. if (mLastVideoFrame && mVideoSeekTimeUs != -1) { mLastVideoFrame = nullptr; } ImageBufferCallback bufferCallback(mDecoder->GetImageContainer()); nsRefPtr<Image> currentImage; // Read next frame while (true) { MPAPI::VideoFrame frame; if (!mPlugin->ReadVideo(mPlugin, &frame, mVideoSeekTimeUs, &bufferCallback)) { // We reached the end of the video stream. If we have a buffered // video frame, push it the video queue using the total duration // of the video as the end time. if (mLastVideoFrame) { int64_t durationUs; mPlugin->GetDuration(mPlugin, &durationUs); if (durationUs < mLastVideoFrame->mTime) { durationUs = 0; } mVideoQueue.Push(VideoData::ShallowCopyUpdateDuration(mLastVideoFrame, durationUs)); mLastVideoFrame = nullptr; } return false; } mVideoSeekTimeUs = -1; if (aKeyframeSkip) { // Disable keyframe skipping for now as // stagefright doesn't seem to be telling us // when a frame is a keyframe. #if 0 if (!frame.mKeyFrame) { ++parsed; continue; } #endif aKeyframeSkip = false; } if (frame.mSize == 0) return true; currentImage = bufferCallback.GetImage(); int64_t pos = mDecoder->GetResource()->Tell(); nsIntRect picture = mPicture; nsAutoPtr<VideoData> v; if (currentImage) { gfx::IntSize frameSize = currentImage->GetSize(); if (frameSize.width != mInitialFrame.width || frameSize.height != mInitialFrame.height) { // Frame size is different from what the container reports. This is legal, // and we will preserve the ratio of the crop rectangle as it // was reported relative to the picture size reported by the container. picture.x = (mPicture.x * frameSize.width) / mInitialFrame.width; picture.y = (mPicture.y * frameSize.height) / mInitialFrame.height; picture.width = (frameSize.width * mPicture.width) / mInitialFrame.width; picture.height = (frameSize.height * mPicture.height) / mInitialFrame.height; } v = VideoData::CreateFromImage(mInfo.mVideo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, 1, // We don't know the duration yet. currentImage, frame.mKeyFrame, -1, picture); } else { // Assume YUV VideoData::YCbCrBuffer b; b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData); b.mPlanes[0].mStride = frame.Y.mStride; b.mPlanes[0].mHeight = frame.Y.mHeight; b.mPlanes[0].mWidth = frame.Y.mWidth; b.mPlanes[0].mOffset = frame.Y.mOffset; b.mPlanes[0].mSkip = frame.Y.mSkip; b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData); b.mPlanes[1].mStride = frame.Cb.mStride; b.mPlanes[1].mHeight = frame.Cb.mHeight; b.mPlanes[1].mWidth = frame.Cb.mWidth; b.mPlanes[1].mOffset = frame.Cb.mOffset; b.mPlanes[1].mSkip = frame.Cb.mSkip; b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData); b.mPlanes[2].mStride = frame.Cr.mStride; b.mPlanes[2].mHeight = frame.Cr.mHeight; b.mPlanes[2].mWidth = frame.Cr.mWidth; b.mPlanes[2].mOffset = frame.Cr.mOffset; b.mPlanes[2].mSkip = frame.Cr.mSkip; if (frame.Y.mWidth != mInitialFrame.width || frame.Y.mHeight != mInitialFrame.height) { // Frame size is different from what the container reports. This is legal, // and we will preserve the ratio of the crop rectangle as it // was reported relative to the picture size reported by the container. picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; } // This is the approximate byte position in the stream. v = VideoData::Create(mInfo.mVideo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, 1, // We don't know the duration yet. b, frame.mKeyFrame, -1, picture); } if (!v) { return false; } parsed++; decoded++; NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in MediaPlugin..."); // Since MPAPI doesn't give us the end time of frames, we keep one frame // buffered in MediaPluginReader and push it into the queue as soon // we read the following frame so we can use that frame's start time as // the end time of the buffered frame. if (!mLastVideoFrame) { mLastVideoFrame = v; continue; } // Calculate the duration as the timestamp of the current frame minus the // timestamp of the previous frame. We can then return the previously // decoded frame, and it will have a valid timestamp. int64_t duration = v->mTime - mLastVideoFrame->mTime; mLastVideoFrame = VideoData::ShallowCopyUpdateDuration(mLastVideoFrame, duration); // We have the start time of the next frame, so we can push the previous // frame into the queue, except if the end time is below the threshold, // in which case it wouldn't be displayed anyway. if (mLastVideoFrame->GetEndTime() < aTimeThreshold) { mLastVideoFrame = nullptr; continue; } mVideoQueue.Push(mLastVideoFrame.forget()); // Buffer the current frame we just decoded. mLastVideoFrame = v; break; } return true; }
bool WMFReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { NS_ASSERTION(mDecoder->OnDecodeThread(), "Should be on decode thread."); // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. uint32_t parsed = 0, decoded = 0; AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); HRESULT hr; hr = mSourceReader->ReadSample(MF_SOURCE_READER_FIRST_VIDEO_STREAM, 0, // control flags 0, // read stream index nullptr, nullptr, nullptr); if (FAILED(hr)) { LOG("WMFReader::DecodeVideoData() ReadSample failed with hr=0x%x", hr); return false; } DWORD flags = 0; LONGLONG timestampHns = 0; RefPtr<IMFSample> sample; hr = mSourceReaderCallback->Wait(&flags, ×tampHns, byRef(sample)); if (flags & MF_SOURCE_READERF_ERROR) { NS_WARNING("WMFReader: Catastrophic failure reading video sample"); // Future ReadSample() calls will fail, so give up and report end of stream. return false; } if (FAILED(hr)) { // Unknown failure, ask caller to try again? return true; } if (!sample) { if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) { LOG("WMFReader; Null sample after video decode, at end of stream"); return false; } LOG("WMFReader; Null sample after video decode. Maybe insufficient data..."); return true; } if ((flags & MF_SOURCE_READERF_CURRENTMEDIATYPECHANGED)) { LOG("WMFReader: Video media type changed!"); RefPtr<IMFMediaType> mediaType; hr = mSourceReader->GetCurrentMediaType(MF_SOURCE_READER_FIRST_VIDEO_STREAM, byRef(mediaType)); if (FAILED(hr) || FAILED(ConfigureVideoFrameGeometry(mediaType))) { NS_WARNING("Failed to reconfigure video media type"); return false; } } int64_t timestamp = HNsToUsecs(timestampHns); if (timestamp < aTimeThreshold) { return true; } int64_t offset = mDecoder->GetResource()->Tell(); int64_t duration = GetSampleDuration(sample); VideoData* v = nullptr; if (mUseHwAccel) { hr = CreateD3DVideoFrame(sample, timestamp, duration, offset, &v); } else { hr = CreateBasicVideoFrame(sample, timestamp, duration, offset, &v); } NS_ENSURE_TRUE(SUCCEEDED(hr) && v, false); parsed++; decoded++; mVideoQueue.Push(v); #ifdef LOG_SAMPLE_DECODE LOG("Decoded video sample timestamp=%lld duration=%lld stride=%d height=%u flags=%u", timestamp, duration, mVideoStride, mVideoHeight, flags); #endif if ((flags & MF_SOURCE_READERF_ENDOFSTREAM)) { // End of stream. LOG("End of video stream"); return false; } return true; }
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. uint32_t parsed = 0, decoded = 0; AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); bool doSeek = mVideoSeekTimeUs != -1; if (doSeek) { aTimeThreshold = mVideoSeekTimeUs; } // Read next frame while (true) { MPAPI::VideoFrame frame; frame.mGraphicBuffer = nullptr; frame.mShouldSkip = false; if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) { mVideoQueue.Finish(); return false; } parsed++; if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { mSkipCount++; return true; } mSkipCount = 0; mVideoSeekTimeUs = -1; doSeek = aKeyframeSkip = false; nsIntRect picture = mPicture; if (frame.Y.mWidth != mInitialFrame.width || frame.Y.mHeight != mInitialFrame.height) { // Frame size is different from what the container reports. This is legal, // and we will preserve the ratio of the crop rectangle as it // was reported relative to the picture size reported by the container. picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; } // This is the approximate byte position in the stream. int64_t pos = mDecoder->GetResource()->Tell(); VideoData *v; if (!frame.mGraphicBuffer) { VideoData::YCbCrBuffer b; b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData); b.mPlanes[0].mStride = frame.Y.mStride; b.mPlanes[0].mHeight = frame.Y.mHeight; b.mPlanes[0].mWidth = frame.Y.mWidth; b.mPlanes[0].mOffset = frame.Y.mOffset; b.mPlanes[0].mSkip = frame.Y.mSkip; b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData); b.mPlanes[1].mStride = frame.Cb.mStride; b.mPlanes[1].mHeight = frame.Cb.mHeight; b.mPlanes[1].mWidth = frame.Cb.mWidth; b.mPlanes[1].mOffset = frame.Cb.mOffset; b.mPlanes[1].mSkip = frame.Cb.mSkip; b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData); b.mPlanes[2].mStride = frame.Cr.mStride; b.mPlanes[2].mHeight = frame.Cr.mHeight; b.mPlanes[2].mWidth = frame.Cr.mWidth; b.mPlanes[2].mOffset = frame.Cr.mOffset; b.mPlanes[2].mSkip = frame.Cr.mSkip; v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, frame.mTimeUs+1, // We don't know the end time. b, frame.mKeyFrame, -1, picture); } else { v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, frame.mTimeUs+1, // We don't know the end time. frame.mGraphicBuffer, frame.mKeyFrame, -1, picture); } if (!v) { NS_WARNING("Unable to create VideoData"); return false; } decoded++; NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in MediaPlugin..."); mVideoQueue.Push(v); break; } return true; }
bool MediaOmxReader::DecodeVideoFrame(bool &aKeyframeSkip, int64_t aTimeThreshold) { // Record number of frames decoded and parsed. Automatically update the // stats counters using the AutoNotifyDecoded stack-based class. uint32_t parsed = 0, decoded = 0; AbstractMediaDecoder::AutoNotifyDecoded autoNotify(mDecoder, parsed, decoded); // Throw away the currently buffered frame if we are seeking. if (mLastVideoFrame && mVideoSeekTimeUs != -1) { delete mLastVideoFrame; mLastVideoFrame = nullptr; } bool doSeek = mVideoSeekTimeUs != -1; if (doSeek) { aTimeThreshold = mVideoSeekTimeUs; } // Read next frame while (true) { MPAPI::VideoFrame frame; frame.mGraphicBuffer = nullptr; frame.mShouldSkip = false; if (!mOmxDecoder->ReadVideo(&frame, aTimeThreshold, aKeyframeSkip, doSeek)) { // We reached the end of the video stream. If we have a buffered // video frame, push it the video queue using the total duration // of the video as the end time. if (mLastVideoFrame) { int64_t durationUs; mOmxDecoder->GetDuration(&durationUs); mLastVideoFrame->mEndTime = (durationUs > mLastVideoFrame->mTime) ? durationUs : mLastVideoFrame->mTime; mVideoQueue.Push(mLastVideoFrame); mLastVideoFrame = nullptr; } mVideoQueue.Finish(); return false; } parsed++; if (frame.mShouldSkip && mSkipCount < MAX_DROPPED_FRAMES) { mSkipCount++; return true; } mSkipCount = 0; mVideoSeekTimeUs = -1; doSeek = aKeyframeSkip = false; nsIntRect picture = mPicture; if (frame.Y.mWidth != mInitialFrame.width || frame.Y.mHeight != mInitialFrame.height) { // Frame size is different from what the container reports. This is legal, // and we will preserve the ratio of the crop rectangle as it // was reported relative to the picture size reported by the container. picture.x = (mPicture.x * frame.Y.mWidth) / mInitialFrame.width; picture.y = (mPicture.y * frame.Y.mHeight) / mInitialFrame.height; picture.width = (frame.Y.mWidth * mPicture.width) / mInitialFrame.width; picture.height = (frame.Y.mHeight * mPicture.height) / mInitialFrame.height; } // This is the approximate byte position in the stream. int64_t pos = mDecoder->GetResource()->Tell(); VideoData *v; if (!frame.mGraphicBuffer) { VideoData::YCbCrBuffer b; b.mPlanes[0].mData = static_cast<uint8_t *>(frame.Y.mData); b.mPlanes[0].mStride = frame.Y.mStride; b.mPlanes[0].mHeight = frame.Y.mHeight; b.mPlanes[0].mWidth = frame.Y.mWidth; b.mPlanes[0].mOffset = frame.Y.mOffset; b.mPlanes[0].mSkip = frame.Y.mSkip; b.mPlanes[1].mData = static_cast<uint8_t *>(frame.Cb.mData); b.mPlanes[1].mStride = frame.Cb.mStride; b.mPlanes[1].mHeight = frame.Cb.mHeight; b.mPlanes[1].mWidth = frame.Cb.mWidth; b.mPlanes[1].mOffset = frame.Cb.mOffset; b.mPlanes[1].mSkip = frame.Cb.mSkip; b.mPlanes[2].mData = static_cast<uint8_t *>(frame.Cr.mData); b.mPlanes[2].mStride = frame.Cr.mStride; b.mPlanes[2].mHeight = frame.Cr.mHeight; b.mPlanes[2].mWidth = frame.Cr.mWidth; b.mPlanes[2].mOffset = frame.Cr.mOffset; b.mPlanes[2].mSkip = frame.Cr.mSkip; v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, frame.mTimeUs+1, // We don't know the end time. b, frame.mKeyFrame, -1, picture); } else { v = VideoData::Create(mInfo, mDecoder->GetImageContainer(), pos, frame.mTimeUs, frame.mTimeUs+1, // We don't know the end time. frame.mGraphicBuffer, frame.mKeyFrame, -1, picture); } if (!v) { NS_WARNING("Unable to create VideoData"); return false; } decoded++; NS_ASSERTION(decoded <= parsed, "Expect to decode fewer frames than parsed in MediaPlugin..."); // Seeking hack if (mLastVideoFrame && mLastVideoFrame->mTime > v->mTime) { delete mLastVideoFrame; mLastVideoFrame = v; continue; } // Since MPAPI doesn't give us the end time of frames, we keep one frame // buffered in MediaOmxReader and push it into the queue as soon // we read the following frame so we can use that frame's start time as // the end time of the buffered frame. if (!mLastVideoFrame) { mLastVideoFrame = v; continue; } mLastVideoFrame->mEndTime = v->mTime; mVideoQueue.Push(mLastVideoFrame); // Buffer the current frame we just decoded. mLastVideoFrame = v; break; } return true; }