1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * Copyright (C) STMicroelectronics SA 2013
4*4882a593Smuzhiyun * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include "delta.h"
8*4882a593Smuzhiyun #include "delta-mjpeg.h"
9*4882a593Smuzhiyun
10*4882a593Smuzhiyun #define MJPEG_SOF_0 0xc0
11*4882a593Smuzhiyun #define MJPEG_SOF_1 0xc1
12*4882a593Smuzhiyun #define MJPEG_SOI 0xd8
13*4882a593Smuzhiyun #define MJPEG_MARKER 0xff
14*4882a593Smuzhiyun
header_str(struct mjpeg_header * header,char * str,unsigned int len)15*4882a593Smuzhiyun static char *header_str(struct mjpeg_header *header,
16*4882a593Smuzhiyun char *str,
17*4882a593Smuzhiyun unsigned int len)
18*4882a593Smuzhiyun {
19*4882a593Smuzhiyun char *cur = str;
20*4882a593Smuzhiyun unsigned int left = len;
21*4882a593Smuzhiyun
22*4882a593Smuzhiyun if (!header)
23*4882a593Smuzhiyun return "";
24*4882a593Smuzhiyun
25*4882a593Smuzhiyun snprintf(cur, left, "[MJPEG header]\n"
26*4882a593Smuzhiyun "|- length = %d\n"
27*4882a593Smuzhiyun "|- precision = %d\n"
28*4882a593Smuzhiyun "|- width = %d\n"
29*4882a593Smuzhiyun "|- height = %d\n"
30*4882a593Smuzhiyun "|- components = %d\n",
31*4882a593Smuzhiyun header->length,
32*4882a593Smuzhiyun header->sample_precision,
33*4882a593Smuzhiyun header->frame_width,
34*4882a593Smuzhiyun header->frame_height,
35*4882a593Smuzhiyun header->nb_of_components);
36*4882a593Smuzhiyun
37*4882a593Smuzhiyun return str;
38*4882a593Smuzhiyun }
39*4882a593Smuzhiyun
delta_mjpeg_read_sof(struct delta_ctx * pctx,unsigned char * data,unsigned int size,struct mjpeg_header * header)40*4882a593Smuzhiyun static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
41*4882a593Smuzhiyun unsigned char *data, unsigned int size,
42*4882a593Smuzhiyun struct mjpeg_header *header)
43*4882a593Smuzhiyun {
44*4882a593Smuzhiyun struct delta_dev *delta = pctx->dev;
45*4882a593Smuzhiyun unsigned int offset = 0;
46*4882a593Smuzhiyun
47*4882a593Smuzhiyun if (size < 64)
48*4882a593Smuzhiyun goto err_no_more;
49*4882a593Smuzhiyun
50*4882a593Smuzhiyun memset(header, 0, sizeof(*header));
51*4882a593Smuzhiyun header->length = be16_to_cpu(*(__be16 *)(data + offset));
52*4882a593Smuzhiyun offset += sizeof(u16);
53*4882a593Smuzhiyun header->sample_precision = *(u8 *)(data + offset);
54*4882a593Smuzhiyun offset += sizeof(u8);
55*4882a593Smuzhiyun header->frame_height = be16_to_cpu(*(__be16 *)(data + offset));
56*4882a593Smuzhiyun offset += sizeof(u16);
57*4882a593Smuzhiyun header->frame_width = be16_to_cpu(*(__be16 *)(data + offset));
58*4882a593Smuzhiyun offset += sizeof(u16);
59*4882a593Smuzhiyun header->nb_of_components = *(u8 *)(data + offset);
60*4882a593Smuzhiyun offset += sizeof(u8);
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
63*4882a593Smuzhiyun dev_err(delta->dev,
64*4882a593Smuzhiyun "%s unsupported number of components (%d > %d)\n",
65*4882a593Smuzhiyun pctx->name, header->nb_of_components,
66*4882a593Smuzhiyun MJPEG_MAX_COMPONENTS);
67*4882a593Smuzhiyun return -EINVAL;
68*4882a593Smuzhiyun }
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun if ((offset + header->nb_of_components *
71*4882a593Smuzhiyun sizeof(header->components[0])) > size)
72*4882a593Smuzhiyun goto err_no_more;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun return 0;
75*4882a593Smuzhiyun
76*4882a593Smuzhiyun err_no_more:
77*4882a593Smuzhiyun dev_err(delta->dev,
78*4882a593Smuzhiyun "%s sof: reached end of %d size input stream\n",
79*4882a593Smuzhiyun pctx->name, size);
80*4882a593Smuzhiyun return -ENODATA;
81*4882a593Smuzhiyun }
82*4882a593Smuzhiyun
delta_mjpeg_read_header(struct delta_ctx * pctx,unsigned char * data,unsigned int size,struct mjpeg_header * header,unsigned int * data_offset)83*4882a593Smuzhiyun int delta_mjpeg_read_header(struct delta_ctx *pctx,
84*4882a593Smuzhiyun unsigned char *data, unsigned int size,
85*4882a593Smuzhiyun struct mjpeg_header *header,
86*4882a593Smuzhiyun unsigned int *data_offset)
87*4882a593Smuzhiyun {
88*4882a593Smuzhiyun struct delta_dev *delta = pctx->dev;
89*4882a593Smuzhiyun unsigned char str[200];
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun unsigned int ret = 0;
92*4882a593Smuzhiyun unsigned int offset = 0;
93*4882a593Smuzhiyun unsigned int soi = 0;
94*4882a593Smuzhiyun
95*4882a593Smuzhiyun if (size < 2)
96*4882a593Smuzhiyun goto err_no_more;
97*4882a593Smuzhiyun
98*4882a593Smuzhiyun offset = 0;
99*4882a593Smuzhiyun while (1) {
100*4882a593Smuzhiyun if (data[offset] == MJPEG_MARKER)
101*4882a593Smuzhiyun switch (data[offset + 1]) {
102*4882a593Smuzhiyun case MJPEG_SOI:
103*4882a593Smuzhiyun soi = 1;
104*4882a593Smuzhiyun *data_offset = offset;
105*4882a593Smuzhiyun break;
106*4882a593Smuzhiyun
107*4882a593Smuzhiyun case MJPEG_SOF_0:
108*4882a593Smuzhiyun case MJPEG_SOF_1:
109*4882a593Smuzhiyun if (!soi) {
110*4882a593Smuzhiyun dev_err(delta->dev,
111*4882a593Smuzhiyun "%s wrong sequence, got SOF while SOI not seen\n",
112*4882a593Smuzhiyun pctx->name);
113*4882a593Smuzhiyun return -EINVAL;
114*4882a593Smuzhiyun }
115*4882a593Smuzhiyun
116*4882a593Smuzhiyun ret = delta_mjpeg_read_sof(pctx,
117*4882a593Smuzhiyun &data[offset + 2],
118*4882a593Smuzhiyun size - (offset + 2),
119*4882a593Smuzhiyun header);
120*4882a593Smuzhiyun if (ret)
121*4882a593Smuzhiyun goto err;
122*4882a593Smuzhiyun
123*4882a593Smuzhiyun goto done;
124*4882a593Smuzhiyun
125*4882a593Smuzhiyun default:
126*4882a593Smuzhiyun break;
127*4882a593Smuzhiyun }
128*4882a593Smuzhiyun
129*4882a593Smuzhiyun offset++;
130*4882a593Smuzhiyun if ((offset + 2) >= size)
131*4882a593Smuzhiyun goto err_no_more;
132*4882a593Smuzhiyun }
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun done:
135*4882a593Smuzhiyun dev_dbg(delta->dev,
136*4882a593Smuzhiyun "%s found header @ offset %d:\n%s", pctx->name,
137*4882a593Smuzhiyun *data_offset,
138*4882a593Smuzhiyun header_str(header, str, sizeof(str)));
139*4882a593Smuzhiyun return 0;
140*4882a593Smuzhiyun
141*4882a593Smuzhiyun err_no_more:
142*4882a593Smuzhiyun dev_err(delta->dev,
143*4882a593Smuzhiyun "%s no header found within %d bytes input stream\n",
144*4882a593Smuzhiyun pctx->name, size);
145*4882a593Smuzhiyun return -ENODATA;
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun err:
148*4882a593Smuzhiyun return ret;
149*4882a593Smuzhiyun }
150