Bug 1885602 - Part 5: Implement navigating to the SUMO help topic from the menu heade...
[gecko.git] / dom / media / ImageToI420.cpp
blob0f7976cb631104a5c1c09908da48ec1ddb02641d
1 /* -*- Mode: C++; tab-width: 2; indent-tabs-mode: nil; c-basic-offset: 2 -*-*/
2 /* This Source Code Form is subject to the terms of the Mozilla Public
3 * License, v. 2.0. If a copy of the MPL was not distributed with this file,
4 * You can obtain one at http://mozilla.org/MPL/2.0/. */
6 #include "ImageToI420.h"
8 #include "ImageContainer.h"
9 #include "libyuv/convert.h"
10 #include "mozilla/dom/ImageBitmapBinding.h"
11 #include "mozilla/dom/ImageUtils.h"
12 #include "mozilla/gfx/Point.h"
13 #include "mozilla/RefPtr.h"
14 #include "mozilla/Result.h"
15 #include "nsThreadUtils.h"
17 using mozilla::ImageFormat;
18 using mozilla::dom::ImageBitmapFormat;
19 using mozilla::dom::ImageUtils;
20 using mozilla::gfx::DataSourceSurface;
21 using mozilla::gfx::SourceSurface;
22 using mozilla::gfx::SurfaceFormat;
23 using mozilla::layers::Image;
24 using mozilla::layers::PlanarYCbCrData;
25 using mozilla::layers::PlanarYCbCrImage;
27 static const PlanarYCbCrData* GetPlanarYCbCrData(Image* aImage) {
28 switch (aImage->GetFormat()) {
29 case ImageFormat::PLANAR_YCBCR:
30 return aImage->AsPlanarYCbCrImage()->GetData();
31 case ImageFormat::NV_IMAGE:
32 return aImage->AsNVImage()->GetData();
33 default:
34 return nullptr;
38 static already_AddRefed<SourceSurface> GetSourceSurface(Image* aImage) {
39 if (!aImage->AsGLImage() || NS_IsMainThread()) {
40 return aImage->GetAsSourceSurface();
43 // GLImage::GetAsSourceSurface() only supports main thread
44 RefPtr<SourceSurface> surf;
45 NS_DispatchAndSpinEventLoopUntilComplete(
46 "ImageToI420::GLImage::GetSourceSurface"_ns,
47 mozilla::GetMainThreadSerialEventTarget(),
48 NS_NewRunnableFunction(
49 "ImageToI420::GLImage::GetSourceSurface",
50 [&aImage, &surf]() { surf = aImage->GetAsSourceSurface(); }));
52 return surf.forget();
55 static nsresult MapRv(int aRv) {
56 // Docs for libyuv::ConvertToI420 say:
57 // Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
58 switch (aRv) {
59 case 0:
60 return NS_OK;
61 case -1:
62 return NS_ERROR_INVALID_ARG;
63 default:
64 return NS_ERROR_FAILURE;
68 namespace mozilla {
70 nsresult ConvertToI420(Image* aImage, uint8_t* aDestY, int aDestStrideY,
71 uint8_t* aDestU, int aDestStrideU, uint8_t* aDestV,
72 int aDestStrideV) {
73 if (!aImage->IsValid()) {
74 return NS_ERROR_INVALID_ARG;
77 if (const PlanarYCbCrData* data = GetPlanarYCbCrData(aImage)) {
78 const ImageUtils imageUtils(aImage);
79 Maybe<dom::ImageBitmapFormat> format = imageUtils.GetFormat();
80 if (format.isNothing()) {
81 MOZ_ASSERT_UNREACHABLE("YUV format conversion not implemented");
82 return NS_ERROR_NOT_IMPLEMENTED;
84 switch (format.value()) {
85 case ImageBitmapFormat::YUV420P:
86 return MapRv(libyuv::I420ToI420(
87 data->mYChannel, data->mYStride, data->mCbChannel,
88 data->mCbCrStride, data->mCrChannel, data->mCbCrStride, aDestY,
89 aDestStrideY, aDestU, aDestStrideU, aDestV, aDestStrideV,
90 aImage->GetSize().width, aImage->GetSize().height));
91 case ImageBitmapFormat::YUV422P:
92 return MapRv(libyuv::I422ToI420(
93 data->mYChannel, data->mYStride, data->mCbChannel,
94 data->mCbCrStride, data->mCrChannel, data->mCbCrStride, aDestY,
95 aDestStrideY, aDestU, aDestStrideU, aDestV, aDestStrideV,
96 aImage->GetSize().width, aImage->GetSize().height));
97 case ImageBitmapFormat::YUV444P:
98 return MapRv(libyuv::I444ToI420(
99 data->mYChannel, data->mYStride, data->mCbChannel,
100 data->mCbCrStride, data->mCrChannel, data->mCbCrStride, aDestY,
101 aDestStrideY, aDestU, aDestStrideU, aDestV, aDestStrideV,
102 aImage->GetSize().width, aImage->GetSize().height));
103 case ImageBitmapFormat::YUV420SP_NV12:
104 return MapRv(libyuv::NV12ToI420(
105 data->mYChannel, data->mYStride, data->mCbChannel,
106 data->mCbCrStride, aDestY, aDestStrideY, aDestU, aDestStrideU,
107 aDestV, aDestStrideV, aImage->GetSize().width,
108 aImage->GetSize().height));
109 case ImageBitmapFormat::YUV420SP_NV21:
110 return MapRv(libyuv::NV21ToI420(
111 data->mYChannel, data->mYStride, data->mCrChannel,
112 data->mCbCrStride, aDestY, aDestStrideY, aDestU, aDestStrideU,
113 aDestV, aDestStrideV, aImage->GetSize().width,
114 aImage->GetSize().height));
115 default:
116 MOZ_ASSERT_UNREACHABLE("YUV format conversion not implemented");
117 return NS_ERROR_NOT_IMPLEMENTED;
121 RefPtr<SourceSurface> surf = GetSourceSurface(aImage);
122 if (!surf) {
123 return NS_ERROR_FAILURE;
126 RefPtr<DataSourceSurface> data = surf->GetDataSurface();
127 if (!data) {
128 return NS_ERROR_FAILURE;
131 DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
132 if (!map.IsMapped()) {
133 return NS_ERROR_FAILURE;
136 switch (surf->GetFormat()) {
137 case SurfaceFormat::B8G8R8A8:
138 case SurfaceFormat::B8G8R8X8:
139 return MapRv(libyuv::ARGBToI420(
140 static_cast<uint8_t*>(map.GetData()), map.GetStride(), aDestY,
141 aDestStrideY, aDestU, aDestStrideU, aDestV, aDestStrideV,
142 aImage->GetSize().width, aImage->GetSize().height));
143 case SurfaceFormat::R5G6B5_UINT16:
144 return MapRv(libyuv::RGB565ToI420(
145 static_cast<uint8_t*>(map.GetData()), map.GetStride(), aDestY,
146 aDestStrideY, aDestU, aDestStrideU, aDestV, aDestStrideV,
147 aImage->GetSize().width, aImage->GetSize().height));
148 default:
149 MOZ_ASSERT_UNREACHABLE("Surface format conversion not implemented");
150 return NS_ERROR_NOT_IMPLEMENTED;
154 } // namespace mozilla