mirror of
https://github.com/espressif/esp32-camera.git
synced 2025-07-03 23:55:31 +08:00
Separate JPEG decoder and add JPEG EOF detection
This commit is contained in:
118
conversions/esp_jpg_decode.c
Normal file
118
conversions/esp_jpg_decode.c
Normal file
@ -0,0 +1,118 @@
|
|||||||
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#include "esp_jpg_decode.h"
|
||||||
|
#include "rom/tjpgd.h"
|
||||||
|
|
||||||
|
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||||
|
#include "esp32-hal-log.h"
|
||||||
|
#define TAG ""
|
||||||
|
#else
|
||||||
|
#include "esp_log.h"
|
||||||
|
static const char* TAG = "esp_jpg_decode";
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef struct {
|
||||||
|
jpg_scale_t scale;
|
||||||
|
jpg_reader_cb reader;
|
||||||
|
jpg_writer_cb writer;
|
||||||
|
void * arg;
|
||||||
|
size_t len;
|
||||||
|
size_t index;
|
||||||
|
} esp_jpg_decoder_t;
|
||||||
|
|
||||||
|
static const char * jd_errors[] = {
|
||||||
|
"Succeeded",
|
||||||
|
"Interrupted by output function",
|
||||||
|
"Device error or wrong termination of input stream",
|
||||||
|
"Insufficient memory pool for the image",
|
||||||
|
"Insufficient stream input buffer",
|
||||||
|
"Parameter error",
|
||||||
|
"Data format error",
|
||||||
|
"Right format but not supported",
|
||||||
|
"Not supported JPEG standard"
|
||||||
|
};
|
||||||
|
|
||||||
|
static uint32_t _jpg_write(JDEC *decoder, void *bitmap, JRECT *rect)
|
||||||
|
{
|
||||||
|
uint16_t x = rect->left;
|
||||||
|
uint16_t y = rect->top;
|
||||||
|
uint16_t w = rect->right + 1 - x;
|
||||||
|
uint16_t h = rect->bottom + 1 - y;
|
||||||
|
uint8_t *data = (uint8_t *)bitmap;
|
||||||
|
|
||||||
|
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||||
|
|
||||||
|
if (jpeg->writer) {
|
||||||
|
return jpeg->writer(jpeg->arg, x, y, w, h, data);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static uint32_t _jpg_read(JDEC *decoder, uint8_t *buf, uint32_t len)
|
||||||
|
{
|
||||||
|
esp_jpg_decoder_t * jpeg = (esp_jpg_decoder_t *)decoder->device;
|
||||||
|
if (jpeg->len && len > (jpeg->len - jpeg->index)) {
|
||||||
|
len = jpeg->len - jpeg->index;
|
||||||
|
}
|
||||||
|
if (len) {
|
||||||
|
len = jpeg->reader(jpeg->arg, jpeg->index, buf, len);
|
||||||
|
if (!len) {
|
||||||
|
ESP_LOGE(TAG, "Read Fail at %u/%u", jpeg->index, jpeg->len);
|
||||||
|
}
|
||||||
|
jpeg->index += len;
|
||||||
|
}
|
||||||
|
return len;
|
||||||
|
}
|
||||||
|
|
||||||
|
esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg)
|
||||||
|
{
|
||||||
|
static uint8_t work[3100];
|
||||||
|
JDEC decoder;
|
||||||
|
esp_jpg_decoder_t jpeg;
|
||||||
|
|
||||||
|
jpeg.len = len;
|
||||||
|
jpeg.reader = reader;
|
||||||
|
jpeg.writer = writer;
|
||||||
|
jpeg.arg = arg;
|
||||||
|
jpeg.scale = scale;
|
||||||
|
jpeg.index = 0;
|
||||||
|
|
||||||
|
JRESULT jres = jd_prepare(&decoder, _jpg_read, work, 3100, &jpeg);
|
||||||
|
if(jres != JDR_OK){
|
||||||
|
ESP_LOGE(TAG, "JPG Header Parse Failed! %s", jd_errors[jres]);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint16_t output_width = decoder.width / (1 << (uint8_t)(jpeg.scale));
|
||||||
|
uint16_t output_height = decoder.height / (1 << (uint8_t)(jpeg.scale));
|
||||||
|
|
||||||
|
//output start
|
||||||
|
writer(arg, 0, 0, output_width, output_height, NULL);
|
||||||
|
//output write
|
||||||
|
jres = jd_decomp(&decoder, _jpg_write, (uint8_t)jpeg.scale);
|
||||||
|
//output end
|
||||||
|
writer(arg, output_width, output_height, output_width, output_height, NULL);
|
||||||
|
|
||||||
|
if (jres != JDR_OK) {
|
||||||
|
ESP_LOGE(TAG, "JPG Decompression Failed! %s", jd_errors[jres]);
|
||||||
|
return ESP_FAIL;
|
||||||
|
}
|
||||||
|
//check if all data has been consumed.
|
||||||
|
if (len && jpeg.index < len) {
|
||||||
|
_jpg_read(&decoder, NULL, len - jpeg.index);
|
||||||
|
}
|
||||||
|
|
||||||
|
return ESP_OK;
|
||||||
|
}
|
||||||
|
|
43
conversions/include/esp_jpg_decode.h
Normal file
43
conversions/include/esp_jpg_decode.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
// Copyright 2015-2016 Espressif Systems (Shanghai) PTE LTD
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
// you may not use this file except in compliance with the License.
|
||||||
|
// You may obtain a copy of the License at
|
||||||
|
//
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
//
|
||||||
|
// Unless required by applicable law or agreed to in writing, software
|
||||||
|
// distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
// See the License for the specific language governing permissions and
|
||||||
|
// limitations under the License.
|
||||||
|
#ifndef _ESP_JPG_DECODE_H_
|
||||||
|
#define _ESP_JPG_DECODE_H_
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <stdint.h>
|
||||||
|
#include <stdbool.h>
|
||||||
|
#include "esp_err.h"
|
||||||
|
|
||||||
|
typedef enum {
|
||||||
|
JPG_SCALE_NONE,
|
||||||
|
JPG_SCALE_2X,
|
||||||
|
JPG_SCALE_4X,
|
||||||
|
JPG_SCALE_8X,
|
||||||
|
JPG_SCALE_MAX = JPG_SCALE_8X
|
||||||
|
} jpg_scale_t;
|
||||||
|
|
||||||
|
typedef size_t (* jpg_reader_cb)(void * arg, size_t index, uint8_t *buf, size_t len);
|
||||||
|
typedef bool (* jpg_writer_cb)(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data);
|
||||||
|
|
||||||
|
esp_err_t esp_jpg_decode(size_t len, jpg_scale_t scale, jpg_reader_cb reader, jpg_writer_cb writer, void * arg);
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#endif /* _ESP_JPG_DECODE_H_ */
|
@ -14,12 +14,12 @@
|
|||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include "img_converters.h"
|
#include "img_converters.h"
|
||||||
#include "rom/tjpgd.h"
|
|
||||||
#include "esp_spiram.h"
|
#include "esp_spiram.h"
|
||||||
#include "soc/efuse_reg.h"
|
#include "soc/efuse_reg.h"
|
||||||
#include "esp_heap_caps.h"
|
#include "esp_heap_caps.h"
|
||||||
#include "yuv.h"
|
#include "yuv.h"
|
||||||
#include "sdkconfig.h"
|
#include "sdkconfig.h"
|
||||||
|
#include "esp_jpg_decode.h"
|
||||||
|
|
||||||
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
#if defined(ARDUINO_ARCH_ESP32) && defined(CONFIG_ARDUHAL_ESP_LOG)
|
||||||
#include "esp32-hal-log.h"
|
#include "esp32-hal-log.h"
|
||||||
@ -31,14 +31,6 @@ static const char* TAG = "to_bmp";
|
|||||||
|
|
||||||
static const int BMP_HEADER_LEN = 54;
|
static const int BMP_HEADER_LEN = 54;
|
||||||
|
|
||||||
typedef enum {
|
|
||||||
JPEG_DIV_NONE,
|
|
||||||
JPEG_DIV_2,
|
|
||||||
JPEG_DIV_4,
|
|
||||||
JPEG_DIV_8,
|
|
||||||
JPEG_DIV_MAX
|
|
||||||
} jpeg_div_t;
|
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
uint32_t filesize;
|
uint32_t filesize;
|
||||||
uint32_t reserved;
|
uint32_t reserved;
|
||||||
@ -57,45 +49,49 @@ typedef struct {
|
|||||||
} bmp_header_t;
|
} bmp_header_t;
|
||||||
|
|
||||||
typedef struct {
|
typedef struct {
|
||||||
jpeg_div_t scale;
|
uint16_t width;
|
||||||
const void * src;
|
uint16_t height;
|
||||||
size_t len;
|
const uint8_t *input;
|
||||||
size_t index;
|
uint8_t *output;
|
||||||
uint16_t width;
|
} rgb_jpg_decoder;
|
||||||
uint16_t height;
|
|
||||||
uint8_t * dst;
|
|
||||||
size_t dstlen;
|
|
||||||
} jpg_frame_decoder_t;
|
|
||||||
|
|
||||||
const char * jpgd_errors[] = {
|
|
||||||
"Succeeded",
|
|
||||||
"Interrupted by output function",
|
|
||||||
"Device error or wrong termination of input stream",
|
|
||||||
"Insufficient memory pool for the image",
|
|
||||||
"Insufficient stream input buffer",
|
|
||||||
"Parameter error",
|
|
||||||
"Data format error",
|
|
||||||
"Right format but not supported",
|
|
||||||
"Not supported JPEG standard"
|
|
||||||
};
|
|
||||||
|
|
||||||
static void *_malloc(size_t size)
|
static void *_malloc(size_t size)
|
||||||
{
|
{
|
||||||
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
return heap_caps_malloc(size, MALLOC_CAP_SPIRAM | MALLOC_CAP_8BIT);
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t jpg_write_bmp(JDEC *decoder, void *bitmap, JRECT *rect)
|
//output buffer and image width
|
||||||
|
static bool _rgb_write(void * arg, uint16_t x, uint16_t y, uint16_t w, uint16_t h, uint8_t *data)
|
||||||
{
|
{
|
||||||
jpg_frame_decoder_t * jpeg = (jpg_frame_decoder_t *)decoder->device;
|
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||||
|
if(!data){
|
||||||
|
if(x == 0 && y == 0){
|
||||||
|
//write start
|
||||||
|
jpeg->width = w;
|
||||||
|
jpeg->height = h;
|
||||||
|
//if output is null, this is BMP
|
||||||
|
if(!jpeg->output){
|
||||||
|
jpeg->output = (uint8_t *)_malloc((w*h*3)+BMP_HEADER_LEN);
|
||||||
|
if(!jpeg->output){
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
//write end
|
||||||
|
}
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
size_t jw = jpeg->width*3;
|
size_t jw = jpeg->width*3;
|
||||||
size_t t = rect->top * jw;
|
size_t t = y * jw;
|
||||||
size_t b = (rect->bottom * jw) + 1;
|
size_t b = t + (h * jw);
|
||||||
size_t l = rect->left * 3;
|
size_t l = x * 3;
|
||||||
size_t w = (rect->right + 1 - rect->left) * 3;
|
uint8_t *out = jpeg->output+BMP_HEADER_LEN;
|
||||||
uint8_t *data = (uint8_t *)bitmap;
|
|
||||||
uint8_t *out = jpeg->dst;
|
|
||||||
uint8_t *o = out;
|
uint8_t *o = out;
|
||||||
size_t iy, ix;
|
size_t iy, ix;
|
||||||
|
|
||||||
|
w = w * 3;
|
||||||
|
|
||||||
for(iy=t; iy<b; iy+=jw) {
|
for(iy=t; iy<b; iy+=jw) {
|
||||||
o = out+iy+l;
|
o = out+iy+l;
|
||||||
for(ix=0; ix<w; ix+= 3) {
|
for(ix=0; ix<w; ix+= 3) {
|
||||||
@ -105,48 +101,69 @@ static uint32_t jpg_write_bmp(JDEC *decoder, void *bitmap, JRECT *rect)
|
|||||||
}
|
}
|
||||||
data+=w;
|
data+=w;
|
||||||
}
|
}
|
||||||
return 1;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint32_t jpg_read_frame(JDEC *decoder, uint8_t *buf, uint32_t len)
|
//input buffer
|
||||||
|
static uint32_t _jpg_read(void * arg, size_t index, uint8_t *buf, size_t len)
|
||||||
{
|
{
|
||||||
jpg_frame_decoder_t * jpeg = (jpg_frame_decoder_t *)decoder->device;
|
rgb_jpg_decoder * jpeg = (rgb_jpg_decoder *)arg;
|
||||||
if(buf) {
|
if(buf) {
|
||||||
memcpy(buf, (const uint8_t *)jpeg->src + jpeg->index, len);
|
memcpy(buf, jpeg->input + index, len);
|
||||||
}
|
}
|
||||||
jpeg->index += len;
|
|
||||||
return len;
|
return len;
|
||||||
}
|
}
|
||||||
|
|
||||||
static uint8_t jpg_work_buffer[3100];
|
static bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpg_scale_t scale)
|
||||||
|
|
||||||
bool jpg2rgb888(const uint8_t *src, size_t src_len, uint8_t * out, jpeg_div_t scale)
|
|
||||||
{
|
{
|
||||||
JDEC decoder;
|
rgb_jpg_decoder jpeg;
|
||||||
jpg_frame_decoder_t jpeg;
|
|
||||||
jpeg.src = src;
|
|
||||||
jpeg.len = src_len;
|
|
||||||
jpeg.index = 0;
|
|
||||||
jpeg.width = 0;
|
jpeg.width = 0;
|
||||||
jpeg.height = 0;
|
jpeg.height = 0;
|
||||||
jpeg.dst = out;
|
jpeg.input = src;
|
||||||
jpeg.dstlen = 0;
|
jpeg.output = out;
|
||||||
jpeg.scale = scale;
|
|
||||||
|
|
||||||
JRESULT jres = jd_prepare(&decoder, jpg_read_frame, jpg_work_buffer, 3100, &jpeg);
|
if(esp_jpg_decode(src_len, scale, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
|
||||||
if(jres != JDR_OK) {
|
|
||||||
ESP_LOGE(TAG, "jd_prepare failed! %s", jpgd_errors[jres]);
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
jpeg.width = decoder.width / (1 << (uint8_t)(jpeg.scale));
|
return true;
|
||||||
jpeg.height = decoder.height / (1 << (uint8_t)(jpeg.scale));
|
}
|
||||||
jpeg.dstlen = jpeg.width*jpeg.height*3;
|
|
||||||
|
|
||||||
jres = jd_decomp(&decoder, jpg_write_bmp, (uint8_t)jpeg.scale);
|
bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
|
||||||
if(jres != JDR_OK) {
|
{
|
||||||
ESP_LOGE(TAG, "jd_decomp failed! %s", jpgd_errors[jres]);
|
|
||||||
|
rgb_jpg_decoder jpeg;
|
||||||
|
jpeg.width = 0;
|
||||||
|
jpeg.height = 0;
|
||||||
|
jpeg.input = src;
|
||||||
|
jpeg.output = NULL;
|
||||||
|
|
||||||
|
if(esp_jpg_decode(src_len, JPG_SCALE_NONE, _jpg_read, _rgb_write, (void*)&jpeg) != ESP_OK){
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
size_t output_size = jpeg.width*jpeg.height*3;
|
||||||
|
|
||||||
|
jpeg.output[0] = 'B';
|
||||||
|
jpeg.output[1] = 'M';
|
||||||
|
bmp_header_t * bitmap = (bmp_header_t*)&jpeg.output[2];
|
||||||
|
bitmap->reserved = 0;
|
||||||
|
bitmap->filesize = output_size+BMP_HEADER_LEN;
|
||||||
|
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
||||||
|
bitmap->dibheadersize = 40;
|
||||||
|
bitmap->width = jpeg.width;
|
||||||
|
bitmap->height = -jpeg.height;//set negative for top to bottom
|
||||||
|
bitmap->planes = 1;
|
||||||
|
bitmap->bitsperpixel = 24;
|
||||||
|
bitmap->compression = 0;
|
||||||
|
bitmap->imagesize = output_size;
|
||||||
|
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||||
|
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
||||||
|
bitmap->numcolorspallette = 0;
|
||||||
|
bitmap->mostimpcolor = 0;
|
||||||
|
|
||||||
|
*out = jpeg.output;
|
||||||
|
*out_len = output_size+BMP_HEADER_LEN;
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -154,7 +171,7 @@ bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint
|
|||||||
{
|
{
|
||||||
int pix_count = 0;
|
int pix_count = 0;
|
||||||
if(format == PIXFORMAT_JPEG) {
|
if(format == PIXFORMAT_JPEG) {
|
||||||
return jpg2rgb888(src_buf, src_len, rgb_buf, JPEG_DIV_NONE);
|
return jpg2rgb888(src_buf, src_len, rgb_buf, JPG_SCALE_NONE);
|
||||||
} else if(format == PIXFORMAT_RGB888) {
|
} else if(format == PIXFORMAT_RGB888) {
|
||||||
memcpy(rgb_buf, src_buf, src_len);
|
memcpy(rgb_buf, src_buf, src_len);
|
||||||
} else if(format == PIXFORMAT_RGB565) {
|
} else if(format == PIXFORMAT_RGB565) {
|
||||||
@ -203,73 +220,6 @@ bool fmt2rgb888(const uint8_t *src_buf, size_t src_len, pixformat_t format, uint
|
|||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool jpg2bmp(const uint8_t *src, size_t src_len, uint8_t ** out, size_t * out_len)
|
|
||||||
{
|
|
||||||
JDEC decoder;
|
|
||||||
uint8_t * out_buf = NULL;
|
|
||||||
jpg_frame_decoder_t jpeg;
|
|
||||||
|
|
||||||
jpeg.src = src;
|
|
||||||
jpeg.len = src_len;
|
|
||||||
jpeg.index = 0;
|
|
||||||
jpeg.width = 0;
|
|
||||||
jpeg.height = 0;
|
|
||||||
jpeg.dst = NULL;
|
|
||||||
jpeg.dstlen = 0;
|
|
||||||
jpeg.scale = JPEG_DIV_NONE;
|
|
||||||
|
|
||||||
*out = jpeg.dst;
|
|
||||||
*out_len = jpeg.dstlen;
|
|
||||||
|
|
||||||
JRESULT jres = jd_prepare(&decoder, jpg_read_frame, jpg_work_buffer, 3100, &jpeg);
|
|
||||||
if(jres != JDR_OK) {
|
|
||||||
ESP_LOGE(TAG, "jd_prepare failed! %s", jpgd_errors[jres]);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
jpeg.width = decoder.width / (1 << (uint8_t)(jpeg.scale));
|
|
||||||
jpeg.height = decoder.height / (1 << (uint8_t)(jpeg.scale));
|
|
||||||
size_t output_size = jpeg.width*jpeg.height*3;
|
|
||||||
|
|
||||||
//setup output buffer
|
|
||||||
jpeg.dstlen = output_size+BMP_HEADER_LEN;
|
|
||||||
out_buf = (uint8_t *)_malloc(jpeg.dstlen);
|
|
||||||
if(!out_buf) {
|
|
||||||
ESP_LOGE(TAG, "_malloc failed! %u", jpeg.dstlen);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
jpeg.dst = out_buf+BMP_HEADER_LEN;
|
|
||||||
|
|
||||||
out_buf[0] = 'B';
|
|
||||||
out_buf[1] = 'M';
|
|
||||||
bmp_header_t * bitmap = (bmp_header_t*)&out_buf[2];
|
|
||||||
bitmap->reserved = 0;
|
|
||||||
bitmap->filesize = jpeg.dstlen;
|
|
||||||
bitmap->fileoffset_to_pixelarray = BMP_HEADER_LEN;
|
|
||||||
bitmap->dibheadersize = 40;
|
|
||||||
bitmap->width = jpeg.width;
|
|
||||||
bitmap->height = -jpeg.height;//set negative for top to bottom
|
|
||||||
bitmap->planes = 1;
|
|
||||||
bitmap->bitsperpixel = 24;
|
|
||||||
bitmap->compression = 0;
|
|
||||||
bitmap->imagesize = output_size;
|
|
||||||
bitmap->ypixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
|
||||||
bitmap->xpixelpermeter = 0x0B13 ; //2835 , 72 DPI
|
|
||||||
bitmap->numcolorspallette = 0;
|
|
||||||
bitmap->mostimpcolor = 0;
|
|
||||||
|
|
||||||
jres = jd_decomp(&decoder, jpg_write_bmp, (uint8_t)jpeg.scale);
|
|
||||||
|
|
||||||
if(jres != JDR_OK) {
|
|
||||||
ESP_LOGE(TAG, "jd_decomp failed! %s", jpgd_errors[jres]);
|
|
||||||
free(out_buf);
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
*out = out_buf;
|
|
||||||
*out_len = jpeg.dstlen;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len)
|
bool fmt2bmp(uint8_t *src, size_t src_len, uint16_t width, uint16_t height, pixformat_t format, uint8_t ** out, size_t * out_len)
|
||||||
{
|
{
|
||||||
if(format == PIXFORMAT_JPEG) {
|
if(format == PIXFORMAT_JPEG) {
|
||||||
|
@ -614,6 +614,24 @@ static void IRAM_ATTR dma_filter_buffer(size_t buf_idx)
|
|||||||
if (buf_idx == SIZE_MAX) {
|
if (buf_idx == SIZE_MAX) {
|
||||||
if(!s_state->fb->ref) {
|
if(!s_state->fb->ref) {
|
||||||
s_state->fb->len = s_state->dma_filtered_count * buf_len;
|
s_state->fb->len = s_state->dma_filtered_count * buf_len;
|
||||||
|
if(s_state->fb->format == PIXFORMAT_JPEG){
|
||||||
|
//find end of file 0xFF 0xD9
|
||||||
|
uint8_t * dptr = &s_state->fb->buf[s_state->fb->len - 1];
|
||||||
|
while(dptr > s_state->fb->buf){
|
||||||
|
if(dptr[0] == 0xFF && dptr[1] == 0xD9 && dptr[2] == 0x00 && dptr[3] == 0x00){
|
||||||
|
dptr += 2;
|
||||||
|
s_state->fb->len = dptr - s_state->fb->buf;
|
||||||
|
if((s_state->fb->len & 0x1FF) == 0){
|
||||||
|
s_state->fb->len += 1;
|
||||||
|
}
|
||||||
|
if((s_state->fb->len % 100) == 0){
|
||||||
|
s_state->fb->len += 1;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
dptr--;
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
if(s_state->fb->len) {
|
if(s_state->fb->len) {
|
||||||
if(s_state->config.fb_count == 1) {
|
if(s_state->config.fb_count == 1) {
|
||||||
@ -647,17 +665,6 @@ static void IRAM_ATTR dma_filter_buffer(size_t buf_idx)
|
|||||||
s_state->fb->height = resolution[s_state->sensor.framesize][1];
|
s_state->fb->height = resolution[s_state->sensor.framesize][1];
|
||||||
s_state->fb->format = s_state->sensor.pixformat;
|
s_state->fb->format = s_state->sensor.pixformat;
|
||||||
}
|
}
|
||||||
|
|
||||||
if(s_state->config.pixel_format == PIXFORMAT_JPEG) {
|
|
||||||
if(!s_state->dma_filtered_count) { //first buffer
|
|
||||||
uint32_t sig = *((uint32_t *)s_state->fb->buf) & 0xFFFFFF;
|
|
||||||
if(sig != 0xffd8ff) {
|
|
||||||
//ets_printf("*");
|
|
||||||
//maybe skip frame?
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
s_state->dma_filtered_count++;
|
s_state->dma_filtered_count++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Reference in New Issue
Block a user