mirror of
https://github.com/rzeldent/esp32cam-rtsp.git
synced 2025-11-14 04:04:02 +00:00
Work in progress
This commit is contained in:
@@ -2,17 +2,34 @@
|
|||||||
|
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <stddef.h>
|
#include <stddef.h>
|
||||||
#include <tuple>
|
|
||||||
|
|
||||||
class micro_rtsp_jpeg
|
class micro_rtsp_jpeg
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
micro_rtsp_jpeg(const uint8_t *jpeg, size_t size);
|
bool decode_jpeg(const uint8_t *jpg, size_t size);
|
||||||
|
|
||||||
std::tuple<const uint8_t *, size_t> quantization_table_0_;
|
class __attribute__ ((packed)) jpg_section
|
||||||
std::tuple<const uint8_t *, size_t> quantization_table_1_;
|
{
|
||||||
std::tuple<const uint8_t *, size_t> jpeg_data_;
|
public:
|
||||||
protected:
|
uint8_t flag() const { return section_flag; }
|
||||||
bool decode_jpeg(uint8_t *jpg, size_t size);
|
const char *flag_name() const;
|
||||||
std::tuple<const uint8_t *, size_t> find_jpeg_section(uint8_t **ptr, uint8_t *end, uint8_t flag);
|
uint16_t section_length() const { return section_flag == 0xd8 || section_flag == 0xd9 ? 0 : (section_length_msb << 8) + section_length_lsb; }
|
||||||
|
const uint8_t *data() const { return reinterpret_cast<const uint8_t *>(§ion_data[1]); }
|
||||||
|
uint16_t data_length() const { return section_length() - 3; }
|
||||||
|
|
||||||
|
private:
|
||||||
|
const uint8_t section_flag;
|
||||||
|
const uint8_t section_length_msb;
|
||||||
|
const uint8_t section_length_lsb;
|
||||||
|
const uint8_t section_data[];
|
||||||
|
};
|
||||||
|
|
||||||
|
const jpg_section *quantization_table_0_;
|
||||||
|
const jpg_section *quantization_table_1_;
|
||||||
|
|
||||||
|
const uint8_t *jpeg_data_start;
|
||||||
|
const uint8_t *jpeg_data_end;
|
||||||
|
|
||||||
|
private:
|
||||||
|
static const jpg_section *find_jpeg_section(const uint8_t **ptr, const uint8_t *end, uint8_t flag);
|
||||||
};
|
};
|
||||||
@@ -2,100 +2,100 @@
|
|||||||
|
|
||||||
#include "micro_rtsp_jpeg.h"
|
#include "micro_rtsp_jpeg.h"
|
||||||
|
|
||||||
micro_rtsp_jpeg::micro_rtsp_jpeg(const uint8_t *jpeg, size_t size)
|
const char *micro_rtsp_jpeg::jpg_section::flag_name() const
|
||||||
{
|
{
|
||||||
|
switch (section_flag)
|
||||||
|
{
|
||||||
|
case 0xd8:
|
||||||
|
return "SOI"; // start of image
|
||||||
|
case 0xd9:
|
||||||
|
return "EOI"; // end of image
|
||||||
|
case 0xe0:
|
||||||
|
return "APP0";
|
||||||
|
case 0xdb:
|
||||||
|
return "DQT"; // define quantization table
|
||||||
|
case 0xc4:
|
||||||
|
return "DHT"; // define Huffman table
|
||||||
|
case 0xc0:
|
||||||
|
return "SOF"; // start of frame
|
||||||
|
case 0xda:
|
||||||
|
return "SOS"; // start of scan
|
||||||
|
}
|
||||||
|
return "Unknown";
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<const uint8_t *, size_t> micro_rtsp_jpeg::find_jpeg_section(uint8_t **ptr, uint8_t *end, uint8_t flag)
|
const micro_rtsp_jpeg::jpg_section *micro_rtsp_jpeg::find_jpeg_section(const uint8_t **ptr, const uint8_t *end, uint8_t flag)
|
||||||
{
|
{
|
||||||
size_t len;
|
log_d("find_jpeg_section 0x%02x", flag);
|
||||||
while (*ptr < end)
|
while (*ptr < end)
|
||||||
{
|
{
|
||||||
auto framing = *(*ptr++);
|
auto framing = *((*ptr)++);
|
||||||
if (framing != 0xff)
|
if (framing != 0xff)
|
||||||
{
|
{
|
||||||
log_e("Malformed jpeg. Expected framing 0xff but found: 0x%02x", framing);
|
log_e("Expected framing 0xff but found: 0x%02x", framing);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
// framing = 0xff, flag, len MSB, len LSB
|
// framing = 0xff, flag, len MSB, len LSB
|
||||||
auto flag_code = *(*ptr++);
|
auto section = reinterpret_cast<const jpg_section *>((*ptr)++);
|
||||||
// Length of section
|
// Advance pointer section has a length, so not SOI (0xd8) and EOI (0xd9)
|
||||||
len = *(*ptr++) * 256 + *(*ptr++);
|
*ptr += section->section_length();
|
||||||
if (flag_code == flag)
|
if (section->flag() == flag)
|
||||||
return std::tuple<const uint8_t *, size_t>(*ptr, len);
|
{
|
||||||
|
log_d("Found section 0x%02x (%s), %d bytes", flag, section->flag_name(), section->section_length());
|
||||||
|
return section;
|
||||||
|
}
|
||||||
|
|
||||||
// Skip the section
|
log_d("Skipping section: 0x%02x (%s), %d bytes", section->flag(), section->flag_name(), section->section_length());
|
||||||
switch (flag_code)
|
|
||||||
{
|
|
||||||
case 0xe0: // APP00
|
|
||||||
case 0xdb: // DQT (define quantization table)
|
|
||||||
case 0xc4: // DHT (define Huffman table)
|
|
||||||
case 0xc0: // SOF0 (start of frame)
|
|
||||||
case 0xda: // SOS (start of scan)
|
|
||||||
{
|
|
||||||
log_d("Skipping jpeg section flag: 0x%02x, %d bytes", flag_code, len);
|
|
||||||
ptr += len;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
default:
|
|
||||||
log_e("Unexpected jpeg flag: 0x%02x", flag_code);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Not found
|
// Not found
|
||||||
return std::tuple<const uint8_t *, size_t>(nullptr, 0);
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
// See https://create.stephan-brumme.com/toojpeg/
|
// See https://create.stephan-brumme.com/toojpeg/
|
||||||
bool micro_rtsp_jpeg::decode_jpeg(uint8_t *data, size_t size)
|
bool micro_rtsp_jpeg::decode_jpeg(const uint8_t *data, size_t size)
|
||||||
{
|
{
|
||||||
|
log_d("decode_jpeg");
|
||||||
// Look for start jpeg file (0xd8)
|
// Look for start jpeg file (0xd8)
|
||||||
auto ptr = data;
|
auto ptr = data;
|
||||||
auto end = ptr + size;
|
auto end = ptr + size;
|
||||||
|
|
||||||
// Check for SOI (start of image) 0xff, 0xd8
|
// Check for SOI (start of image) 0xff, 0xd8
|
||||||
if (*(ptr++) != 0xff || *(ptr++) != 0xd8)
|
if (!find_jpeg_section(&ptr, end, 0xd8))
|
||||||
{
|
{
|
||||||
log_e("No valid start of image marker found");
|
log_e("No valid start of image marker found");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
// First quantization table
|
// First quantization table
|
||||||
quantization_table_0_ = find_jpeg_section(&ptr, end, 0xdb);
|
if (!(quantization_table_0_ = find_jpeg_section(&ptr, end, 0xdb)))
|
||||||
if (std::get<0>(quantization_table_0_) == nullptr)
|
|
||||||
{
|
|
||||||
log_e("No quantization table 0 section found");
|
log_e("No quantization table 0 section found");
|
||||||
}
|
|
||||||
|
|
||||||
// Second quantization table (for color images)
|
// Second quantization table (for color images)
|
||||||
quantization_table_1_ = find_jpeg_section(&ptr, end, 0xdb);
|
if (!(quantization_table_1_ = find_jpeg_section(&ptr, end, 0xdb)))
|
||||||
if (std::get<0>(quantization_table_1_) == nullptr)
|
|
||||||
{
|
|
||||||
log_w("No quantization table 1 section found");
|
log_w("No quantization table 1 section found");
|
||||||
}
|
|
||||||
// Start of scan
|
// Start of scan
|
||||||
auto sos = find_jpeg_section(&ptr, end, 0xda);
|
if (!find_jpeg_section(&ptr, end, 0xda))
|
||||||
if (std::get<0>(sos) == nullptr)
|
|
||||||
{
|
|
||||||
log_e("No start of scan section found");
|
log_e("No start of scan section found");
|
||||||
}
|
|
||||||
|
|
||||||
// Start of the data sections
|
// Start of the data sections
|
||||||
auto start = ptr;
|
jpeg_data_start = ptr;
|
||||||
|
|
||||||
// Scan over all the sections. 0xff followed by not zero, is a new section
|
// Scan over all the sections. 0xff followed by not zero, is a new section
|
||||||
while (ptr < end - 1 && (*ptr != 0xff || ptr[1] == 0))
|
while (ptr < end - 1 && (ptr[0] != 0xff || ptr[1] == 0))
|
||||||
ptr++;
|
ptr++;
|
||||||
|
|
||||||
// Go back tgo start of section
|
|
||||||
ptr--;
|
|
||||||
|
|
||||||
// Check if marker is an end of image marker
|
// Check if marker is an end of image marker
|
||||||
if (*(ptr++) != 0xff || *(ptr++) != 0xd9)
|
if (!find_jpeg_section(&ptr, end, 0xd9))
|
||||||
{
|
{
|
||||||
log_e("No end of image marker found");
|
log_e("No end of image marker found");
|
||||||
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
jpeg_data_ = std::tuple<const uint8_t *, size_t>(start, size - (ptr - start - 2));
|
jpeg_data_end = ptr;
|
||||||
|
log_d("Total jpeg data = %d bytes", jpeg_data_end - jpeg_data_start);
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -31,6 +31,7 @@ default_envs = esp32cam_ai_thinker
|
|||||||
[env]
|
[env]
|
||||||
platform = espressif32
|
platform = espressif32
|
||||||
framework = arduino
|
framework = arduino
|
||||||
|
test_framework = unity
|
||||||
|
|
||||||
#upload_protocol = espota
|
#upload_protocol = espota
|
||||||
#upload_port = 192.168.178.223
|
#upload_port = 192.168.178.223
|
||||||
@@ -42,7 +43,8 @@ framework = arduino
|
|||||||
monitor_speed = 115200
|
monitor_speed = 115200
|
||||||
monitor_rts = 0
|
monitor_rts = 0
|
||||||
monitor_dtr = 0
|
monitor_dtr = 0
|
||||||
monitor_filters = log2file, time, default, esp32_exception_decoder
|
#monitor_filters = log2file, time, default, esp32_exception_decoder
|
||||||
|
monitor_filters = esp32_exception_decoder
|
||||||
|
|
||||||
build_flags =
|
build_flags =
|
||||||
-Ofast
|
-Ofast
|
||||||
|
|||||||
File diff suppressed because one or more lines are too long
Reference in New Issue
Block a user