vx32

Local 9vx git repository for patches.
git clone git://r-36.net/vx32
Log | Files | Refs

native.c (4835B)


      1 
      2 #include <stdio.h>
      3 #include <stdlib.h>
      4 #include <stdarg.h>
      5 #include <unistd.h>
      6 #include <setjmp.h>
      7 #include <assert.h>
      8 #include <errno.h>
      9 
     10 #include <vxa/vxa.h>
     11 #include <vxa/codec.h>
     12 
     13 #include "cdjpeg.h"
     14 #include "native.h"
     15 
     16 
     17 char vxacodec_name[] = "jpeg";
     18 
     19 
     20 // Defined in djpeg-bin.c, generated from djpeg by bin2c.pl
     21 extern const uint8_t vxa_djpeg_data[];
     22 extern const int vxa_djpeg_length;
     23 
     24 
     25 int vxacodec_init(vxacodec *c, vxaio *io)
     26 {
     27 	c->decoder = vxa_djpeg_data;
     28 	c->decodersize = vxa_djpeg_length;
     29 
     30 	return VXA_RC_OK;
     31 }
     32 
     33 int vxacodec_encode(struct vxacodec *c, struct vxaio *io)
     34 {
     35 	return vxa_error(io, VXA_RC_WRONG_FORMAT,
     36 			"jpeg codec currently doesn't support compression");
     37 }
     38 
     39 static void error_exit(j_common_ptr cinfo)
     40 {
     41 	struct client_data *cdata = cinfo->client_data;
     42 
     43 	// Jump back to the original entrypoint with an error return
     44 	longjmp(cdata->errjmp, 1);
     45 }
     46 
     47 static void output_message(j_common_ptr cinfo)
     48 {
     49 	struct client_data *cdata = cinfo->client_data;
     50 
     51 	/* Create the message */
     52 	char buffer[JMSG_LENGTH_MAX];
     53 	cinfo->err->format_message(cinfo, buffer);
     54 
     55 	/* Stuff it into the vxaio struct */
     56 	vxa_error(cdata->io, VXA_RC_CORRUPT_DATA, "%s", buffer);
     57 }
     58 
     59 static void init_source(j_decompress_ptr cinfo)
     60 {
     61 	// Nothing to do
     62 }
     63 
     64 static boolean fill_input_buffer(j_decompress_ptr cinfo)
     65 {
     66 	struct client_data *cdata = cinfo->client_data;
     67 
     68 	ssize_t inlen = cdata->io->readf(cdata->io, cdata->inbuf, BUFSIZE);
     69 	if (inlen == 0)
     70 		vxa_error(cdata->io, VXA_RC_CORRUPT_DATA,
     71 			"compressed JPEG stream is truncated");
     72 	if (inlen <= 0)
     73 		longjmp(cdata->errjmp, 1);
     74 
     75 	cinfo->src->next_input_byte = cdata->inbuf;
     76 	cinfo->src->bytes_in_buffer = inlen;
     77 
     78 	return TRUE;
     79 }
     80 
     81 static void skip_input_data(j_decompress_ptr cinfo, long num_bytes)
     82 {
     83 	struct client_data *cdata = cinfo->client_data;
     84 
     85 	while (num_bytes > cinfo->src->bytes_in_buffer) {
     86 		num_bytes -= cinfo->src->bytes_in_buffer;
     87 		fill_input_buffer(cinfo);
     88 	}
     89 	cinfo->src->next_input_byte += num_bytes;
     90 	cinfo->src->bytes_in_buffer -= num_bytes;
     91 }
     92 
     93 static void term_source(j_decompress_ptr cinfo)
     94 {
     95 	// Nothing to do
     96 }
     97 
     98 void vxajpeg_flush(struct client_data *cd)
     99 {
    100 	if (cd->outpos == 0)
    101 		return;
    102 
    103 	ssize_t rc = cd->io->writef(cd->io, cd->outbuf, cd->outpos);
    104 	if (rc < 0)
    105 		longjmp(cd->errjmp, 1);
    106 	cd->outpos = 0;
    107 }
    108 
    109 int vxacodec_decode(struct vxacodec *c, struct vxaio *io)
    110 {
    111 	// Save the vital args in a client_data struct for our callbacks
    112 	struct client_data cdata;
    113 	cdata.io = io;
    114 	cdata.inbuf = NULL;
    115 
    116 	// Set up the JPEG library error handler struct
    117 	struct jpeg_error_mgr jerr;
    118 	memset(&jerr, 0, sizeof(jerr));
    119 	jpeg_std_error(&jerr);
    120 	jerr.error_exit = error_exit;
    121 	jerr.output_message = output_message;
    122 
    123 	// Setup the JPEG input source
    124 	struct jpeg_source_mgr jsrc;
    125 	memset(&jsrc, 0, sizeof(jsrc));
    126 	jsrc.init_source = init_source;
    127 	jsrc.fill_input_buffer = fill_input_buffer;
    128 	jsrc.skip_input_data = skip_input_data;
    129 	jsrc.resync_to_restart = jpeg_resync_to_restart;
    130 	jsrc.term_source = term_source;
    131 
    132 	// Set up the main decompression state struct
    133 	struct jpeg_decompress_struct cinfo;
    134 	memset(&cinfo, 0, sizeof(cinfo));
    135 	cinfo.client_data = &cdata;
    136 	cinfo.err = &jerr;
    137 	cinfo.src = &jsrc;
    138 
    139 	// Set up a JMP_BUF for error_exit() to longjmp to on fatal errors. */
    140 	if (setjmp(cdata.errjmp)) {
    141 		jpeg_destroy_decompress(&cinfo);
    142 		if (cdata.inbuf != NULL)
    143 			free(cdata.inbuf);
    144 		return io->errcode;
    145 	}
    146 
    147 	// Allocate the input and output buffers
    148 	cdata.inbuf = malloc(BUFSIZE*2);
    149 	if (cdata.inbuf == NULL)
    150 		return vxa_error(io, VXA_RC_NO_MEMORY,
    151 				"no memory for JPEG decoder input buffer");
    152 	cdata.outbuf = cdata.inbuf + BUFSIZE;
    153 	cdata.outpos = 0;
    154 
    155 	// Initialize the JPEG decoder
    156 	jpeg_create_decompress(&cinfo);
    157 	(void) jpeg_read_header(&cinfo, TRUE);
    158 
    159 	djpeg_dest_ptr dest_mgr = jinit_write_bmp(&cinfo, FALSE);
    160 	dest_mgr->output_file = (FILE*)&cdata;	// XX hack hack hack
    161 
    162 	(void) jpeg_start_decompress(&cinfo);
    163 	dest_mgr->start_output(&cinfo, dest_mgr);
    164 
    165 	/* Process data */
    166 	while (cinfo.output_scanline < cinfo.output_height) {
    167 		JDIMENSION num_scanlines = jpeg_read_scanlines(
    168 				&cinfo, dest_mgr->buffer,
    169 				dest_mgr->buffer_height);
    170 		dest_mgr->put_pixel_rows(&cinfo, dest_mgr, num_scanlines);
    171 	}
    172 
    173 	dest_mgr->finish_output(&cinfo, dest_mgr);
    174 
    175 	vxajpeg_flush(&cdata);
    176 
    177 	(void) jpeg_finish_decompress(&cinfo);
    178 	jpeg_destroy_decompress(&cinfo);
    179 
    180 	free(cdata.inbuf);
    181 
    182 	return VXA_RC_OK;
    183 }
    184 
    185 int vxacodec_recognize(struct vxacodec *c, struct vxaio *io,
    186 			const void *header, size_t size)
    187 {
    188 	const uint8_t *inp = header;
    189 	if (size >= 4 &&
    190 			inp[0] == 0xff &&
    191 			inp[1] == 0xd8 &&	// SOI
    192 			inp[2] == 0xff &&
    193 			inp[3] >= 0xe0) {	// APPx
    194 		io->method = VXA_M_JPEG;
    195 		return vxa_error(io, VXA_RC_COMPRESSED,
    196 				"input already compressed in JPEG format");
    197 	}
    198 
    199 	return vxa_error(io, VXA_RC_WRONG_FORMAT,
    200 			"JPEG codec currently can't compress");
    201 }
    202