Coverage Report

Created: 2018-09-25 14:53

/src/mozilla-central/gfx/ycbcr/YCbCrUtils.cpp
Line
Count
Source (jump to first uncovered line)
1
/* -*- Mode: C++; tab-width: 20; indent-tabs-mode: nil; c-basic-offset: 4 -*-
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
4
 * file, You can obtain one at http://mozilla.org/MPL/2.0/. */
5
6
#include "gfx2DGlue.h"
7
8
#include "YCbCrUtils.h"
9
#include "yuv_convert.h"
10
#include "ycbcr_to_rgb565.h"
11
12
namespace mozilla {
13
namespace gfx {
14
15
void
16
GetYCbCrToRGBDestFormatAndSize(const layers::PlanarYCbCrData& aData,
17
                               SurfaceFormat& aSuggestedFormat,
18
                               IntSize& aSuggestedSize)
19
0
{
20
0
  YUVType yuvtype =
21
0
    TypeFromSize(aData.mYSize.width,
22
0
                 aData.mYSize.height,
23
0
                 aData.mCbCrSize.width,
24
0
                 aData.mCbCrSize.height);
25
0
26
0
  // 'prescale' is true if the scaling is to be done as part of the
27
0
  // YCbCr to RGB conversion rather than on the RGB data when rendered.
28
0
  bool prescale = aSuggestedSize.width > 0 && aSuggestedSize.height > 0 &&
29
0
                  aSuggestedSize != aData.mPicSize;
30
0
31
0
  if (aSuggestedFormat == SurfaceFormat::R5G6B5_UINT16) {
32
#if defined(HAVE_YCBCR_TO_RGB565)
33
    if (prescale &&
34
        !IsScaleYCbCrToRGB565Fast(aData.mPicX,
35
                                  aData.mPicY,
36
                                  aData.mPicSize.width,
37
                                  aData.mPicSize.height,
38
                                  aSuggestedSize.width,
39
                                  aSuggestedSize.height,
40
                                  yuvtype,
41
                                  FILTER_BILINEAR) &&
42
        IsConvertYCbCrToRGB565Fast(aData.mPicX,
43
                                   aData.mPicY,
44
                                   aData.mPicSize.width,
45
                                   aData.mPicSize.height,
46
                                   yuvtype)) {
47
      prescale = false;
48
    }
49
#else
50
    // yuv2rgb16 function not available
51
0
    aSuggestedFormat = SurfaceFormat::B8G8R8X8;
52
0
#endif
53
0
  }
54
0
  else if (aSuggestedFormat != SurfaceFormat::B8G8R8X8) {
55
0
    // No other formats are currently supported.
56
0
    aSuggestedFormat = SurfaceFormat::B8G8R8X8;
57
0
  }
58
0
  if (aSuggestedFormat == SurfaceFormat::B8G8R8X8) {
59
0
    /* ScaleYCbCrToRGB32 does not support a picture offset, nor 4:4:4 data.
60
0
     See bugs 639415 and 640073. */
61
0
    if (aData.mPicX != 0 || aData.mPicY != 0 || yuvtype == YV24)
62
0
      prescale = false;
63
0
  }
64
0
  if (!prescale) {
65
0
    aSuggestedSize = aData.mPicSize;
66
0
  }
67
0
}
68
69
static inline void
70
ConvertYCbCr16to8Line(uint8_t* aDst,
71
                      int aStride,
72
                      const uint16_t* aSrc,
73
                      int aStride16,
74
                      int aWidth,
75
                      int aHeight,
76
                      int aBitDepth)
77
0
{
78
0
  uint16_t mask = (1 << aBitDepth) - 1;
79
0
80
0
  for (int i = 0; i < aHeight; i++) {
81
0
    for (int j = 0; j < aWidth; j++) {
82
0
      uint16_t val = (aSrc[j] & mask) >> (aBitDepth - 8);
83
0
      aDst[j] = val;
84
0
    }
85
0
    aDst += aStride;
86
0
    aSrc += aStride16;
87
0
  }
88
0
}
89
90
void
91
ConvertYCbCrToRGB(const layers::PlanarYCbCrData& aData,
92
                  const SurfaceFormat& aDestFormat,
93
                  const IntSize& aDestSize,
94
                  unsigned char* aDestBuffer,
95
                  int32_t aStride)
96
0
{
97
0
  // ConvertYCbCrToRGB et al. assume the chroma planes are rounded up if the
98
0
  // luma plane is odd sized.
99
0
  MOZ_ASSERT((aData.mCbCrSize.width == aData.mYSize.width ||
100
0
              aData.mCbCrSize.width == (aData.mYSize.width + 1) >> 1) &&
101
0
             (aData.mCbCrSize.height == aData.mYSize.height ||
102
0
              aData.mCbCrSize.height == (aData.mYSize.height + 1) >> 1));
103
0
104
0
  // Used if converting to 8 bits YUV.
105
0
  UniquePtr<uint8_t[]> yChannel;
106
0
  UniquePtr<uint8_t[]> cbChannel;
107
0
  UniquePtr<uint8_t[]> crChannel;
108
0
  layers::PlanarYCbCrData dstData;
109
0
  const layers::PlanarYCbCrData& srcData = aData.mBitDepth == 8 ? aData : dstData;
110
0
111
0
  if (aData.mBitDepth != 8) {
112
0
    MOZ_ASSERT(aData.mBitDepth > 8 && aData.mBitDepth <= 16);
113
0
    // Convert to 8 bits data first.
114
0
    dstData.mPicSize = aData.mPicSize;
115
0
    dstData.mPicX = aData.mPicX;
116
0
    dstData.mPicY = aData.mPicY;
117
0
    dstData.mYSize = aData.mYSize;
118
0
    // We align the destination stride to 32 bytes, so that libyuv can use
119
0
    // SSE optimised code.
120
0
    dstData.mYStride = (aData.mYSize.width + 31) & ~31;
121
0
    dstData.mCbCrSize = aData.mCbCrSize;
122
0
    dstData.mCbCrStride = (aData.mCbCrSize.width + 31) & ~31;
123
0
    dstData.mYUVColorSpace = aData.mYUVColorSpace;
124
0
    dstData.mBitDepth = 8;
125
0
126
0
    size_t ySize = GetAlignedStride<1>(dstData.mYStride, aData.mYSize.height);
127
0
    size_t cbcrSize =
128
0
      GetAlignedStride<1>(dstData.mCbCrStride, aData.mCbCrSize.height);
129
0
    if (ySize == 0 || cbcrSize == 0) {
130
0
      return;
131
0
    }
132
0
    yChannel = MakeUnique<uint8_t[]>(ySize);
133
0
    cbChannel = MakeUnique<uint8_t[]>(cbcrSize);
134
0
    crChannel = MakeUnique<uint8_t[]>(cbcrSize);
135
0
136
0
    dstData.mYChannel = yChannel.get();
137
0
    dstData.mCbChannel = cbChannel.get();
138
0
    dstData.mCrChannel = crChannel.get();
139
0
140
0
    ConvertYCbCr16to8Line(dstData.mYChannel,
141
0
                          dstData.mYStride,
142
0
                          reinterpret_cast<uint16_t*>(aData.mYChannel),
143
0
                          aData.mYStride / 2,
144
0
                          aData.mYSize.width,
145
0
                          aData.mYSize.height,
146
0
                          aData.mBitDepth);
147
0
148
0
    ConvertYCbCr16to8Line(dstData.mCbChannel,
149
0
                          dstData.mCbCrStride,
150
0
                          reinterpret_cast<uint16_t*>(aData.mCbChannel),
151
0
                          aData.mCbCrStride / 2,
152
0
                          aData.mCbCrSize.width,
153
0
                          aData.mCbCrSize.height,
154
0
                          aData.mBitDepth);
155
0
156
0
    ConvertYCbCr16to8Line(dstData.mCrChannel,
157
0
                          dstData.mCbCrStride,
158
0
                          reinterpret_cast<uint16_t*>(aData.mCrChannel),
159
0
                          aData.mCbCrStride / 2,
160
0
                          aData.mCbCrSize.width,
161
0
                          aData.mCbCrSize.height,
162
0
                          aData.mBitDepth);
163
0
  }
164
0
165
0
  YUVType yuvtype =
166
0
    TypeFromSize(srcData.mYSize.width,
167
0
                 srcData.mYSize.height,
168
0
                 srcData.mCbCrSize.width,
169
0
                 srcData.mCbCrSize.height);
170
0
171
0
  // Convert from YCbCr to RGB now, scaling the image if needed.
172
0
  if (aDestSize != srcData.mPicSize) {
173
#if defined(HAVE_YCBCR_TO_RGB565)
174
    if (aDestFormat == SurfaceFormat::R5G6B5_UINT16) {
175
      ScaleYCbCrToRGB565(srcData.mYChannel,
176
                         srcData.mCbChannel,
177
                         srcData.mCrChannel,
178
                         aDestBuffer,
179
                         srcData.mPicX,
180
                         srcData.mPicY,
181
                         srcData.mPicSize.width,
182
                         srcData.mPicSize.height,
183
                         aDestSize.width,
184
                         aDestSize.height,
185
                         srcData.mYStride,
186
                         srcData.mCbCrStride,
187
                         aStride,
188
                         yuvtype,
189
                         FILTER_BILINEAR);
190
    } else
191
#endif
192
      ScaleYCbCrToRGB32(srcData.mYChannel, //
193
0
                        srcData.mCbChannel,
194
0
                        srcData.mCrChannel,
195
0
                        aDestBuffer,
196
0
                        srcData.mPicSize.width,
197
0
                        srcData.mPicSize.height,
198
0
                        aDestSize.width,
199
0
                        aDestSize.height,
200
0
                        srcData.mYStride,
201
0
                        srcData.mCbCrStride,
202
0
                        aStride,
203
0
                        yuvtype,
204
0
                        srcData.mYUVColorSpace,
205
0
                        FILTER_BILINEAR);
206
0
  } else { // no prescale
207
#if defined(HAVE_YCBCR_TO_RGB565)
208
    if (aDestFormat == SurfaceFormat::R5G6B5_UINT16) {
209
      ConvertYCbCrToRGB565(srcData.mYChannel,
210
                           srcData.mCbChannel,
211
                           srcData.mCrChannel,
212
                           aDestBuffer,
213
                           srcData.mPicX,
214
                           srcData.mPicY,
215
                           srcData.mPicSize.width,
216
                           srcData.mPicSize.height,
217
                           srcData.mYStride,
218
                           srcData.mCbCrStride,
219
                           aStride,
220
                           yuvtype);
221
    } else // aDestFormat != SurfaceFormat::R5G6B5_UINT16
222
#endif
223
      ConvertYCbCrToRGB32(srcData.mYChannel, //
224
0
                          srcData.mCbChannel,
225
0
                          srcData.mCrChannel,
226
0
                          aDestBuffer,
227
0
                          srcData.mPicX,
228
0
                          srcData.mPicY,
229
0
                          srcData.mPicSize.width,
230
0
                          srcData.mPicSize.height,
231
0
                          srcData.mYStride,
232
0
                          srcData.mCbCrStride,
233
0
                          aStride,
234
0
                          yuvtype,
235
0
                          srcData.mYUVColorSpace);
236
0
  }
237
0
}
238
239
void
240
ConvertYCbCrAToARGB(const uint8_t* aSrcY,
241
                    const uint8_t* aSrcU,
242
                    const uint8_t* aSrcV,
243
                    const uint8_t* aSrcA,
244
                    int aSrcStrideYA, int aSrcStrideUV,
245
                    uint8_t* aDstARGB, int aDstStrideARGB,
246
0
                    int aWidth, int aHeight) {
247
0
248
0
  ConvertYCbCrAToARGB32(aSrcY,
249
0
                        aSrcU,
250
0
                        aSrcV,
251
0
                        aSrcA,
252
0
                        aDstARGB,
253
0
                        aWidth,
254
0
                        aHeight,
255
0
                        aSrcStrideYA,
256
0
                        aSrcStrideUV,
257
0
                        aDstStrideARGB);
258
0
}
259
260
} // namespace gfx
261
} // namespace mozilla