Coverage Report

Created: 2025-12-20 06:29

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libraw/src/decoders/sonycc.cpp
Line
Count
Source
1
/* -*- C++ -*-
2
 * File: sonycc.cpp
3
 * Copyright (C) 2024-2025 Alex Tutubalin, LibRaw LLC
4
 *
5
   Sony YCC (small/medium lossy compressed) decoder
6
7
   Code partially backported from DNGLab's rust code
8
   DNGLab was originally created in 2021 by Daniel Vogelbacher.
9
10
LibRaw is free software; you can redistribute it and/or modify
11
it under the terms of the one of two licenses as you choose:
12
13
1. GNU LESSER GENERAL PUBLIC LICENSE version 2.1
14
   (See file LICENSE.LGPL provided in LibRaw distribution archive for details).
15
16
2. COMMON DEVELOPMENT AND DISTRIBUTION LICENSE (CDDL) Version 1.0
17
   (See file LICENSE.CDDL provided in LibRaw distribution archive for details).
18
19
 */
20
21
#include "../../internal/libraw_cxx_defs.h"
22
#include "../../internal/losslessjpeg.h"
23
#include <vector>
24
#include <algorithm>
25
26
16
#define ifp libraw_internal_data.internal_data.input
27
64
#define UD libraw_internal_data.unpacker_data
28
28
#define S imgdata.sizes
29
30
struct LibRaw_SonyYCC_Decompressor : public LibRaw_LjpegDecompressor
31
{
32
2
  LibRaw_SonyYCC_Decompressor(uint8_t *b, unsigned s): LibRaw_LjpegDecompressor(b,s){}
33
  bool decode_sony(std::vector<uint16_t> &dest, int width, int height);
34
  bool decode_sony_ljpeg_420(std::vector<uint16_t> &dest, int width, int height);
35
36
};
37
38
static
39
#ifdef _MSC_VER
40
    __forceinline
41
#else
42
    inline
43
#endif
44
void copy_yuv_420(uint16_t *out, uint32_t row, uint32_t col, uint32_t width,
45
  int32_t y1, int32_t y2, int32_t y3, int32_t y4, int32_t cb, int32_t cr)
46
0
{
47
0
  uint32_t pix1 = row * width + col;
48
0
  uint32_t pix2 = pix1 + 3;
49
0
  uint32_t pix3 = (row + 1) * width + col;
50
0
  uint32_t pix4 = pix3 + 3;
51
52
0
  out[pix1 + 0] = uint16_t(y1);
53
0
  out[pix1 + 1] = uint16_t(cb);
54
0
  out[pix1 + 2] = uint16_t(cr);
55
0
  out[pix2 + 0] = uint16_t(y2);
56
0
  out[pix2 + 1] = uint16_t(cb);
57
0
  out[pix2 + 2] = uint16_t(cr);
58
0
  out[pix3 + 0] = uint16_t(y3);
59
0
  out[pix3 + 1] = uint16_t(cb);
60
0
  out[pix3 + 2] = uint16_t(cr);
61
0
  out[pix4 + 0] = uint16_t(y4);
62
0
  out[pix4 + 1] = uint16_t(cb);
63
0
  out[pix4 + 2] = uint16_t(cr);
64
0
}
65
66
67
bool LibRaw_SonyYCC_Decompressor::decode_sony_ljpeg_420(std::vector<uint16_t> &_dest, int width, int height)
68
0
{
69
0
  if (sof.width * 3 != unsigned(width) || sof.height != unsigned(height))
70
0
    return false;
71
0
  if (width % 2 || width % 6 || height % 2)
72
0
    return false;
73
0
  if (_dest.size() < size_t(width*height))
74
0
    return false;
75
76
0
  HuffTable &huff1 = dhts[sof.components[0].dc_tbl];
77
0
  HuffTable &huff2 = dhts[sof.components[1].dc_tbl];
78
0
  HuffTable &huff3 = dhts[sof.components[2].dc_tbl];
79
80
0
  if (!huff1.initialized || !huff2.initialized || !huff3.initialized)
81
0
    return false;
82
83
0
  BitPumpJpeg pump(buffer);
84
85
0
  int32_t base = 1 << (sof.precision - point_transform - 1);
86
0
  int32_t y1 = base + huff1.decode(pump);
87
0
  int32_t y2 = y1 + huff1.decode(pump);
88
0
  int32_t y3 = y1 + huff1.decode(pump); 
89
0
  int32_t y4 = y3 + huff1.decode(pump);
90
91
0
  int32_t cb = base + huff2.decode(pump);
92
0
  int32_t cr = base + huff3.decode(pump);
93
94
0
  uint16_t *dest = _dest.data();
95
0
  copy_yuv_420(dest, 0, 0, width, y1, y2, y3, y4, cb, cr);
96
97
0
  for (int32_t row = 0; row < height; row += 2)
98
0
  {
99
0
    int32_t startcol = row == 0 ? 6 : 0;
100
0
    for (int32_t col = startcol; col < width; col += 6)
101
0
    {
102
0
      int32_t py1, py3, pcb, pcr;
103
0
      if (col == 0)
104
0
      {
105
0
        uint32_t pos = (row - 2) * width; 
106
0
        py1 = dest[pos];
107
0
        py3 = 0;
108
0
        pcb = dest[pos + 1];
109
0
        pcr = dest[pos + 2];
110
0
      }
111
0
      else
112
0
      {
113
0
        uint32_t pos1 = row * width + col - 3;       
114
0
        uint32_t pos3 = (row + 1) * width + col - 3; 
115
0
        py1 = dest[pos1];
116
0
        py3 = dest[pos3];
117
0
        pcb = dest[pos1 + 1];
118
0
        pcr = dest[pos1 + 2];
119
0
      };
120
0
      y1 = py1 + huff1.decode(pump);
121
0
      y2 = y1 + huff1.decode(pump);
122
0
      y3 = ((col == 0) ? y1 : py3) + huff1.decode(pump);
123
0
      y4 = y3 + huff1.decode(pump);
124
0
      cb = pcb + huff2.decode(pump);
125
0
      cr = pcr + huff3.decode(pump);
126
0
      copy_yuv_420(dest, row, col, width, y1, y2, y3, y4, cb, cr);
127
0
    }
128
0
  }
129
0
  return true;
130
0
}
131
132
bool LibRaw_SonyYCC_Decompressor::decode_sony(std::vector<uint16_t> &dest, int width, int height)
133
0
{
134
0
  if (sof.components[0].subsample_h == 2 && sof.components[0].subsample_v == 2)
135
0
  {
136
0
    return decode_sony_ljpeg_420(dest, width, height);
137
0
  }
138
0
  else if (sof.components[0].subsample_h == 2 && sof.components[0].subsample_v == 1)
139
0
    return decode_ljpeg_422(dest, width, height);
140
0
  else
141
0
    return false;
142
0
}
143
144
static
145
#ifdef _MSC_VER
146
    __forceinline
147
#else
148
    inline
149
#endif
150
void copy_ycc(ushort dst[][4], int rawwidth, int rawheight, int destrow0, int destcol0, ushort *src,
151
  int srcwidth, // full array width is 3x
152
  int srcheight, int steph, int stepv)
153
0
{
154
0
  if (steph < 2 && stepv < 2)
155
0
  {
156
0
    for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++)
157
0
    {
158
0
      ushort(*destrow)[4] = &dst[(destrow0 + tilerow) * rawwidth + destcol0];
159
0
      for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++)
160
0
      {
161
0
        int pix = (tilerow * srcwidth + tilecol) * 3;
162
0
        destrow[tilecol][0] = src[pix];
163
0
        destrow[tilecol][1] = src[pix + 1] > 8192 ? src[pix + 1] - 8192 : 0;
164
0
        destrow[tilecol][2] = src[pix + 2] > 8192 ? src[pix + 2] - 8192 : 0;
165
0
      }
166
0
    }
167
0
  }
168
0
  else
169
0
  {
170
0
      for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++)
171
0
      {
172
0
        int destrow = destrow0 + tilerow;
173
0
        ushort(*dest)[4] = &dst[destrow * rawwidth + destcol0];
174
0
        for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++)
175
0
        {
176
0
          int pix = (tilerow * srcwidth + tilecol) * 3;
177
0
      int destcol = destcol0 + tilecol;
178
0
          dest[tilecol][0] = src[pix];
179
0
      if((destrow%stepv) == 0 && (destcol%steph)==0)
180
0
      {
181
0
            dest[tilecol][1] = src[pix + 1] > 8192 ? src[pix + 1] - 8192 : 0;
182
0
            dest[tilecol][2] = src[pix + 2] > 8192 ? src[pix + 2] - 8192 : 0;
183
0
      }
184
0
        }
185
0
      }
186
187
0
  }
188
0
}
189
190
static
191
#ifdef _MSC_VER
192
    __forceinline
193
#else
194
    inline
195
#endif
196
uint16_t _lim16bit(float q)
197
0
{
198
0
  if (q < 0.f)
199
0
    q = 0.f;
200
0
  else if (q > 65535.f)
201
0
    q = 65535.f;
202
0
  return uint16_t(uint32_t(q));
203
0
}
204
205
static
206
#ifdef _MSC_VER
207
    __forceinline
208
#else
209
    inline
210
#endif
211
void ycc2rgb(uint16_t dst[][4], int rawwidth, int rawheight, int destrow0, int destcol0, ushort *src,
212
                     int srcwidth, // full array width is 3x
213
                     int srcheight)
214
0
{
215
0
  const ushort cdelta = 16383;
216
0
  for (int tilerow = 0; tilerow < srcheight && destrow0 + tilerow < rawheight; tilerow++)
217
0
  {
218
0
    ushort(*destrow)[4] = &dst[(destrow0 + tilerow) * rawwidth + destcol0];
219
0
    for (int tilecol = 0; tilecol < srcwidth && tilecol + destcol0 < rawwidth; tilecol++)
220
0
    {
221
0
      int pix = (tilerow * srcwidth + tilecol) * 3;
222
0
      float Y = float(src[pix]);
223
0
    float Cb = float(src[pix + 1] - cdelta);
224
0
      float Cr = float(src[pix + 2] - cdelta);
225
0
    float R = Y + 1.40200f * Cr;
226
0
    float G = Y - 0.34414f * Cb - 0.71414f * Cr;
227
0
    float B = Y + 1.77200f * Cb;
228
0
    destrow[tilecol][0] = _lim16bit(R);
229
0
    destrow[tilecol][1] = _lim16bit(G);
230
0
    destrow[tilecol][2] = _lim16bit(B);
231
0
    }
232
0
  }
233
0
}
234
235
void LibRaw::sony_ycbcr_load_raw()
236
10
{
237
10
  if (!imgdata.image)
238
1
    throw LIBRAW_EXCEPTION_IO_CORRUPT;
239
  // Sony YCC RAWs are always tiled
240
9
  if (UD.tile_width < 1 || UD.tile_width > S.raw_width)
241
2
    throw LIBRAW_EXCEPTION_IO_CORRUPT;
242
7
  if (UD.tile_length < 1 || UD.tile_length > S.raw_height)
243
1
    throw LIBRAW_EXCEPTION_IO_CORRUPT;
244
245
  // calculate tile count
246
6
  int tile_w = (S.raw_width + UD.tile_width - 1) / UD.tile_width;
247
6
  int tile_h = (S.raw_height + UD.tile_length - 1) / UD.tile_length;
248
6
  int tiles = tile_w * tile_h;
249
6
  if (tiles < 1 || tiles > 1024)
250
2
    throw LIBRAW_EXCEPTION_IO_CORRUPT;
251
252
4
  INT64 fsize = ifp->size();
253
4
  std::vector<INT64> toffsets(tiles);
254
4
  ifp->seek(UD.data_offset, SEEK_SET); // We're already here, but to make sure
255
19
  for (int i = 0; i < tiles; i++)
256
15
    toffsets[i] = get4();
257
258
4
  std::vector<unsigned> tlengths(tiles);
259
4
  ifp->seek(UD.data_size, SEEK_SET);
260
10
  for (int i = 0; i < tiles; i++)
261
8
  {
262
8
    tlengths[i] = get4();
263
8
    if(toffsets[i]+tlengths[i] > fsize)
264
2
        throw LIBRAW_EXCEPTION_IO_CORRUPT;
265
8
  }
266
2
  unsigned maxcomprlen = *std::max_element(tlengths.begin(), tlengths.end());
267
268
2
  std::vector<uint8_t> iobuffer(maxcomprlen+1); // Extra byte to ensure LJPEG byte stream marker search is ok
269
2
  std::vector<uint16_t> tilebuffer;
270
2
  for (int tile = 0; tile < tiles; tile++)
271
2
  {
272
2
    ifp->seek(toffsets[tile],SEEK_SET);
273
2
    int readed =  ifp->read(iobuffer.data(), 1, tlengths[tile]);
274
2
    if(unsigned(readed) != tlengths[tile])
275
0
        throw LIBRAW_EXCEPTION_IO_EOF;
276
2
    LibRaw_SonyYCC_Decompressor dec(iobuffer.data(), readed);
277
2
    if(dec.sof.cps != 3) // !YUV
278
2
        throw LIBRAW_EXCEPTION_IO_CORRUPT;
279
0
    if(dec.state != LibRaw_LjpegDecompressor::State::OK)
280
0
        throw LIBRAW_EXCEPTION_IO_CORRUPT;
281
282
0
    unsigned tiledatatsize = UD.tile_width * UD.tile_length * 3;
283
0
    if (tilebuffer.size() < tiledatatsize)
284
0
      tilebuffer.resize(tiledatatsize);
285
286
0
    if(!dec.decode_sony(tilebuffer, UD.tile_width * 3, UD.tile_length))
287
0
        throw LIBRAW_EXCEPTION_IO_CORRUPT;
288
289
0
    int tilerow = tile / tile_w;
290
0
    int tilecol = tile % tile_w;
291
0
    if (imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_RGB)
292
0
    {
293
0
      if(imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_INTERPOLATE)
294
0
            copy_ycc(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width,
295
0
                   tilebuffer.data(), UD.tile_width, UD.tile_length, dec.sof.components[0].subsample_h, dec.sof.components[0].subsample_v);
296
0
      else
297
0
            copy_ycc(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width,
298
0
                     tilebuffer.data(), UD.tile_width, UD.tile_length, 1, 1);
299
0
    }
300
0
    else
301
0
    ycc2rgb(imgdata.image, S.raw_width, S.raw_height, tilerow * UD.tile_length, tilecol * UD.tile_width,
302
0
        tilebuffer.data(), UD.tile_width, UD.tile_length);
303
0
  }
304
305
0
  for (int i = 0; i < 6; i++)
306
0
    imgdata.color.cblack[i] = 0;
307
308
0
  if (imgdata.rawparams.specials & LIBRAW_RAWSPECIAL_SRAW_NO_RGB)
309
0
  {
310
0
    imgdata.color.maximum = 18091; // estimated on over-exposed ISO100 frame
311
0
    imgdata.color.black = 0;
312
0
  }
313
0
  else
314
0
  {
315
0
    imgdata.color.maximum = 17536; // estimated on over-exposed ISO100 frame
316
0
    imgdata.color.black = 1024;
317
0
  }
318
0
}