зеркало из https://github.com/mozilla/gecko-dev.git
Bug 1653409
- Upload software decoded video directly to IOSurface on OSX. r=mstange
Differential Revision: https://phabricator.services.mozilla.com/D85105
This commit is contained in:
Родитель
87db131e32
Коммит
553c2d162d
|
@ -19,6 +19,8 @@
|
|||
#ifdef XP_WIN
|
||||
# include "mozilla/WindowsVersion.h"
|
||||
# include "mozilla/layers/D3D11YCbCrImage.h"
|
||||
#elif XP_MACOSX
|
||||
# include "MacIOSurfaceImage.h"
|
||||
#endif
|
||||
|
||||
namespace mozilla {
|
||||
|
@ -348,6 +350,14 @@ already_AddRefed<VideoData> VideoData::CreateAndCopyData(
|
|||
return v.forget();
|
||||
}
|
||||
}
|
||||
#elif XP_MACOSX
|
||||
RefPtr<layers::MacIOSurfaceImage> ioImage =
|
||||
new layers::MacIOSurfaceImage(nullptr);
|
||||
PlanarYCbCrData data = ConstructPlanarYCbCrData(aInfo, aBuffer, aPicture);
|
||||
if (ioImage->SetData(aContainer, data)) {
|
||||
v->mImage = ioImage;
|
||||
return v.forget();
|
||||
}
|
||||
#endif
|
||||
if (!v->mImage) {
|
||||
v->mImage = aContainer->CreatePlanarYCbCrImage();
|
||||
|
|
|
@ -74,6 +74,106 @@ already_AddRefed<MacIOSurface> MacIOSurface::CreateIOSurface(
|
|||
return ioSurface.forget();
|
||||
}
|
||||
|
||||
void AddDictionaryInt(const CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
||||
const void* aType, uint32_t aValue) {
|
||||
auto cfValue = CFTypeRefPtr<CFNumberRef>::WrapUnderCreateRule(
|
||||
::CFNumberCreate(nullptr, kCFNumberSInt32Type, &aValue));
|
||||
::CFDictionaryAddValue(aDict.get(), aType, cfValue.get());
|
||||
}
|
||||
|
||||
size_t CreatePlaneDictionary(CFTypeRefPtr<CFMutableDictionaryRef>& aDict,
|
||||
const gfx::IntSize& aSize, size_t aOffset,
|
||||
size_t aBytesPerPixel) {
|
||||
size_t bytesPerRow = IOSurfaceAlignProperty(kIOSurfaceBytesPerRow,
|
||||
aSize.width * aBytesPerPixel);
|
||||
size_t totalBytes =
|
||||
IOSurfaceAlignProperty(kIOSurfaceAllocSize, aSize.height * bytesPerRow);
|
||||
|
||||
aDict = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
||||
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneWidth, aSize.width);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneHeight, aSize.height);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneBytesPerRow, bytesPerRow);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneOffset, aOffset);
|
||||
AddDictionaryInt(aDict, kIOSurfacePlaneSize, totalBytes);
|
||||
AddDictionaryInt(aDict, kIOSurfaceBytesPerElement, aBytesPerPixel);
|
||||
|
||||
return totalBytes;
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::CreateNV12Surface(
|
||||
const IntSize& aYSize, const IntSize& aCbCrSize, YUVColorSpace aColorSpace,
|
||||
ColorRange aColorRange) {
|
||||
MOZ_ASSERT(aColorSpace == YUVColorSpace::BT601 ||
|
||||
aColorSpace == YUVColorSpace::BT709);
|
||||
MOZ_ASSERT(aColorRange == ColorRange::LIMITED ||
|
||||
aColorRange == ColorRange::FULL);
|
||||
|
||||
auto props = CFTypeRefPtr<CFMutableDictionaryRef>::WrapUnderCreateRule(
|
||||
::CFDictionaryCreateMutable(kCFAllocatorDefault, 4,
|
||||
&kCFTypeDictionaryKeyCallBacks,
|
||||
&kCFTypeDictionaryValueCallBacks));
|
||||
if (!props) return nullptr;
|
||||
|
||||
MOZ_ASSERT((size_t)aYSize.width <= GetMaxWidth());
|
||||
MOZ_ASSERT((size_t)aYSize.height <= GetMaxHeight());
|
||||
|
||||
AddDictionaryInt(props, kIOSurfaceWidth, aYSize.width);
|
||||
AddDictionaryInt(props, kIOSurfaceHeight, aYSize.height);
|
||||
::CFDictionaryAddValue(props.get(), kIOSurfaceIsGlobal, kCFBooleanTrue);
|
||||
|
||||
if (aColorRange == ColorRange::LIMITED) {
|
||||
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange);
|
||||
} else {
|
||||
AddDictionaryInt(props, kIOSurfacePixelFormat,
|
||||
(uint32_t)kCVPixelFormatType_420YpCbCr8BiPlanarFullRange);
|
||||
}
|
||||
|
||||
CFTypeRefPtr<CFMutableDictionaryRef> planeProps[2];
|
||||
size_t planeTotalBytes = CreatePlaneDictionary(planeProps[0], aYSize, 0, 1);
|
||||
planeTotalBytes +=
|
||||
CreatePlaneDictionary(planeProps[1], aCbCrSize, planeTotalBytes, 2);
|
||||
|
||||
AddDictionaryInt(props, kIOSurfaceAllocSize, planeTotalBytes);
|
||||
|
||||
auto array = CFTypeRefPtr<CFArrayRef>::WrapUnderCreateRule(
|
||||
CFArrayCreate(kCFAllocatorDefault, (const void**)planeProps, 2,
|
||||
&kCFTypeArrayCallBacks));
|
||||
::CFDictionaryAddValue(props.get(), kIOSurfacePlaneInfo, array.get());
|
||||
|
||||
CFTypeRefPtr<IOSurfaceRef> surfaceRef =
|
||||
CFTypeRefPtr<IOSurfaceRef>::WrapUnderCreateRule(
|
||||
::IOSurfaceCreate(props.get()));
|
||||
|
||||
if (!surfaceRef) {
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
CFTypeRefPtr<CGColorSpaceRef> colorSpace;
|
||||
if (aColorSpace == YUVColorSpace::BT601) {
|
||||
colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCreateWithName(kCGColorSpaceSRGB));
|
||||
|
||||
} else {
|
||||
colorSpace = CFTypeRefPtr<CGColorSpaceRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCreateWithName(kCGColorSpaceITUR_709));
|
||||
}
|
||||
auto colorData = CFTypeRefPtr<CFDataRef>::WrapUnderCreateRule(
|
||||
CGColorSpaceCopyICCProfile(colorSpace.get()));
|
||||
IOSurfaceSetValue(surfaceRef.get(), CFSTR("IOSurfaceColorSpace"),
|
||||
colorData.get());
|
||||
|
||||
RefPtr<MacIOSurface> ioSurface =
|
||||
new MacIOSurface(std::move(surfaceRef), 1.0, false, aColorSpace);
|
||||
|
||||
return ioSurface.forget();
|
||||
}
|
||||
|
||||
/* static */
|
||||
already_AddRefed<MacIOSurface> MacIOSurface::LookupSurface(
|
||||
IOSurfaceID aIOSurfaceID, double aContentsScaleFactor, bool aHasAlpha,
|
||||
|
|
|
@ -48,6 +48,9 @@ class MacIOSurface final
|
|||
typedef mozilla::gfx::SourceSurface SourceSurface;
|
||||
typedef mozilla::gfx::DrawTarget DrawTarget;
|
||||
typedef mozilla::gfx::BackendType BackendType;
|
||||
typedef mozilla::gfx::IntSize IntSize;
|
||||
typedef mozilla::gfx::YUVColorSpace YUVColorSpace;
|
||||
typedef mozilla::gfx::ColorRange ColorRange;
|
||||
|
||||
// The usage count of the IOSurface is increased by 1 during the lifetime
|
||||
// of the MacIOSurface instance.
|
||||
|
@ -56,6 +59,9 @@ class MacIOSurface final
|
|||
static already_AddRefed<MacIOSurface> CreateIOSurface(
|
||||
int aWidth, int aHeight, double aContentsScaleFactor = 1.0,
|
||||
bool aHasAlpha = true);
|
||||
static already_AddRefed<MacIOSurface> CreateNV12Surface(
|
||||
const IntSize& aYSize, const IntSize& aCbCrSize,
|
||||
YUVColorSpace aColorSpace, ColorRange aColorRange);
|
||||
static void ReleaseIOSurface(MacIOSurface* aIOSurface);
|
||||
static already_AddRefed<MacIOSurface> LookupSurface(
|
||||
IOSurfaceID aSurfaceID, double aContentsScaleFactor = 1.0,
|
||||
|
@ -68,6 +74,7 @@ class MacIOSurface final
|
|||
bool aHasAlpha = true,
|
||||
mozilla::gfx::YUVColorSpace aColorSpace =
|
||||
mozilla::gfx::YUVColorSpace::UNKNOWN);
|
||||
|
||||
~MacIOSurface();
|
||||
IOSurfaceID GetIOSurfaceID() const;
|
||||
void* GetBaseAddress() const;
|
||||
|
@ -80,6 +87,9 @@ class MacIOSurface final
|
|||
// device pixel. Use GetDevicePixel**() to get device pixels.
|
||||
size_t GetWidth(size_t plane = 0) const;
|
||||
size_t GetHeight(size_t plane = 0) const;
|
||||
IntSize GetSize(size_t plane = 0) const {
|
||||
return IntSize(GetWidth(plane), GetHeight(plane));
|
||||
}
|
||||
double GetContentsScaleFactor() const { return mContentsScaleFactor; }
|
||||
size_t GetDevicePixelWidth(size_t plane = 0) const;
|
||||
size_t GetDevicePixelHeight(size_t plane = 0) const;
|
||||
|
@ -95,10 +105,10 @@ class MacIOSurface final
|
|||
// This would be better suited on MacIOSurfaceImage type, however due to the
|
||||
// current data structure, this is not possible as only the IOSurfaceRef is
|
||||
// being used across.
|
||||
void SetYUVColorSpace(mozilla::gfx::YUVColorSpace aColorSpace) {
|
||||
void SetYUVColorSpace(YUVColorSpace aColorSpace) {
|
||||
mColorSpace = aColorSpace;
|
||||
}
|
||||
mozilla::gfx::YUVColorSpace GetYUVColorSpace() const { return mColorSpace; }
|
||||
YUVColorSpace GetYUVColorSpace() const { return mColorSpace; }
|
||||
bool IsFullRange() const {
|
||||
return GetPixelFormat() == kCVPixelFormatType_420YpCbCr8BiPlanarFullRange;
|
||||
}
|
||||
|
@ -132,8 +142,7 @@ class MacIOSurface final
|
|||
double mContentsScaleFactor;
|
||||
bool mHasAlpha;
|
||||
bool mIsLocked = false;
|
||||
mozilla::gfx::YUVColorSpace mColorSpace =
|
||||
mozilla::gfx::YUVColorSpace::UNKNOWN;
|
||||
YUVColorSpace mColorSpace = YUVColorSpace::UNKNOWN;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
|
|
@ -32,6 +32,7 @@
|
|||
|
||||
#ifdef XP_MACOSX
|
||||
# include "mozilla/gfx/QuartzSupport.h"
|
||||
# include "MacIOSurfaceImage.h"
|
||||
#endif
|
||||
|
||||
#ifdef XP_WIN
|
||||
|
@ -462,6 +463,17 @@ D3D11YCbCrRecycleAllocator* ImageContainer::GetD3D11YCbCrRecycleAllocator(
|
|||
}
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
MacIOSurfaceRecycleAllocator*
|
||||
ImageContainer::GetMacIOSurfaceRecycleAllocator() {
|
||||
if (!mMacIOSurfaceRecycleAllocator) {
|
||||
mMacIOSurfaceRecycleAllocator = new MacIOSurfaceRecycleAllocator();
|
||||
}
|
||||
|
||||
return mMacIOSurfaceRecycleAllocator;
|
||||
}
|
||||
#endif
|
||||
|
||||
PlanarYCbCrImage::PlanarYCbCrImage()
|
||||
: Image(nullptr, ImageFormat::PLANAR_YCBCR),
|
||||
mOffscreenFormat(SurfaceFormat::UNKNOWN),
|
||||
|
|
|
@ -153,6 +153,9 @@ class NVImage;
|
|||
#ifdef XP_WIN
|
||||
class D3D11YCbCrRecycleAllocator;
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
class MacIOSurfaceRecycleAllocator;
|
||||
#endif
|
||||
class SurfaceDescriptorBuffer;
|
||||
|
||||
struct ImageBackendData {
|
||||
|
@ -555,6 +558,10 @@ class ImageContainer final : public SupportsWeakPtr {
|
|||
KnowsCompositor* aKnowsCompositor);
|
||||
#endif
|
||||
|
||||
#ifdef XP_MACOSX
|
||||
MacIOSurfaceRecycleAllocator* GetMacIOSurfaceRecycleAllocator();
|
||||
#endif
|
||||
|
||||
/**
|
||||
* Returns the delay between the last composited image's presentation
|
||||
* timestamp and when it was first composited. It's possible for the delay
|
||||
|
@ -639,6 +646,9 @@ class ImageContainer final : public SupportsWeakPtr {
|
|||
#ifdef XP_WIN
|
||||
RefPtr<D3D11YCbCrRecycleAllocator> mD3D11YCbCrRecycleAllocator;
|
||||
#endif
|
||||
#ifdef XP_MACOSX
|
||||
RefPtr<MacIOSurfaceRecycleAllocator> mMacIOSurfaceRecycleAllocator;
|
||||
#endif
|
||||
|
||||
nsTArray<OwningImage> mCurrentImages;
|
||||
|
||||
|
|
|
@ -10,7 +10,9 @@
|
|||
#include "mozilla/layers/CompositableClient.h"
|
||||
#include "mozilla/layers/CompositableForwarder.h"
|
||||
#include "mozilla/layers/MacIOSurfaceTextureClientOGL.h"
|
||||
#include "mozilla/StaticPrefs_layers.h"
|
||||
#include "mozilla/UniquePtr.h"
|
||||
#include "YCbCrUtils.h"
|
||||
|
||||
using namespace mozilla;
|
||||
using namespace mozilla::layers;
|
||||
|
@ -30,3 +32,105 @@ TextureClient* MacIOSurfaceImage::GetTextureClient(
|
|||
already_AddRefed<SourceSurface> MacIOSurfaceImage::GetAsSourceSurface() {
|
||||
return CreateSourceSurfaceFromMacIOSurface(mSurface);
|
||||
}
|
||||
|
||||
bool MacIOSurfaceImage::SetData(ImageContainer* aContainer,
|
||||
const PlanarYCbCrData& aData) {
|
||||
MOZ_ASSERT(!mSurface);
|
||||
|
||||
// The RDD sandbox won't allow us to create an IOSurface.
|
||||
if (XRE_IsRDDProcess()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (aData.mYSkip != 0 || aData.mCbSkip != 0 || aData.mCrSkip != 0 ||
|
||||
!(aData.mYUVColorSpace == YUVColorSpace::BT601 ||
|
||||
aData.mYUVColorSpace == YUVColorSpace::BT709) ||
|
||||
!(aData.mColorRange == ColorRange::FULL ||
|
||||
aData.mColorRange == ColorRange::LIMITED) ||
|
||||
aData.mColorDepth != ColorDepth::COLOR_8) {
|
||||
return false;
|
||||
}
|
||||
|
||||
RefPtr<MacIOSurfaceRecycleAllocator> allocator =
|
||||
aContainer->GetMacIOSurfaceRecycleAllocator();
|
||||
|
||||
RefPtr<MacIOSurface> surf = allocator->Allocate(
|
||||
aData.mYSize, aData.mCbCrSize, aData.mYUVColorSpace, aData.mColorRange);
|
||||
|
||||
surf->Lock(false);
|
||||
|
||||
MOZ_ASSERT(aData.mYSize.height > 0);
|
||||
uint8_t* dst = (uint8_t*)surf->GetBaseAddressOfPlane(0);
|
||||
size_t stride = surf->GetBytesPerRow(0);
|
||||
for (size_t i = 0; i < (size_t)aData.mYSize.height; i++) {
|
||||
uint8_t* rowSrc = aData.mYChannel + aData.mYStride * i;
|
||||
uint8_t* rowDst = dst + stride * i;
|
||||
memcpy(rowDst, rowSrc, aData.mYSize.width);
|
||||
}
|
||||
|
||||
// CoreAnimation doesn't appear to support planar YCbCr formats, so we
|
||||
// allocated an NV12 surface and now we need to copy and interleave the Cb and
|
||||
// Cr channels.
|
||||
MOZ_ASSERT(aData.mCbCrSize.height > 0);
|
||||
dst = (uint8_t*)surf->GetBaseAddressOfPlane(1);
|
||||
stride = surf->GetBytesPerRow(1);
|
||||
for (size_t i = 0; i < (size_t)aData.mCbCrSize.height; i++) {
|
||||
uint8_t* rowCbSrc = aData.mCbChannel + aData.mCbCrStride * i;
|
||||
uint8_t* rowCrSrc = aData.mCrChannel + aData.mCbCrStride * i;
|
||||
uint8_t* rowDst = dst + stride * i;
|
||||
|
||||
for (size_t j = 0; j < (size_t)aData.mCbCrSize.width; j++) {
|
||||
*rowDst = *rowCbSrc;
|
||||
rowDst++;
|
||||
rowCbSrc++;
|
||||
*rowDst = *rowCrSrc;
|
||||
rowDst++;
|
||||
rowCrSrc++;
|
||||
}
|
||||
}
|
||||
|
||||
surf->Unlock(false);
|
||||
mSurface = surf;
|
||||
mPictureRect = aData.GetPictureRect();
|
||||
return true;
|
||||
}
|
||||
|
||||
already_AddRefed<MacIOSurface> MacIOSurfaceRecycleAllocator::Allocate(
|
||||
const gfx::IntSize aYSize, const gfx::IntSize& aCbCrSize,
|
||||
gfx::YUVColorSpace aYUVColorSpace, gfx::ColorRange aColorRange) {
|
||||
nsTArray<CFTypeRefPtr<IOSurfaceRef>> surfaces = std::move(mSurfaces);
|
||||
RefPtr<MacIOSurface> result;
|
||||
for (auto& surf : surfaces) {
|
||||
MOZ_ASSERT(::IOSurfaceGetPlaneCount(surf.get()) == 2);
|
||||
|
||||
// If the surface size has changed, then discard any surfaces of the old
|
||||
// size.
|
||||
if (::IOSurfaceGetWidthOfPlane(surf.get(), 0) != (size_t)aYSize.width ||
|
||||
::IOSurfaceGetHeightOfPlane(surf.get(), 0) != (size_t)aYSize.height ||
|
||||
::IOSurfaceGetWidthOfPlane(surf.get(), 1) != (size_t)aCbCrSize.width ||
|
||||
::IOSurfaceGetHeightOfPlane(surf.get(), 1) !=
|
||||
(size_t)aCbCrSize.height) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// Only construct a MacIOSurface object when we find one that isn't
|
||||
// in-use, since the constructor adds a usage ref.
|
||||
if (!result && !::IOSurfaceIsInUse(surf.get())) {
|
||||
result = new MacIOSurface(surf, 1.0, false, aYUVColorSpace);
|
||||
}
|
||||
|
||||
mSurfaces.AppendElement(surf);
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
result = MacIOSurface::CreateNV12Surface(aYSize, aCbCrSize, aYUVColorSpace,
|
||||
aColorRange);
|
||||
|
||||
if (mSurfaces.Length() <
|
||||
StaticPrefs::layers_iosurfaceimage_recycle_limit()) {
|
||||
mSurfaces.AppendElement(result->GetIOSurfaceRef());
|
||||
}
|
||||
}
|
||||
|
||||
return result.forget();
|
||||
}
|
||||
|
|
|
@ -19,7 +19,13 @@ namespace layers {
|
|||
class MacIOSurfaceImage : public Image {
|
||||
public:
|
||||
explicit MacIOSurfaceImage(MacIOSurface* aSurface)
|
||||
: Image(nullptr, ImageFormat::MAC_IOSURFACE), mSurface(aSurface) {}
|
||||
: Image(nullptr, ImageFormat::MAC_IOSURFACE), mSurface(aSurface) {
|
||||
if (aSurface) {
|
||||
mPictureRect = gfx::IntRect(gfx::IntPoint{}, aSurface->GetSize(0));
|
||||
}
|
||||
}
|
||||
|
||||
bool SetData(ImageContainer* aContainer, const PlanarYCbCrData& aData);
|
||||
|
||||
MacIOSurface* GetSurface() { return mSurface; }
|
||||
|
||||
|
@ -34,9 +40,27 @@ class MacIOSurfaceImage : public Image {
|
|||
|
||||
MacIOSurfaceImage* AsMacIOSurfaceImage() override { return this; }
|
||||
|
||||
gfx::IntRect GetPictureRect() const override { return mPictureRect; }
|
||||
|
||||
private:
|
||||
RefPtr<MacIOSurface> mSurface;
|
||||
RefPtr<TextureClient> mTextureClient;
|
||||
gfx::IntRect mPictureRect;
|
||||
};
|
||||
|
||||
class MacIOSurfaceRecycleAllocator {
|
||||
public:
|
||||
NS_INLINE_DECL_THREADSAFE_REFCOUNTING(MacIOSurfaceRecycleAllocator)
|
||||
|
||||
already_AddRefed<MacIOSurface> Allocate(const gfx::IntSize aYSize,
|
||||
const gfx::IntSize& aCbCrSize,
|
||||
gfx::YUVColorSpace aYUVColorSpace,
|
||||
gfx::ColorRange aColorRange);
|
||||
|
||||
private:
|
||||
~MacIOSurfaceRecycleAllocator() = default;
|
||||
|
||||
nsTArray<CFTypeRefPtr<IOSurfaceRef>> mSurfaces;
|
||||
};
|
||||
|
||||
} // namespace layers
|
||||
|
|
|
@ -5550,6 +5550,11 @@
|
|||
value: true
|
||||
mirror: once
|
||||
|
||||
- name: layers.iosurfaceimage.recycle-limit
|
||||
type: RelaxedAtomicUint32
|
||||
value: 15
|
||||
mirror: always
|
||||
|
||||
#---------------------------------------------------------------------------
|
||||
# Prefs starting with "layout."
|
||||
#---------------------------------------------------------------------------
|
||||
|
|
Загрузка…
Ссылка в новой задаче