RemoteImageHolder.cpp (8876B)
1 /* -*- Mode: C++; tab-width: 8; indent-tabs-mode: nil; c-basic-offset: 2 -*- */ 2 /* vim: set ts=8 sts=2 et sw=2 tw=80: */ 3 /* This Source Code Form is subject to the terms of the Mozilla Public 4 * License, v. 2.0. If a copy of the MPL was not distributed with this 5 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */ 6 7 #include "RemoteImageHolder.h" 8 9 #include "GPUVideoImage.h" 10 #include "mozilla/PRemoteDecoderChild.h" 11 #include "mozilla/RemoteDecodeUtils.h" 12 #include "mozilla/RemoteMediaManagerChild.h" 13 #include "mozilla/RemoteMediaManagerParent.h" 14 #include "mozilla/gfx/SourceSurfaceRawData.h" 15 #include "mozilla/gfx/Swizzle.h" 16 #include "mozilla/layers/ImageDataSerializer.h" 17 #include "mozilla/layers/VideoBridgeUtils.h" 18 19 namespace mozilla { 20 21 using namespace gfx; 22 using namespace layers; 23 24 RemoteImageHolder::RemoteImageHolder() = default; 25 RemoteImageHolder::RemoteImageHolder(layers::SurfaceDescriptor&& aSD) 26 : mSD(Some(std::move(aSD))) {} 27 RemoteImageHolder::RemoteImageHolder( 28 layers::IGPUVideoSurfaceManager* aManager, 29 layers::VideoBridgeSource aSource, const gfx::IntSize& aSize, 30 const gfx::ColorDepth& aColorDepth, const layers::SurfaceDescriptor& aSD, 31 gfx::YUVColorSpace aYUVColorSpace, gfx::ColorSpace2 aColorPrimaries, 32 gfx::TransferFunction aTransferFunction, gfx::ColorRange aColorRange) 33 : mSource(aSource), 34 mSize(aSize), 35 mColorDepth(aColorDepth), 36 mSD(Some(aSD)), 37 mManager(aManager), 38 mYUVColorSpace(aYUVColorSpace), 39 mColorPrimaries(aColorPrimaries), 40 mTransferFunction(aTransferFunction), 41 mColorRange(aColorRange) {} 42 43 RemoteImageHolder::RemoteImageHolder(RemoteImageHolder&& aOther) 44 : mSource(aOther.mSource), 45 mSize(aOther.mSize), 46 mColorDepth(aOther.mColorDepth), 47 mSD(std::move(aOther.mSD)), 48 mManager(aOther.mManager), 49 mYUVColorSpace(aOther.mYUVColorSpace), 50 mColorPrimaries(aOther.mColorPrimaries), 51 mTransferFunction(aOther.mTransferFunction), 52 mColorRange(aOther.mColorRange) { 53 aOther.mSD = Nothing(); 54 } 55 56 already_AddRefed<Image> RemoteImageHolder::DeserializeImage( 57 layers::BufferRecycleBin* aBufferRecycleBin) { 58 MOZ_ASSERT(mSD && mSD->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer); 59 if (!aBufferRecycleBin) { 60 return nullptr; 61 } 62 63 const SurfaceDescriptorBuffer& sdBuffer = mSD->get_SurfaceDescriptorBuffer(); 64 const MemoryOrShmem& memOrShmem = sdBuffer.data(); 65 if (memOrShmem.type() != MemoryOrShmem::TShmem) { 66 MOZ_ASSERT_UNREACHABLE("Unexpected MemoryOrShmem type"); 67 return nullptr; 68 } 69 70 // Note that the shmem will be recycled by the parent automatically. 71 uint8_t* buffer = memOrShmem.get_Shmem().get<uint8_t>(); 72 if (!buffer) { 73 return nullptr; 74 } 75 76 size_t bufferSize = memOrShmem.get_Shmem().Size<uint8_t>(); 77 78 if (sdBuffer.desc().type() == BufferDescriptor::TYCbCrDescriptor) { 79 const YCbCrDescriptor& descriptor = sdBuffer.desc().get_YCbCrDescriptor(); 80 81 size_t descriptorSize = ImageDataSerializer::ComputeYCbCrBufferSize( 82 descriptor.ySize(), descriptor.yStride(), descriptor.cbCrSize(), 83 descriptor.cbCrStride(), descriptor.yOffset(), descriptor.cbOffset(), 84 descriptor.crOffset()); 85 if (NS_WARN_IF(descriptorSize > bufferSize)) { 86 MOZ_ASSERT_UNREACHABLE("Buffer too small to fit descriptor!"); 87 return nullptr; 88 } 89 90 PlanarYCbCrData pData; 91 pData.mYStride = descriptor.yStride(); 92 pData.mCbCrStride = descriptor.cbCrStride(); 93 // default mYSkip, mCbSkip, mCrSkip because not held in YCbCrDescriptor 94 pData.mYSkip = pData.mCbSkip = pData.mCrSkip = 0; 95 pData.mPictureRect = descriptor.display(); 96 pData.mStereoMode = descriptor.stereoMode(); 97 pData.mColorDepth = descriptor.colorDepth(); 98 pData.mYUVColorSpace = descriptor.yUVColorSpace(); 99 pData.mColorRange = descriptor.colorRange(); 100 pData.mChromaSubsampling = descriptor.chromaSubsampling(); 101 pData.mYChannel = ImageDataSerializer::GetYChannel(buffer, descriptor); 102 pData.mCbChannel = ImageDataSerializer::GetCbChannel(buffer, descriptor); 103 pData.mCrChannel = ImageDataSerializer::GetCrChannel(buffer, descriptor); 104 105 // images coming from AOMDecoder are RecyclingPlanarYCbCrImages. 106 RefPtr<RecyclingPlanarYCbCrImage> image = 107 new RecyclingPlanarYCbCrImage(aBufferRecycleBin); 108 if (NS_WARN_IF(NS_FAILED(image->CopyData(pData)))) { 109 return nullptr; 110 } 111 112 return image.forget(); 113 } 114 115 if (sdBuffer.desc().type() == BufferDescriptor::TRGBDescriptor) { 116 const RGBDescriptor& descriptor = sdBuffer.desc().get_RGBDescriptor(); 117 118 size_t descriptorSize = ImageDataSerializer::ComputeRGBBufferSize( 119 descriptor.size(), descriptor.format()); 120 if (NS_WARN_IF(descriptorSize > bufferSize)) { 121 MOZ_ASSERT_UNREACHABLE("Buffer too small to fit descriptor!"); 122 return nullptr; 123 } 124 125 auto stride = ImageDataSerializer::ComputeRGBStride( 126 descriptor.format(), descriptor.size().width); 127 auto surface = MakeRefPtr<SourceSurfaceAlignedRawData>(); 128 if (NS_WARN_IF(!surface->Init(descriptor.size(), descriptor.format(), 129 /* aClearMem */ false, /* aClearValue */ 0, 130 stride))) { 131 return nullptr; 132 } 133 134 DataSourceSurface::ScopedMap map(surface, DataSourceSurface::WRITE); 135 if (NS_WARN_IF(!map.IsMapped())) { 136 return nullptr; 137 } 138 139 if (NS_WARN_IF(!SwizzleData(buffer, stride, descriptor.format(), 140 map.GetData(), map.GetStride(), 141 descriptor.format(), descriptor.size()))) { 142 return nullptr; 143 } 144 145 return MakeAndAddRef<SourceSurfaceImage>(descriptor.size(), surface); 146 } 147 148 MOZ_ASSERT_UNREACHABLE("Unexpected buffer descriptor type!"); 149 return nullptr; 150 } 151 152 already_AddRefed<layers::Image> RemoteImageHolder::TransferToImage( 153 layers::BufferRecycleBin* aBufferRecycleBin) { 154 if (IsEmpty()) { 155 return nullptr; 156 } 157 RefPtr<Image> image; 158 if (mSD->type() == SurfaceDescriptor::TSurfaceDescriptorBuffer) { 159 image = DeserializeImage(aBufferRecycleBin); 160 } else if (mManager) { 161 image = mManager->TransferToImage(*mSD, mSize, mColorDepth, mYUVColorSpace, 162 mColorPrimaries, mTransferFunction, 163 mColorRange); 164 } 165 mSD = Nothing(); 166 mManager = nullptr; 167 168 return image.forget(); 169 } 170 171 RemoteImageHolder::~RemoteImageHolder() { 172 // GPU Images are held by the RemoteMediaManagerParent, we didn't get to use 173 // this image holder (the decoder could have been flushed). We don't need to 174 // worry about Shmem based image as the Shmem will be automatically re-used 175 // once the decoder is used again. 176 if (!IsEmpty() && mManager && 177 mSD->type() != SurfaceDescriptor::TSurfaceDescriptorBuffer) { 178 SurfaceDescriptorRemoteDecoder remoteSD = 179 static_cast<const SurfaceDescriptorGPUVideo&>(*mSD); 180 mManager->DeallocateSurfaceDescriptor(remoteSD); 181 } 182 } 183 184 } // namespace mozilla 185 186 /* static */ void IPC::ParamTraits<mozilla::RemoteImageHolder>::Write( 187 MessageWriter* aWriter, mozilla::RemoteImageHolder&& aParam) { 188 WriteParam(aWriter, aParam.mSource); 189 WriteParam(aWriter, aParam.mSize); 190 WriteParam(aWriter, aParam.mColorDepth); 191 WriteParam(aWriter, aParam.mSD); 192 WriteParam(aWriter, aParam.mYUVColorSpace); 193 WriteParam(aWriter, aParam.mColorPrimaries); 194 WriteParam(aWriter, aParam.mTransferFunction); 195 WriteParam(aWriter, aParam.mColorRange); 196 // Empty this holder. 197 aParam.mSD = mozilla::Nothing(); 198 aParam.mManager = nullptr; 199 } 200 201 /* static */ bool IPC::ParamTraits<mozilla::RemoteImageHolder>::Read( 202 MessageReader* aReader, mozilla::RemoteImageHolder* aResult) { 203 if (!ReadParam(aReader, &aResult->mSource) || 204 !ReadParam(aReader, &aResult->mSize) || 205 !ReadParam(aReader, &aResult->mColorDepth) || 206 !ReadParam(aReader, &aResult->mSD) || 207 !ReadParam(aReader, &aResult->mYUVColorSpace) || 208 !ReadParam(aReader, &aResult->mColorPrimaries) || 209 !ReadParam(aReader, &aResult->mTransferFunction) || 210 !ReadParam(aReader, &aResult->mColorRange)) { 211 return false; 212 } 213 214 if (aResult->IsEmpty()) { 215 return true; 216 } 217 218 if (auto* actor = aReader->GetActor()) { 219 if (auto* manager = actor->Manager()) { 220 if (manager->GetProtocolId() == 221 mozilla::ipc::ProtocolId::PRemoteMediaManagerMsgStart) { 222 aResult->mManager = 223 XRE_IsContentProcess() 224 ? static_cast<mozilla::IGPUVideoSurfaceManager*>( 225 static_cast<mozilla::RemoteMediaManagerChild*>(manager)) 226 : static_cast<mozilla::IGPUVideoSurfaceManager*>( 227 static_cast<mozilla::RemoteMediaManagerParent*>(manager)); 228 return true; 229 } 230 } 231 } 232 233 MOZ_ASSERT_UNREACHABLE("Unexpected or missing protocol manager!"); 234 return false; 235 }