xref: /OK3568_Linux_fs/kernel/drivers/media/platform/sti/delta/delta-mjpeg-hdr.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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