150 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
			
		
		
	
	
			150 lines
		
	
	
		
			3.1 KiB
		
	
	
	
		
			C
		
	
	
	
	
	
// SPDX-License-Identifier: GPL-2.0
 | 
						|
/*
 | 
						|
 * Copyright (C) STMicroelectronics SA 2013
 | 
						|
 * Author: Hugues Fruchet <hugues.fruchet@st.com> for STMicroelectronics.
 | 
						|
 */
 | 
						|
 | 
						|
#include "delta.h"
 | 
						|
#include "delta-mjpeg.h"
 | 
						|
 | 
						|
#define MJPEG_SOF_0  0xc0
 | 
						|
#define MJPEG_SOF_1  0xc1
 | 
						|
#define MJPEG_SOI    0xd8
 | 
						|
#define MJPEG_MARKER 0xff
 | 
						|
 | 
						|
static char *header_str(struct mjpeg_header *header,
 | 
						|
			char *str,
 | 
						|
			unsigned int len)
 | 
						|
{
 | 
						|
	char *cur = str;
 | 
						|
	unsigned int left = len;
 | 
						|
 | 
						|
	if (!header)
 | 
						|
		return "";
 | 
						|
 | 
						|
	snprintf(cur, left, "[MJPEG header]\n"
 | 
						|
			"|- length     = %d\n"
 | 
						|
			"|- precision  = %d\n"
 | 
						|
			"|- width      = %d\n"
 | 
						|
			"|- height     = %d\n"
 | 
						|
			"|- components = %d\n",
 | 
						|
			header->length,
 | 
						|
			header->sample_precision,
 | 
						|
			header->frame_width,
 | 
						|
			header->frame_height,
 | 
						|
			header->nb_of_components);
 | 
						|
 | 
						|
	return str;
 | 
						|
}
 | 
						|
 | 
						|
static int delta_mjpeg_read_sof(struct delta_ctx *pctx,
 | 
						|
				unsigned char *data, unsigned int size,
 | 
						|
				struct mjpeg_header *header)
 | 
						|
{
 | 
						|
	struct delta_dev *delta = pctx->dev;
 | 
						|
	unsigned int offset = 0;
 | 
						|
 | 
						|
	if (size < 64)
 | 
						|
		goto err_no_more;
 | 
						|
 | 
						|
	memset(header, 0, sizeof(*header));
 | 
						|
	header->length           = be16_to_cpu(*(__be16 *)(data + offset));
 | 
						|
	offset += sizeof(u16);
 | 
						|
	header->sample_precision = *(u8 *)(data + offset);
 | 
						|
	offset += sizeof(u8);
 | 
						|
	header->frame_height     = be16_to_cpu(*(__be16 *)(data + offset));
 | 
						|
	offset += sizeof(u16);
 | 
						|
	header->frame_width      = be16_to_cpu(*(__be16 *)(data + offset));
 | 
						|
	offset += sizeof(u16);
 | 
						|
	header->nb_of_components = *(u8 *)(data + offset);
 | 
						|
	offset += sizeof(u8);
 | 
						|
 | 
						|
	if (header->nb_of_components >= MJPEG_MAX_COMPONENTS) {
 | 
						|
		dev_err(delta->dev,
 | 
						|
			"%s   unsupported number of components (%d > %d)\n",
 | 
						|
			pctx->name, header->nb_of_components,
 | 
						|
			MJPEG_MAX_COMPONENTS);
 | 
						|
		return -EINVAL;
 | 
						|
	}
 | 
						|
 | 
						|
	if ((offset + header->nb_of_components *
 | 
						|
	     sizeof(header->components[0])) > size)
 | 
						|
		goto err_no_more;
 | 
						|
 | 
						|
	return 0;
 | 
						|
 | 
						|
err_no_more:
 | 
						|
	dev_err(delta->dev,
 | 
						|
		"%s   sof: reached end of %d size input stream\n",
 | 
						|
		pctx->name, size);
 | 
						|
	return -ENODATA;
 | 
						|
}
 | 
						|
 | 
						|
int delta_mjpeg_read_header(struct delta_ctx *pctx,
 | 
						|
			    unsigned char *data, unsigned int size,
 | 
						|
			    struct mjpeg_header *header,
 | 
						|
			    unsigned int *data_offset)
 | 
						|
{
 | 
						|
	struct delta_dev *delta = pctx->dev;
 | 
						|
	unsigned char str[200];
 | 
						|
 | 
						|
	unsigned int ret = 0;
 | 
						|
	unsigned int offset = 0;
 | 
						|
	unsigned int soi = 0;
 | 
						|
 | 
						|
	if (size < 2)
 | 
						|
		goto err_no_more;
 | 
						|
 | 
						|
	offset = 0;
 | 
						|
	while (1) {
 | 
						|
		if (data[offset] == MJPEG_MARKER)
 | 
						|
			switch (data[offset + 1]) {
 | 
						|
			case MJPEG_SOI:
 | 
						|
				soi = 1;
 | 
						|
				*data_offset = offset;
 | 
						|
				break;
 | 
						|
 | 
						|
			case MJPEG_SOF_0:
 | 
						|
			case MJPEG_SOF_1:
 | 
						|
				if (!soi) {
 | 
						|
					dev_err(delta->dev,
 | 
						|
						"%s   wrong sequence, got SOF while SOI not seen\n",
 | 
						|
						pctx->name);
 | 
						|
					return -EINVAL;
 | 
						|
				}
 | 
						|
 | 
						|
				ret = delta_mjpeg_read_sof(pctx,
 | 
						|
							   &data[offset + 2],
 | 
						|
							   size - (offset + 2),
 | 
						|
							   header);
 | 
						|
				if (ret)
 | 
						|
					goto err;
 | 
						|
 | 
						|
				goto done;
 | 
						|
 | 
						|
			default:
 | 
						|
				break;
 | 
						|
			}
 | 
						|
 | 
						|
		offset++;
 | 
						|
		if ((offset + 2) >= size)
 | 
						|
			goto err_no_more;
 | 
						|
	}
 | 
						|
 | 
						|
done:
 | 
						|
	dev_dbg(delta->dev,
 | 
						|
		"%s   found header @ offset %d:\n%s", pctx->name,
 | 
						|
		*data_offset,
 | 
						|
		header_str(header, str, sizeof(str)));
 | 
						|
	return 0;
 | 
						|
 | 
						|
err_no_more:
 | 
						|
	dev_err(delta->dev,
 | 
						|
		"%s   no header found within %d bytes input stream\n",
 | 
						|
		pctx->name, size);
 | 
						|
	return -ENODATA;
 | 
						|
 | 
						|
err:
 | 
						|
	return ret;
 | 
						|
}
 |