summaryrefslogtreecommitdiff
path: root/subprojects/pixpat/pixpat-native/src/io/csi2.h
blob: 59a8f8d060242e12a3b9ae634c191490307ca88b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#pragma once

// Shared MIPI CSI-2 byte (un)packing for the 10P / 12P forms used by
// Bayer raw and Y-only grayscale.
//
//   10P: 4 samples in 5 bytes — bytes 0..3 hold the high 8 bits of
//        samples 0..3; byte 4 holds 4 x 2 LSBs (sample 0 in bits 6..7,
//        sample 1 in bits 4..5, ...).
//   12P: 2 samples in 3 bytes — bytes 0..1 hold the high 8 bits of
//        samples 0..1; byte 2 holds 2 x 4 LSBs (sample 0 in bits 4..7,
//        sample 1 in bits 0..3).
//
// Helpers deal in the stored integer (low BitDepth bits set);
// normalization to/from the 16-bit pivot stays in the caller.

#include <array>
#include <cstddef>
#include <cstdint>

namespace pixpat::detail::csi2
{

template <size_t BitDepth>
struct packed_traits;

template <>
struct packed_traits<10> {
	static constexpr size_t ppg = 4;
	static constexpr size_t bpg = 5;
};

template <>
struct packed_traits<12> {
	static constexpr size_t ppg = 2;
	static constexpr size_t bpg = 3;
};

// Extract one BitDepth-bit sample from a packed group, where `i` is the
// in-group index (0..ppg-1). The returned value occupies the low
// BitDepth bits.
template <size_t BitDepth>
inline uint16_t unpack_sample(const uint8_t* src, size_t i) noexcept
{
	if constexpr (BitDepth == 10) {
		const uint8_t hi  = src[i];
		const uint8_t lsb = (src[4] >> ((3 - i) * 2)) & 0x03;
		return uint16_t((hi << 2) | lsb);
	} else { // 12
		const uint8_t hi  = src[i];
		const uint8_t lsb = (i == 0) ? ((src[2] >> 4) & 0x0F)
		                             :  (src[2]       & 0x0F);
		return uint16_t((hi << 4) | lsb);
	}
}

// Write `ppg` BitDepth-bit samples (low BitDepth bits significant) into
// a packed group of `bpg` bytes.
template <size_t BitDepth>
inline void pack_group(
	uint8_t* dst,
	const std::array<uint16_t, packed_traits<BitDepth>::ppg>& vals) noexcept
{
	if constexpr (BitDepth == 10) {
		dst[0] = (vals[0] >> 2) & 0xFF;
		dst[1] = (vals[1] >> 2) & 0xFF;
		dst[2] = (vals[2] >> 2) & 0xFF;
		dst[3] = (vals[3] >> 2) & 0xFF;
		dst[4] = ((vals[0] & 0x03) << 6)
		         | ((vals[1] & 0x03) << 4)
		         | ((vals[2] & 0x03) << 2)
		         | ((vals[3] & 0x03) << 0);
	} else { // 12
		dst[0] = (vals[0] >> 4) & 0xFF;
		dst[1] = (vals[1] >> 4) & 0xFF;
		dst[2] = ((vals[0] & 0x0F) << 4)
		         | ((vals[1] & 0x0F) << 0);
	}
}

} // namespace pixpat::detail::csi2