summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--Makefile16
-rw-r--r--ipedec.c220
2 files changed, 236 insertions, 0 deletions
diff --git a/Makefile b/Makefile
new file mode 100644
index 0000000..0edd281
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,16 @@
+CC = gcc
+CFLAGS = -g -std=c99
+
+all: ipedec
+
+ipedec: ipedec.o
+ $(CC) $(LDFLAGS) -o $@ $^
+
+ipedec.o: ipedec.c
+ $(CC) $(CFLAGS) -c -o $@ $<
+
+clean:
+ rm -f ipedec ipedec.o
+
+.PHONY: clean
+
diff --git a/ipedec.c b/ipedec.c
new file mode 100644
index 0000000..48a1a7a
--- /dev/null
+++ b/ipedec.c
@@ -0,0 +1,220 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdint.h>
+#include <assert.h>
+
+#define IPECAMERA_MAX_LINES 1088
+#define IPECAMERA_MAX_CHANNELS 16
+#define IPECAMERA_PIXELS_PER_CHANNEL 128
+#define IPECAMERA_WIDTH (IPECAMERA_MAX_CHANNELS * IPECAMERA_PIXELS_PER_CHANNEL)
+#define IPECAMERA_HEIGHT 1088
+
+int ipecamera_channel_order[IPECAMERA_MAX_CHANNELS] = { 15, 13, 14, 12, 10, 8, 11, 7, 9, 6, 5, 2, 4, 3, 0, 1 };
+
+#define CHECK_VALUE(value, expected) \
+ if (value != expected) { \
+ fprintf(stderr, "<%s:%i> 0x%x != 0x%x\n", __FILE__, __LINE__, value, expected); \
+ err = 1; \
+ }
+
+#define CHECK_FLAG(flag, check, ...) \
+ if (!(check)) { \
+ fprintf(stderr, "<%s:%i> Unexpected value 0x%x of " flag "\n", __FILE__, __LINE__, __VA_ARGS__); \
+ err = 1; \
+ }
+
+
+static int ipecamera_get_payload(uint16_t *pixel_buffer,
+ int line_req, size_t size,
+ uint32_t *payload,
+ int *advance, int *increase_line)
+{
+ int ppw;
+ int err = 0;
+
+ uint32_t info = payload[0];
+ int channel = info & 0x0F; // 4 bits
+ int line = (info >> 4) & 0x7FF; // 11 bits
+ int bpp = (info >> 16) & 0x0F; // 4 bits
+ int pixels = (info >> 20) & 0xFF; // 8 bits
+ int header = (info >> 30) & 0x03; // 2 bits
+
+ int bytes, pix, pix_offset = 0;
+ uint32_t data;
+
+ *increase_line = channel == 15 ? 1 : 0;
+ channel = ipecamera_channel_order[channel];
+
+ CHECK_FLAG("payload header magick", header == 2, header);
+ CHECK_FLAG("pixel size, only 10 bits are supported", bpp == 10, bpp);
+ CHECK_FLAG("row number, should be %i", line == line_req, line, line_req);
+ CHECK_FLAG("channel, limited by %i output channels", channel < IPECAMERA_MAX_CHANNELS, channel, IPECAMERA_MAX_CHANNELS);
+
+ if ((line < 2) && (pixels == (IPECAMERA_PIXELS_PER_CHANNEL - 1))) {
+ pix_offset = 1;
+ pixel_buffer[channel*IPECAMERA_PIXELS_PER_CHANNEL] = 0;
+ }
+ else
+ CHECK_FLAG("number of pixels, %i is expected", pixels == IPECAMERA_PIXELS_PER_CHANNEL, pixels, IPECAMERA_PIXELS_PER_CHANNEL);
+
+ bytes = pixels / 3;
+ ppw = pixels - bytes * 3;
+ if (ppw)
+ ++bytes;
+
+ CHECK_FLAG("payload data bytes, at least %i are expected", bytes < size, (unsigned int) size, bytes);
+
+ if (err)
+ return err;
+
+ pix = pix_offset;
+ for (int i = 1; i < bytes; i++) {
+ data = payload[i];
+ header = (data >> 30) & 0x03;
+
+ CHECK_FLAG("payload data magick", header == 3, header);
+ if (err)
+ return err;
+
+ pixel_buffer[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix++] = (data >> 20) & 0x3FF;
+ pixel_buffer[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix++] = (data >> 10) & 0x3FF;
+ pixel_buffer[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix++] = data & 0x3FF;
+ }
+
+ data = payload[bytes];
+ header = (data >> 30) & 0x03;
+
+ CHECK_FLAG("payload data magick", header == 3, header);
+ CHECK_FLAG("payload footer magick", (data&0x3FF) == 0x55, (data&0x3FF));
+ if ((err) && ((data & 0x3FF) != 0x55)) {
+ err = 0;
+ int counter = 0;
+ printf(" -> %x\n", data);
+ while ((data & 0x3FF) != 0x55) {
+ bytes++;
+ data = payload[bytes];
+ counter++;
+ }
+ printf("skipped %i bytes: found %x\n", counter, data);
+ }
+ if (err)
+ return err;
+
+ ppw = pixels % 3;
+ assert(ppw < 3);
+
+ for (int j = 0; j < ppw; j++, pix++)
+ pixel_buffer[channel*IPECAMERA_PIXELS_PER_CHANNEL + pix] = (data >> (10 * (ppw - j))) & 0x3FF;
+
+ *advance = bytes + 1;
+ return 0;
+}
+
+static int ipecamera_parse_image(int first_line, int num_lines,
+ size_t size, uint32_t *linebuf, int *frames_decoded)
+{
+ int err = 0, current_frame = 0;
+ int pos = 0, advance, increase_line;
+
+ if (size < 16) {
+ fprintf(stderr, "The payload is tool small, we should have at least 8 header dwords and 8 footer.");
+ return 1;
+ }
+
+ FILE *fp = fopen("image.dec.raw", "wb");
+ uint16_t *pixel_buffer = (uint16_t *) malloc(num_lines * IPECAMERA_WIDTH * sizeof(uint16_t));
+
+ printf("Decoding");
+ while (size > 0) {
+ printf(".");
+ int line = first_line;
+ CHECK_VALUE(linebuf[pos++], 0x51111111);
+ CHECK_VALUE(linebuf[pos++], 0x52222222);
+ CHECK_VALUE(linebuf[pos++], 0x53333333);
+ CHECK_VALUE(linebuf[pos++], 0x54444444);
+ CHECK_VALUE(linebuf[pos++], 0x55555555);
+ CHECK_VALUE(linebuf[pos++], 0x56666666);
+ CHECK_VALUE(linebuf[pos++], 0x57777777);
+ CHECK_VALUE(linebuf[pos++], 0x58888888);
+ if (err)
+ return err;
+
+ size -= 16;
+
+ while ((size > 0) && (line < (first_line + num_lines))) {
+ err = ipecamera_get_payload(pixel_buffer + line * IPECAMERA_WIDTH,
+ line - first_line, size, linebuf + pos, &advance, &increase_line);
+ if (err)
+ return err;
+
+ pos += advance;
+ size -= advance;
+ line += increase_line;
+ }
+
+ CHECK_FLAG("lines read, we expect to read exactly %i lines", line == (first_line + num_lines), line - first_line, num_lines);
+
+ CHECK_VALUE(linebuf[pos++], 0x0AAAAAAA);
+ CHECK_VALUE(linebuf[pos++], 0x0BBBBBBB);
+ CHECK_VALUE(linebuf[pos++], 0x0CCCCCCC);
+ CHECK_VALUE(linebuf[pos++], 0x0DDDDDDD);
+ CHECK_VALUE(linebuf[pos++], 0x0EEEEEEE);
+ CHECK_VALUE(linebuf[pos++], 0x0FFFFFFF);
+ CHECK_VALUE(linebuf[pos++], 0x00000000);
+ CHECK_VALUE(linebuf[pos++], 0x01111111);
+
+ fwrite(pixel_buffer, IPECAMERA_WIDTH * num_lines, sizeof(uint16_t), fp);
+
+ if (linebuf[pos] == 0)
+ break;
+
+ current_frame++;
+ }
+ fclose(fp);
+ free(pixel_buffer);
+ printf("\n");
+ *frames_decoded = current_frame + 1;
+ return err;
+}
+
+int main(int argc, char const* argv[])
+{
+ if (argc < 3) {
+ fprintf(stderr, "Usage: ipedec <filename> <number of lines per frame>\n");
+ return 1;
+ }
+
+ FILE *fp = fopen(argv[1], "rb");
+ if (fp == NULL) {
+ fprintf(stderr, "Couldn't open file %s", argv[1]);
+ return 1;
+ }
+
+ const int lines_per_frame = atoi(argv[2]);
+
+ fseek(fp, 0, SEEK_END);
+ const size_t length = ftell(fp);
+ rewind(fp);
+
+ char *buffer = (char *) malloc(length);
+ if (buffer == NULL) {
+ fclose(fp);
+ return 1;
+ }
+
+ size_t buffer_length = fread(buffer, 1, length, fp);
+ fclose(fp);
+ if (buffer_length != length) {
+ free(buffer);
+ return 1;
+ }
+
+ int num_frames;
+ if (ipecamera_parse_image(0, lines_per_frame, length, (uint32_t *) buffer, &num_frames))
+ fprintf(stderr, "Couldn't parse image\n");
+
+ printf("Decoded %i frames.\n", num_frames);
+ free(buffer);
+ return 0;
+}
+