static void CVPX_I420(filter_t *p_filter, picture_t *sourcePicture, picture_t *destinationPicture) { VLC_UNUSED(p_filter); picture_sys_t *picsys = sourcePicture->p_sys; if (picsys == NULL) return; if (picsys->pixelBuffer == nil) return; unsigned width = CVPixelBufferGetWidthOfPlane(picsys->pixelBuffer, 0); unsigned height = CVPixelBufferGetHeightOfPlane(picsys->pixelBuffer, 0); if (width == 0 || height == 0) return; uint8_t *pp_plane[2]; size_t pi_pitch[2]; CVPixelBufferLockBaseAddress(picsys->pixelBuffer, kCVPixelBufferLock_ReadOnly); for (int i = 0; i < 2; i++) { pp_plane[i] = CVPixelBufferGetBaseAddressOfPlane(picsys->pixelBuffer, i); pi_pitch[i] = CVPixelBufferGetBytesPerRowOfPlane(picsys->pixelBuffer, i); } CopyFromNv12ToI420(destinationPicture, pp_plane, pi_pitch, height); CVPixelBufferUnlockBaseAddress(picsys->pixelBuffer, kCVPixelBufferLock_ReadOnly); }
// Copy and return a decoded frame. nsresult AppleVTDecoder::OutputFrame(CVPixelBufferRef aImage, nsAutoPtr<FrameRef> aFrameRef) { size_t width = CVPixelBufferGetWidth(aImage); size_t height = CVPixelBufferGetHeight(aImage); LOG(" got decoded frame data... %ux%u %s", width, height, CVPixelBufferIsPlanar(aImage) ? "planar" : "chunked"); #ifdef DEBUG size_t planes = CVPixelBufferGetPlaneCount(aImage); for (size_t i = 0; i < planes; ++i) { size_t stride = CVPixelBufferGetBytesPerRowOfPlane(aImage, i); LOG(" plane %u %ux%u rowbytes %u", (unsigned)i, CVPixelBufferGetWidthOfPlane(aImage, i), CVPixelBufferGetHeightOfPlane(aImage, i), (unsigned)stride); } MOZ_ASSERT(planes == 2); #endif // DEBUG 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; // Bounds. VideoInfo info; info.mDisplay = nsIntSize(width, height); info.mHasVideo = true; gfx::IntRect visible = gfx::IntRect(0, 0, mConfig.display_width, mConfig.display_height); // Copy the image data into our own format. nsAutoPtr<VideoData> data; data = VideoData::Create(info, mImageContainer, nullptr, aFrameRef->byte_offset, aFrameRef->composition_timestamp, aFrameRef->duration, buffer, aFrameRef->is_sync_point, aFrameRef->decode_timestamp, visible); // Unlock the returned image data. CVPixelBufferUnlockBaseAddress(aImage, kCVPixelBufferLock_ReadOnly); 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. mReorderQueue.Push(data.forget()); // Assume a frame with a PTS <= current DTS is ready. while (mReorderQueue.Length() > 0) { VideoData* readyData = mReorderQueue.Pop(); if (readyData->mTime <= aFrameRef->decode_timestamp) { LOG("returning queued frame with pts %lld", readyData->mTime); mCallback->Output(readyData); } else { LOG("requeued frame with pts %lld > %lld", readyData->mTime, aFrameRef->decode_timestamp); mReorderQueue.Push(readyData); break; } } LOG("%llu decoded frames queued", static_cast<unsigned long long>(mReorderQueue.Length())); return NS_OK; }
size_t QTPixelBuffer::widthOfPlane(size_t plane) const { return CVPixelBufferGetWidthOfPlane(m_pixelBuffer, plane); }