Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/dom/media/ImageToI420.cpp
Line
Count
Source (jump to first uncovered line)
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/. */
5
6
#include "ImageToI420.h"
7
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 "nsThreadUtils.h"
15
16
using mozilla::ImageFormat;
17
using mozilla::dom::ImageBitmapFormat;
18
using mozilla::dom::ImageUtils;
19
using mozilla::gfx::DataSourceSurface;
20
using mozilla::gfx::SourceSurface;
21
using mozilla::gfx::SurfaceFormat;
22
using mozilla::layers::Image;
23
using mozilla::layers::PlanarYCbCrData;
24
using mozilla::layers::PlanarYCbCrImage;
25
26
static const PlanarYCbCrData* GetPlanarYCbCrData(Image* aImage)
27
{
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;
35
  }
36
}
37
38
static already_AddRefed<SourceSurface> GetSourceSurface(Image* aImage)
39
0
{
40
0
  if (!aImage->AsGLImage() || NS_IsMainThread()) {
41
0
    return aImage->GetAsSourceSurface();
42
0
  }
43
0
44
0
  // GLImage::GetAsSourceSurface() only supports main thread
45
0
  RefPtr<SourceSurface> surf;
46
0
  NS_DispatchToMainThread(
47
0
    NS_NewRunnableFunction(
48
0
      "ImageToI420::GLImage::GetSourceSurface",
49
0
      [&aImage, &surf]() { surf = aImage->GetAsSourceSurface(); }),
50
0
    NS_DISPATCH_SYNC);
51
0
52
0
  return surf.forget();
53
0
}
54
55
static nsresult MapRv(int aRv)
56
{
57
  // Docs for libyuv::ConvertToI420 say:
58
  // Returns 0 for successful; -1 for invalid parameter. Non-zero for failure.
59
  switch(aRv) {
60
    case 0:
61
      return NS_OK;
62
    case -1:
63
      return NS_ERROR_INVALID_ARG;
64
    default:
65
      return NS_ERROR_FAILURE;
66
  }
67
}
68
69
namespace mozilla {
70
71
nsresult ConvertToI420(
72
  Image* aImage,
73
  uint8_t* aDestY,
74
  int aDestStrideY,
75
  uint8_t* aDestU,
76
  int aDestStrideU,
77
  uint8_t* aDestV,
78
  int aDestStrideV)
79
0
{
80
0
  if (!aImage->IsValid()) {
81
0
    return NS_ERROR_INVALID_ARG;
82
0
  }
83
0
84
0
  if (const PlanarYCbCrData* data = GetPlanarYCbCrData(aImage)) {
85
0
    const ImageUtils imageUtils(aImage);
86
0
    switch(imageUtils.GetFormat()) {
87
0
      case ImageBitmapFormat::YUV420P:
88
0
        return MapRv(libyuv::I420ToI420(
89
0
          data->mYChannel,
90
0
          data->mYStride,
91
0
          data->mCbChannel,
92
0
          data->mCbCrStride,
93
0
          data->mCrChannel,
94
0
          data->mCbCrStride,
95
0
          aDestY,
96
0
          aDestStrideY,
97
0
          aDestU,
98
0
          aDestStrideU,
99
0
          aDestV,
100
0
          aDestStrideV,
101
0
          aImage->GetSize().width,
102
0
          aImage->GetSize().height));
103
0
      case ImageBitmapFormat::YUV422P:
104
0
        return MapRv(libyuv::I422ToI420(
105
0
          data->mYChannel,
106
0
          data->mYStride,
107
0
          data->mCbChannel,
108
0
          data->mCbCrStride,
109
0
          data->mCrChannel,
110
0
          data->mCbCrStride,
111
0
          aDestY,
112
0
          aDestStrideY,
113
0
          aDestU,
114
0
          aDestStrideU,
115
0
          aDestV,
116
0
          aDestStrideV,
117
0
          aImage->GetSize().width,
118
0
          aImage->GetSize().height));
119
0
      case ImageBitmapFormat::YUV444P:
120
0
        return MapRv(libyuv::I444ToI420(
121
0
          data->mYChannel,
122
0
          data->mYStride,
123
0
          data->mCbChannel,
124
0
          data->mCbCrStride,
125
0
          data->mCrChannel,
126
0
          data->mCbCrStride,
127
0
          aDestY,
128
0
          aDestStrideY,
129
0
          aDestU,
130
0
          aDestStrideU,
131
0
          aDestV,
132
0
          aDestStrideV,
133
0
          aImage->GetSize().width,
134
0
          aImage->GetSize().height));
135
0
      case ImageBitmapFormat::YUV420SP_NV12:
136
0
        return MapRv(libyuv::NV12ToI420(
137
0
          data->mYChannel,
138
0
          data->mYStride,
139
0
          data->mCbChannel,
140
0
          data->mCbCrStride,
141
0
          aDestY,
142
0
          aDestStrideY,
143
0
          aDestU,
144
0
          aDestStrideU,
145
0
          aDestV,
146
0
          aDestStrideV,
147
0
          aImage->GetSize().width,
148
0
          aImage->GetSize().height));
149
0
      case ImageBitmapFormat::YUV420SP_NV21:
150
0
        return MapRv(libyuv::NV21ToI420(
151
0
          data->mYChannel,
152
0
          data->mYStride,
153
0
          data->mCrChannel,
154
0
          data->mCbCrStride,
155
0
          aDestY,
156
0
          aDestStrideY,
157
0
          aDestU,
158
0
          aDestStrideU,
159
0
          aDestV,
160
0
          aDestStrideV,
161
0
          aImage->GetSize().width,
162
0
          aImage->GetSize().height));
163
0
      default:
164
0
        MOZ_ASSERT_UNREACHABLE("YUV format conversion not implemented");
165
0
        return NS_ERROR_NOT_IMPLEMENTED;
166
0
    }
167
0
  }
168
0
169
0
  RefPtr<SourceSurface> surf = GetSourceSurface(aImage);
170
0
  if (!surf) {
171
0
    return NS_ERROR_FAILURE;
172
0
  }
173
0
174
0
  RefPtr<DataSourceSurface> data = surf->GetDataSurface();
175
0
  if (!data) {
176
0
    return NS_ERROR_FAILURE;
177
0
  }
178
0
179
0
  DataSourceSurface::ScopedMap map(data, DataSourceSurface::READ);
180
0
  if (!map.IsMapped()) {
181
0
    return NS_ERROR_FAILURE;
182
0
  }
183
0
184
0
  switch (surf->GetFormat()) {
185
0
    case SurfaceFormat::B8G8R8A8:
186
0
    case SurfaceFormat::B8G8R8X8:
187
0
      return MapRv(libyuv::ARGBToI420(
188
0
        static_cast<uint8_t*>(map.GetData()),
189
0
        map.GetStride(),
190
0
        aDestY,
191
0
        aDestStrideY,
192
0
        aDestU,
193
0
        aDestStrideU,
194
0
        aDestV,
195
0
        aDestStrideV,
196
0
        aImage->GetSize().width,
197
0
        aImage->GetSize().height));
198
0
    case SurfaceFormat::R5G6B5_UINT16:
199
0
      return MapRv(libyuv::RGB565ToI420(
200
0
        static_cast<uint8_t*>(map.GetData()),
201
0
        map.GetStride(),
202
0
        aDestY,
203
0
        aDestStrideY,
204
0
        aDestU,
205
0
        aDestStrideU,
206
0
        aDestV,
207
0
        aDestStrideV,
208
0
        aImage->GetSize().width,
209
0
        aImage->GetSize().height));
210
0
    default:
211
0
      MOZ_ASSERT_UNREACHABLE("Surface format conversion not implemented");
212
0
      return NS_ERROR_NOT_IMPLEMENTED;
213
0
  }
214
0
}
215
216
} // namespace mozilla
217