59 Commits

Author SHA1 Message Date
Rene Zeldenthuis
12332fd7eb Work in progress 2024-11-04 00:46:58 +01:00
Rene Zeldenthuis
4dc36fb1e8 Work in progress 2024-11-02 21:45:07 +01:00
Rene Zeldenthuis
4b50b52ae0 WIP 2024-04-02 01:16:17 +02:00
Rene Zeldenthuis
b8abcdcdee WIP 2024-04-02 00:27:54 +02:00
Rene Zeldenthuis
5117f0d21a WIP 2024-04-01 19:58:44 +02:00
Rene Zeldenthuis
f59fb8bb9a WIP 2024-04-01 17:57:37 +02:00
Rene Zeldenthuis
c599657882 WIP 2024-03-30 22:31:33 +01:00
Rene Zeldenthuis
3e688ddcfb Fix 2024-03-19 14:00:12 +01:00
Rene Zeldenthuis
c2dcd8b3d4 Merge branch 'develop' into 106-create-new-rtsp-server 2024-03-19 13:58:50 +01:00
Rene Zeldenthuis
fe7195c232 Update with settings from Sheed 2024-03-19 13:49:06 +01:00
Rene Zeldenthuis
86ae9af574 WIP 2024-03-19 13:45:22 +01:00
Rene Zeldenthuis
383d5803af Merge branch 'main' into develop 2024-03-10 12:47:22 +01:00
Rene Zeldenthuis
312d916647 merge issues and fixes 2024-03-10 12:46:48 +01:00
Rene Zeldenthuis
c1d92bcb36 Merge branch 'main' into develop 2024-03-10 11:27:10 +01:00
Rene Zeldenthuis
71079f4796 Fix merge 2024-03-10 11:24:40 +01:00
Rene
d99d1c510f Merged from develop (Updated documentation) (#115)
* Added seeed_xiao_esp32s3

* Fixed typo

* Updating build system

* Fixed typos

* Renamed envirnment name to seeed_xiao_esp32s3

* Update README.md

* Updated platformio definitions

* Added cache

* Updated README.md

* - Default value for initResult if initialzation fails

* constexpr camera_config_t m5stack_camera_settings

* Added M5Stack UnitCamS3

* Work in progress

* WIP

* Work in progress

* Removed OTA

* Added unitcams3

* UnitcamS3

* Corrected HTML for ipv4
fixed Sewrial issue esp32s2

* USER_LED_ON_LEVEL=LOW

* Added documentation pins for Mems/grove/led

* Typo

* Removed non required depencency

* Removed non required depencency

* Readded

* Added sccb_i2c_port
Retry 3 times camera init

* Added Freenove wroom-1 n8r8 board (#112)

Co-authored-by: Nick Eales <nick.eales@outlook.com>

* Fixing missing comma in xiao board json (#114)

* Updated Markdown

---------

Co-authored-by: absentwallaby <64674944+absentwallaby@users.noreply.github.com>
Co-authored-by: Nick Eales <nick.eales@outlook.com>
Co-authored-by: Nick Volgas <n.volgas@gmail.com>
2024-03-10 11:11:03 +01:00
Rene
c61e6cd882 Merge branch 'main' into develop 2024-03-10 11:10:09 +01:00
Rene Zeldenthuis
80a23aa5c4 Updated Markdown 2024-03-10 11:01:38 +01:00
Nick Volgas
e702191382 Fixing missing comma in xiao board json (#114) 2024-02-23 19:42:09 +01:00
absentwallaby
613965e425 Added Freenove wroom-1 n8r8 board (#112)
Co-authored-by: Nick Eales <nick.eales@outlook.com>
2024-02-22 00:12:54 +01:00
Rene Zeldenthuis
2eb7a58e1c Work in progress 2024-02-18 12:47:17 +01:00
Rene Zeldenthuis
6119020e7d Work in progress 2024-02-17 10:12:23 +01:00
Rene Zeldenthuis
152c068f68 Fixes 2024-02-15 22:33:42 +01:00
Rene Zeldenthuis
f05932b896 Unittests in progress 2024-02-15 21:59:34 +01:00
Rene Zeldenthuis
4fbba6fc96 Unit tests in progress 2024-02-15 21:59:08 +01:00
Rene Zeldenthuis
4fb0f61e8e Merge branch 'develop' into 106-create-new-rtsp-server 2024-02-15 21:27:15 +01:00
Rene Zeldenthuis
a760fdae38 Added sccb_i2c_port
Retry 3 times camera init
2024-02-15 21:22:22 +01:00
Rene Zeldenthuis
03582b83cb WIP 2024-02-13 19:15:27 +01:00
Rene
a60fbc7917 Develop (#108)
* Added seeed_xiao_esp32s3

* Fixed typo

* Updating build system

* Fixed typos

* Renamed envirnment name to seeed_xiao_esp32s3

* Update README.md

* Updated platformio definitions

* Added cache

* Updated README.md

* - Default value for initResult if initialzation fails

* constexpr camera_config_t m5stack_camera_settings

* Added M5Stack UnitCamS3

* Work in progress

* WIP

* Work in progress

* Removed OTA

* Added unitcams3

* UnitcamS3

* Corrected HTML for ipv4
fixed Sewrial issue esp32s2

* USER_LED_ON_LEVEL=LOW

* Added documentation pins for Mems/grove/led

* Typo

* Removed non required depencency

* Removed non required depencency

* Readded
2024-02-13 14:13:45 +01:00
Rene
1c2236466d Merge branch 'main' into develop 2024-02-13 14:13:05 +01:00
Rene Zeldenthuis
26d1af2f28 Work in progress 2024-02-13 01:23:40 +01:00
Rene Zeldenthuis
97fc4ceb33 WIP 2024-02-11 00:42:55 +01:00
Rene Zeldenthuis
9ba11162d8 Readded 2024-02-10 00:31:34 +01:00
Rene Zeldenthuis
fd21f32870 Merge branch 'develop' of https://github.com/rzeldent/esp32cam-rtsp into develop 2024-02-10 00:26:39 +01:00
Rene Zeldenthuis
4239de2286 Removed non required depencency 2024-02-10 00:26:37 +01:00
Rene Zeldenthuis
60b602b077 Removed non required depencency 2024-02-10 00:20:34 +01:00
Rene Zeldenthuis
7b4f4c056a Typo 2024-02-07 02:09:06 +01:00
Rene Zeldenthuis
4df6c9469d Added documentation pins for Mems/grove/led 2024-02-07 02:07:23 +01:00
Rene Zeldenthuis
50f4b6f94e USER_LED_ON_LEVEL=LOW 2024-02-07 00:14:55 +01:00
Rene Zeldenthuis
f9336ad803 Corrected HTML for ipv4
fixed Sewrial issue esp32s2
2024-02-07 00:00:41 +01:00
Rene Zeldenthuis
8e5f4ee66c UnitcamS3 2024-02-06 16:16:52 +01:00
Rene Zeldenthuis
138c620296 Added unitcams3 2024-02-05 01:19:04 +01:00
Rene Zeldenthuis
545a824b37 Removed OTA 2024-02-05 00:55:44 +01:00
Rene Zeldenthuis
e8cdf6d044 Work in progress 2024-02-04 23:23:59 +01:00
Rene Zeldenthuis
a90c4fe672 WIP 2024-02-04 20:22:09 +01:00
Rene Zeldenthuis
5bdfc45e3b Work in progress 2024-02-04 17:11:21 +01:00
Rene
d0ef68bbf4 Added M5Stack UnitCamS3 2024-01-28 13:43:31 +01:00
Rene
51c5bf08bc constexpr camera_config_t m5stack_camera_settings 2024-01-28 12:06:25 +01:00
Rene
7f37bff13d - Default value for initResult if initialzation fails 2024-01-17 23:51:03 +01:00
Rene Zeldenthuis
351c6a29d5 Updated README.md 2023-12-19 00:01:14 +01:00
Rene Zeldenthuis
6850c2c47f Merge branch 'feature/seeed_xiao_esp32s3' into develop 2023-12-18 23:47:57 +01:00
Rene Zeldenthuis
9ecdd1c05d Added cache 2023-12-17 02:24:52 +01:00
Rene Zeldenthuis
0809f6baba Updated platformio definitions 2023-12-17 02:21:27 +01:00
Rene
ed293ebb68 Update README.md 2023-10-17 16:14:02 +02:00
Rene Zeldenthuis
5b7d6f9da6 Renamed envirnment name to seeed_xiao_esp32s3 2023-10-07 21:59:41 +02:00
Rene Zeldenthuis
fdc0ddd379 Fixed typos 2023-09-21 09:21:08 +02:00
Rene Zeldenthuis
6917e44287 Updating build system 2023-09-18 23:35:53 +02:00
Rene Zeldenthuis
4360630835 Fixed typo 2023-08-17 01:58:47 +02:00
Rene Zeldenthuis
b3cb7d1bf7 Added seeed_xiao_esp32s3 2023-08-17 01:57:14 +02:00
76 changed files with 2719 additions and 505 deletions

View File

@@ -5,18 +5,25 @@ jobs:
name: Build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Set up python
uses: actions/setup-python@v3
- uses: actions/checkout@v4
with:
python-version: '3.x'
architecture: 'x64'
submodules: 'true'
- uses: actions/cache@v4
with:
path: |
~/.cache/pip
~/.platformio/.cache
key: ${{ runner.os }}-pio
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.9'
- name: Install PlatformIO
run: python -m pip install platformio
- name: Build firmware
run: platformio run
- name: Archive
uses: actions/upload-artifact@v3
uses: actions/upload-artifact@v4
with:
name: firmware.bin
name: firmwares.zip
path: .pio/build/*/firmware.bin

136
README.md
View File

@@ -9,34 +9,43 @@ Simple [RTSP](https://en.wikipedia.org/wiki/Real_Time_Streaming_Protocol), [HTTP
> This branch supports all the current devices and the Seeed Studio Xiao esp32s3!
> Please use this and let me know if this works for you!
Flashing this software on a ESP32CAM module will make it a **RTSP streaming camera** server, a **HTTP Motion JPEG streamer** and a **HTTP image server**.
Supported protocols
- :white_check_mark: RTSP
- RTSP
The RTSP protocol is an industry standard and allows many CCTV systems and applications (like for example [VLC](https://www.videolan.org/vlc/)) to connect directly to the ESP32CAM camera stream.
It is also possible to stream directly to a server using [ffmpeg](https://ffmpeg.org).
This makes the module a camera server allowing recording and the stream can be stored on a disk and replayed later.
The URL is rtsp://&lt;ip address&gt;:554/mjpeg/1
- :white_check_mark: HTTP Motion JPEG
- HTTP Motion JPEG
The HTTP JPEG streamer makes it possible to watch the camera stream directly in your browser.
The URL is http://&lt;ip address&gt;/stream
- :white_check_mark: HTTP image
- HTTP image
The HTTP Image returns an HTTP JPEG image of the camera.
The URL is http://&lt;ip address&gt;/snapshot
This software supports the following ESP32-CAM (and alike) modules:
- ESP32CAM
- AI THINKER
- TTGO T-CAM
- WROVER-KIT
- EspressIf ESP-EYE
- EspressIf ESP32S2-CAM
- EspressIf ESP32S3-CAM-LCD
- EspressIf ESP32S3-EYE
- Freenove WROVER KIT
- M5STACK ESP32CAM
- M5STACK_PSRAM
- M5STACK_UNITCAM
- M5STACK_UNITCAMS3
- M5STACK_V2_PSRAM
- M5STACK_PSRAM
- M5STACK_WIDE
- M5STACK
![ESP32CAM module](assets/ESP32-CAM.jpg)
- Seeed Studio XIAO ESP32S3 SENSE
- TTGO T-CAMERA
- TTGO T-JOURNAL
The software provides a **configuration web server**, that can be used to:
@@ -44,7 +53,6 @@ The software provides a **configuration web server**, that can be used to:
- Set the WiFi parameters,
- Set the timeout for connecting to the access point,
- Set an access password,
- Select the board type,
- Select the image size,
- Select the frame rate,
- Select the JPEG quality
@@ -54,7 +62,7 @@ The software provides a **configuration web server**, that can be used to:
- Brightness
- Contrast
- Saturation
- Special effect (Normal, Negative, Grayscale, Red/Green/Blue tint, Sepia)
- Special effect (Normal, Negative, Gray-scale, Red/Green/Blue tint, Sepia)
- White balance
- Automatic White Balance gain
- Wite Balance mode
@@ -83,25 +91,34 @@ It advertises HTTP (port 80) and RTSP (port 554)
- USB to Serial (TTL level) converter, piggyback board ESP32-CAM-MB or other way to connect to the device,
- [**PlatformIO**](https://platformio.org/) software (free download)
## Boards
There are a lot of boards available that are all called ESP32-CAM.
However, there are differences in CPU (type/speed/cores), how the camera is connected, presence of PSRAM or not...
To select the right board use the table below and use the configuration that is listed below for your board:
| Board | Image | CPU | SRAM | Flash | PSRAM | Camera | Extras | Manufacturer site |
|--- |--- |--- |--- |--- | --- |--- |--- |--- |
| Espressif ESP32-Wrover CAM | ![img](assets/boards/esp32-wrover-cam.jpg) | ESP32 | 520KB | 4Mb | 4MB | OV2640 | | |
| AI-Thinker ESP32-CAM | ![img](assets/boards/ai-thinker-esp32-cam-ipex.jpg) ![img](assets/boards/ai-thinker-esp32-cam.jpg) | ESP32-S | 520KB | 4Mb | 4MB | OV2640 | | [https://docs.ai-thinker.com/esp32-cam](https://docs.ai-thinker.com/esp32-cam) |
| Espressif ESP-EYE | ![img](assets/boards/espressif-esp-eye.jpg) | ESP32 | 520KB | 4Mb | 4MB | OV2640 | | |
| Espressif ESP-S3-EYE | ![img](assets/boards/espressif-esps3-eye.jpg) | ESP32-S3 | 520KB | 4Mb | 4MB | OV2640 | | [https://www.espressif.com/en/products/devkits/esp-eye/overview](https://www.espressif.com/en/products/devkits/esp-eye/overview) |
| LilyGo camera module | ![img](assets/boards/lilygo-camera-module.jpg) | ESP32 Wrover | 520KB | 4Mb | 4MB | OV2640 / OV5640 | | |
| LilyGo Simcam | ![img](assets/boards/lilygo-simcam.jpg) | | | | | OV2640 | | |
| LilyGo TTGO-T Camera | ![img](assets/boards/lilygo-ttgo-t-camera.jpg) | | | | | OV2640 | | |
| M5Stack ESP32CAM | ![img](assets/boards/m5stack_esp32cam_02.webp) | ESP32 | 520Kb | 4Mb | - | OV2640 | Microphone | [https://docs.m5stack.com/en/unit/esp32cam](https://docs.m5stack.com/en/unit/esp32cam) |
| M5Stack UnitCam | ![img](assets/boards/m5stack_unit_cam_02.webp) ![img](assets/boards/m5stack_unit_cam_03.webp) | ESP32-WROOM-32E | 520KB | 4Mb | - | OV2640 | | [https://docs.m5stack.com/en/unit/unit_cam](https://docs.m5stack.com/en/unit/unit_cam) |
| M5Stack Camera | ![img](assets/boards/m5stack-esp32-camera.jpg) | ESP32 | 520Kb | 4Mb | - | OV2640 | | [https://docs.m5stack.com/en/unit/m5camera](https://docs.m5stack.com/en/unit/m5camera) |
| M5Stack Camera PSRAM | ![img](assets/boards/m5stack-esp32-camera.jpg) | ESP32 | 520Kb | 4Mb | 4Mb | OV2640 | | [https://docs.m5stack.com/en/unit/m5camera](https://docs.m5stack.com/en/unit/m5camera) |
| M5Stack UnitCamS3 | ![img](assets/boards//m5stack_Unitcams3.webp) ![img](assets/boards/m5stack_Unitcams32.webp) | ESP32-S3-WROOM-1-N16R8 | 520Kb | 16Mb | 8Mb | OV2640 | | [https://docs.m5stack.com/en/unit/Unit-CamS3](https://docs.m5stack.com/en/unit/Unit-CamS3) |
| Seeed studio Xiao ESP32S3 Sense | ![img](assets/boards/seeed-studio-xiao-esp32s3-sense.jpg) | ESP32-S3R8 | 520KB | 8Mb | 8MB | OV2640 | Microphone | [https://www.seeedstudio.com/XIAO-ESP32S3-Sense-p-5639.html](https://www.seeedstudio.com/XIAO-ESP32S3-Sense-p-5639.html) |
## Installing and running PlatformIO
PlatformIO is available for all major operating systems: Windows, Linux and MacOS. It is also provided as a plugin to [Visual Studio Code](https://visualstudio.microsoft.com).
More information can be found at: [https://docs.platformio.org/en/latest/installation.html](https://docs.platformio.org/en/latest/installation.html) below the basics.
### Debian based systems command-line install
Install platformIO
```sh
sudo apt-get install python-pip
sudo pip install platformio
pio upgrade
```
### Windows, Linux and MacOS
Install [**Visual Studio code**](https://code.visualstudio.com) and install the PlatformIO plugin.
For command line usage Python and PlatformIO-Core is sufficient.
Install [Visual Studio Code](https://code.visualstudio.com) and install the PlatformIO plugin.
## Putting the ESP32-CAM in download mode
@@ -135,16 +152,27 @@ cd esp32cam-rtsp
Next, the firmware has to be build and deployed to the ESP32.
There are to flavours to do this; using the command line or the graphical interface of Visual Studio Code.
I recommend to use VIsual Studio Code as it is free to use and offers more insight.
### Using the command line
First the source code has to be compiled. Type:
Make sure you have the latest version of the Espressif toolchain.
```sh
pio pkg update -g -p espressif32
```
First the source code has to be compiled to build all targets
```sh
pio run
```
if only a specific target is required, for example the ```esp32cam_ttgo_t_journal``` type:
```sh
pio run -e esp32cam_ttgo_t_journal
```
When finished, firmware has to be uploaded.
Make sure the ESP32-CAM is in download mode (see previous section) and type:
@@ -152,6 +180,12 @@ Make sure the ESP32-CAM is in download mode (see previous section) and type:
pio run -t upload
```
or, again, for a specific target, for example ```esp32cam_ai_thinker```
```sh
pio run -t upload -e esp32cam_ai_thinker
```
When done remove the jumper when using a FTDI adapter or press the reset button on the ESP32-CAM.
To monitor the output, start a terminal using:
@@ -205,21 +239,21 @@ In case changes have been made to the configuration, this is shown and the possi
Clicking on the ```change configuration``` button will open the configuration. It is possible that a password dialog is shown before entering.
If this happens, for the user enter 'admin' and for the password the value that has been configured as the Access Point password.
## Connecting to the RTSP stream :video_camera:
## Connecting to the RTSP stream
RTSP stream is available at: [rtsp://esp32cam-rtsp.local:554/mjpeg/1](rtsp://esp32cam-rtsp.local:554/mjpeg/1).
This link can be opened with for example [VLC](https://www.videolan.org/vlc/).
## Connecting to the JPEG motion server :video_camera:
## Connecting to the JPEG motion server
The JPEG motion server server is available using a normal web browser at: [http://esp32cam-rtsp.local:/stream](http://esp32cam-rtsp.local/stream).
## Connecting to the image server :camera:
## Connecting to the image server
The image server server is available using a normal web browser at: [http://esp32cam-rtsp.local:/snapshot](http://esp32cam-rtsp.local/snapshot).
:bangbang: **Please be aware that there is no password present!**.
Everybody with access to the device can see the streams or images! Beware of :trollface:!
Everybody with network access to the device can see the streams or images! Beware of :trollface:!
## API
@@ -240,16 +274,8 @@ Calling this URL will start the form for configuring the device in the browser.
### GET: /snapshot
Calling this URL will return a JPEG snapshot of the camera in the browser.
This request can also be used (for example using cURL) to save the snapshot to a file.
### GET: /flash?v={intensity}
Calling this URL will set the intensity of the flash LED. Authentication is required.
The parameter v for the intensity must be between 0 (off) and 255 (max).
If no v parameter is present, it will be set to the value of the flash LED intensity from configuration.
## Issues / Nice to know
- The red LED on the back of the device indicates the device is not connected.
@@ -284,14 +310,22 @@ The availability of PSRAM can be seen in the HTML status overview.
Not all the boards are equipped with PSRAM:
| Board | PSRAM |
|--- |--- |
| ESP32CAM | Yes |
| ESP32CAM (USB-C) | No |
| AI THINKER | Yes |
| TTGO T-CAM | No |
| M5 STACK| | No |
| WROVER KIT | Yes |
| Board | PSRAM |
|--- |--- |
| WROVER_KIT | 8Mb |
| ESP_EYE | 8Mb |
| ESP32S3_EYE | 8Mb |
| M5STACK_PSRAM | 8Mb |
| M5STACK_V2_PSRAM | Version B only |
| M5STACK_WIDE | 8Mb |
| M5STACK_ESP32CAM | No |
| M5STACK_UNITCAM | No |
| M5STACK_UNITCAMS3 | 8Mb |
| AI_THINKER | 8Mb |
| TTGO_T_JOURNAL | No |
| ESP32_CAM_BOARD | ? |
| ESP32S2_CAM_BOARD | ? |
| ESP32S3_CAM_LCD | ? |
Depending on the image resolution, framerate and quality, the PSRAM must be enabled and/or the number of frame buffers increased to keep up with the data generated by the sensor.
There are (a lot of?) boards around with faulty PSRAM. If the camera fails to initialize, this might be a reason. See on [Reddit](https://www.reddit.com/r/esp32/comments/z2hyns/i_have_a_faulty_psram_on_my_esp32cam_what_should/).
@@ -323,6 +357,14 @@ esp32cam-rtsp depends on PlatformIO, Bootstrap 5 and Micro-RTSP by Kevin Hester.
## Change history
- January 2024
- Moved settings to board definitions
- Added new boards
- Removed OTA to increase performance
- Oktober 2023
- Added support for Seeed Xiao esp32s3
- New build system
- Updated documentation
- March 2023
- Added options to set PSRAM / Frame buffers
- Added JPEG Motion streaming

Binary file not shown.

Before

Width:  |  Height:  |  Size: 29 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 152 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 90 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 MiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 151 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 35 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 141 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 180 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 14 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 28 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 19 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 432 KiB

Binary file not shown.

Binary file not shown.

After

Width:  |  Height:  |  Size: 92 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 156 KiB

View File

@@ -0,0 +1,66 @@
{
"build": {
"arduino":{
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_AI_THINKER'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D USER_LED_GPIO=33'",
"'-D USER_LED_ON_LEVEL=LOW'",
"'-D CAMERA_CONFIG_PIN_PWDN=32'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=0'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=26'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=27'",
"'-D CAMERA_CONFIG_PIN_Y9=35'",
"'-D CAMERA_CONFIG_PIN_Y8=34'",
"'-D CAMERA_CONFIG_PIN_Y7=39'",
"'-D CAMERA_CONFIG_PIN_Y6=36'",
"'-D CAMERA_CONFIG_PIN_Y5=21'",
"'-D CAMERA_CONFIG_PIN_Y4=19'",
"'-D CAMERA_CONFIG_PIN_Y3=18'",
"'-D CAMERA_CONFIG_PIN_Y2=5'",
"'-D CAMERA_CONFIG_PIN_VSYNC=25'",
"'-D CAMERA_CONFIG_PIN_HREF=23'",
"'-D CAMERA_CONFIG_PIN_PCLK=22'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32CAM AI Thinker",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.ai-thinker.com/esp32-cam",
"vendor": "Anxinke"
}

View File

@@ -0,0 +1,63 @@
{
"build": {
"arduino": {
"ldscript": "esp32s2_out.ld"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_ESPRESSIF_ESP32S2_CAM_BOARD'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=0'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D CAMERA_CONFIG_PIN_PWDN=1'",
"'-D CAMERA_CONFIG_PIN_RESET=2'",
"'-D CAMERA_CONFIG_PIN_XCLK=42'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=41'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=18'",
"'-D CAMERA_CONFIG_PIN_Y9=16'",
"'-D CAMERA_CONFIG_PIN_Y8=39'",
"'-D CAMERA_CONFIG_PIN_Y7=40'",
"'-D CAMERA_CONFIG_PIN_Y6=15'",
"'-D CAMERA_CONFIG_PIN_Y5=12'",
"'-D CAMERA_CONFIG_PIN_Y4=5'",
"'-D CAMERA_CONFIG_PIN_Y3=13'",
"'-D CAMERA_CONFIG_PIN_Y2=14'",
"'-D CAMERA_CONFIG_PIN_VSYNC=38'",
"'-D CAMERA_CONFIG_PIN_HREF=4'",
"'-D CAMERA_CONFIG_PIN_PCLK=3'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32s2",
"variant": "esp32s2"
},
"connectivity": [
"wifi"
],
"debug": {
"openocd_target": "esp32s2.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Espressif ESP32-S2-Saola-1",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp-lyrap-cam-v1.1.html",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,63 @@
{
"build": {
"arduino": {
"ldscript": "esp32s2_out.ld"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_ESPRESSIF_ESP32S2_CAM_BOARD'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=0'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D CAMERA_CONFIG_PIN_PWDN=1'",
"'-D CAMERA_CONFIG_PIN_RESET=2'",
"'-D CAMERA_CONFIG_PIN_XCLK=42'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=41'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=18'",
"'-D CAMERA_CONFIG_PIN_Y9=16'",
"'-D CAMERA_CONFIG_PIN_Y8=39'",
"'-D CAMERA_CONFIG_PIN_Y7=40'",
"'-D CAMERA_CONFIG_PIN_Y6=15'",
"'-D CAMERA_CONFIG_PIN_Y5=13'",
"'-D CAMERA_CONFIG_PIN_Y4=5'",
"'-D CAMERA_CONFIG_PIN_Y3=12'",
"'-D CAMERA_CONFIG_PIN_Y2=14'",
"'-D CAMERA_CONFIG_PIN_VSYNC=38'",
"'-D CAMERA_CONFIG_PIN_HREF=4'",
"'-D CAMERA_CONFIG_PIN_PCLK=3'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"mcu": "esp32s2",
"variant": "esp32s2"
},
"connectivity": [
"wifi"
],
"debug": {
"openocd_target": "esp32s2.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Espressif ESP32-S2-Saola-1",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.espressif.com/projects/esp-idf/en/latest/esp32s2/hw-reference/esp32s2/user-guide-esp-lyrap-cam-v1.1.html",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,72 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "opi_opi"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_ESP32S3_CAM_LCD'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=1'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=40'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=17'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=18'",
"'-D CAMERA_CONFIG_PIN_Y9=39'",
"'-D CAMERA_CONFIG_PIN_Y8=41'",
"'-D CAMERA_CONFIG_PIN_Y7=42'",
"'-D CAMERA_CONFIG_PIN_Y6=12'",
"'-D CAMERA_CONFIG_PIN_Y5=3'",
"'-D CAMERA_CONFIG_PIN_Y4=14'",
"'-D CAMERA_CONFIG_PIN_Y3=47'",
"'-D CAMERA_CONFIG_PIN_Y2=13'",
"'-D CAMERA_CONFIG_PIN_VSYNC=21'",
"'-D CAMERA_CONFIG_PIN_HREF=38'",
"'-D CAMERA_CONFIG_PIN_PCLK=11'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dout",
"hwids": [
[
"0X303A",
"0x1001"
]
],
"mcu": "esp32s3",
"variant": "esp32s3camlcd"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32S3-CAM LCD",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.espressif.com/en/news/Maple_Eye_ESP32-S3",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,76 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_ESPRESSIF_ESP32S3_EYE'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=1'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=15'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=4'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=5'",
"'-D CAMERA_CONFIG_PIN_Y9=16'",
"'-D CAMERA_CONFIG_PIN_Y8=17'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=12'",
"'-D CAMERA_CONFIG_PIN_Y5=10'",
"'-D CAMERA_CONFIG_PIN_Y4=8'",
"'-D CAMERA_CONFIG_PIN_Y3=9'",
"'-D CAMERA_CONFIG_PIN_Y2=11'",
"'-D CAMERA_CONFIG_PIN_VSYNC=6'",
"'-D CAMERA_CONFIG_PIN_HREF=7'",
"'-D CAMERA_CONFIG_PIN_PCLK=13'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x2886",
"0x0056"
],
[
"0x2886",
"0x8056"
]
],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32S3_EYE",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.espressif.com/en/products/devkits/esp-eye/overview",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,66 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_ESPRESSIF_ESP_EYE'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D USER_LED_GPIO=14'",
"'-D USER_LED_ON_LEVEL=HIGH'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=11'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=17'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=41'",
"'-D CAMERA_CONFIG_PIN_Y9=13'",
"'-D CAMERA_CONFIG_PIN_Y8=4'",
"'-D CAMERA_CONFIG_PIN_Y7=10'",
"'-D CAMERA_CONFIG_PIN_Y6=5'",
"'-D CAMERA_CONFIG_PIN_Y5=7'",
"'-D CAMERA_CONFIG_PIN_Y4=16'",
"'-D CAMERA_CONFIG_PIN_Y3=15'",
"'-D CAMERA_CONFIG_PIN_Y2=6'",
"'-D CAMERA_CONFIG_PIN_VSYNC=42'",
"'-D CAMERA_CONFIG_PIN_HREF=18'",
"'-D CAMERA_CONFIG_PIN_PCLK=12'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=1'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM AI Thinker",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.espressif.com/en/products/devkits/esp-eye/overview",
"vendor": "Espressif"
}

View File

@@ -0,0 +1,70 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"'-D ARDUINO_ESP32S3_DEV'",
"'-D ARDUINO_USB_MODE=1'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=15'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=4'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=5'",
"'-D CAMERA_CONFIG_PIN_Y9=16'",
"'-D CAMERA_CONFIG_PIN_Y8=17'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=12'",
"'-D CAMERA_CONFIG_PIN_Y5=10'",
"'-D CAMERA_CONFIG_PIN_Y4=8'",
"'-D CAMERA_CONFIG_PIN_Y3=9'",
"'-D CAMERA_CONFIG_PIN_Y2=11'",
"'-D CAMERA_CONFIG_PIN_VSYNC=6'",
"'-D CAMERA_CONFIG_PIN_HREF=7'",
"'-D CAMERA_CONFIG_PIN_PCLK=13'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "dio",
"hwids": [
[
"0x303A",
"0x1001"
]
],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32 FREENOVE S3 WROOM",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://github.com/Freenove/Freenove_ESP32_S3_WROOM_Board",
"vendor": "Freenove"
}

View File

@@ -0,0 +1,66 @@
{
"build": {
"arduino":{
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_WROVER_KIT'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D USER_LED_GPIO=2'",
"'-D USER_LED_ON_LEVEL=HIGH'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=21'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=26'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=27'",
"'-D CAMERA_CONFIG_PIN_Y9=35'",
"'-D CAMERA_CONFIG_PIN_Y8=34'",
"'-D CAMERA_CONFIG_PIN_Y7=39'",
"'-D CAMERA_CONFIG_PIN_Y6=36'",
"'-D CAMERA_CONFIG_PIN_Y5=19'",
"'-D CAMERA_CONFIG_PIN_Y4=18'",
"'-D CAMERA_CONFIG_PIN_Y3=5'",
"'-D CAMERA_CONFIG_PIN_Y2=4'",
"'-D CAMERA_CONFIG_PIN_VSYNC=25'",
"'-D CAMERA_CONFIG_PIN_HREF=23'",
"'-D CAMERA_CONFIG_PIN_PCLK=22'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM WROVER kit",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.aliexpress.com/item/1005004960637276.html",
"vendor": "Freenove"
}

View File

@@ -0,0 +1,64 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=25'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=32'",
"'-D CAMERA_CONFIG_PIN_VSYNC=25'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=1'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_DRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D GROVE_SDA=13'",
"'-D GROVE_SCL=4'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5 STACK",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/unit/m5camera",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,66 @@
{
"build": {
"arduino":{
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK_CAMERA_PSRAM'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=25'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=32'",
"'-D CAMERA_CONFIG_PIN_VSYNC=22'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D GROVE_SDA=13'",
"'-D GROVE_SCL=4'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5 STACK",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/unit/m5camera",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,69 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK_ESP32CAM'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D USER_LED_GPIO=16'",
"'-D USER_LED_ON_LEVEL=LOW'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=25'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=17'",
"'-D CAMERA_CONFIG_PIN_VSYNC=22'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D MICROPHONE_GPIO=32'",
"'-D GROVE_SDA=13'",
"'-D GROVE_SCL=4'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5STACK ESP32CAM",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/unit/esp32cam",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,64 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK_UNITCAM'",
"'-D USER_LED_GPIO=4'",
"'-D USER_LED_ON_LEVEL=LOW'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=25'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=32'",
"'-D CAMERA_CONFIG_PIN_VSYNC=22'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=1'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_DRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5STACK UNITCAM",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/unit/unit_cam",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,84 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK_UNITCAMS3'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=1'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D USER_LED_GPIO=14'",
"'-D USER_LED_ON_LEVEL=HIGH'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=21'",
"'-D CAMERA_CONFIG_PIN_XCLK=11'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=17'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=41'",
"'-D CAMERA_CONFIG_PIN_Y9=13'",
"'-D CAMERA_CONFIG_PIN_Y8=4'",
"'-D CAMERA_CONFIG_PIN_Y7=10'",
"'-D CAMERA_CONFIG_PIN_Y6=5'",
"'-D CAMERA_CONFIG_PIN_Y5=7'",
"'-D CAMERA_CONFIG_PIN_Y4=16'",
"'-D CAMERA_CONFIG_PIN_Y3=15'",
"'-D CAMERA_CONFIG_PIN_Y2=6'",
"'-D CAMERA_CONFIG_PIN_VSYNC=42'",
"'-D CAMERA_CONFIG_PIN_HREF=18'",
"'-D CAMERA_CONFIG_PIN_PCLK=12'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_DRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D I2C_MEMS_SDA=17'",
"'-D I2C_MEMS_SCL=41'",
"'-D TF_CS=9'",
"'-D TF_MOSI=38'",
"'-D TF_CLK=39'",
"'-D TF_MISO=40'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x2886",
"0x0056"
],
[
"0x2886",
"0x8056"
]
],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5STACK UNITCAMS3",
"upload": {
"flash_size": "16MB",
"maximum_ram_size": 327680,
"maximum_size": 16777216,
"require_upload_port": true,
"speed": 460800
},
"url": "https://docs.m5stack.com/en/unit/Unit-CamS3",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,64 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_M5STACK_WIDE'",
"'-D BOARD_HAS_PSRAM'",
"'-mfix-esp32-psram-cache-issue'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=22'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=32'",
"'-D CAMERA_CONFIG_PIN_VSYNC=25'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM M5 STACK WIDE",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://shop.m5stack.com/collections/m5-cameras",
"vendor": "M5STACK"
}

View File

@@ -0,0 +1,84 @@
{
"build": {
"arduino": {
"ldscript": "esp32s3_out.ld",
"partitions": "default_8MB.csv",
"memory_type": "qio_opi"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_SEEED_XIAO_ESP32S3_SENSE'",
"'-D BOARD_HAS_PSRAM'",
"'-D ARDUINO_USB_MODE=1'",
"'-D ARDUINO_USB_CDC_ON_BOOT=1'",
"'-D ARDUINO_RUNNING_CORE=1'",
"'-D ARDUINO_EVENT_RUNNING_CORE=1'",
"'-D USER_LED_GPIO=21'",
"'-D USER_LED_ON_LEVEL=LOW'",
"'-D CAMERA_CONFIG_PIN_PWDN=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=10'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=40'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=39'",
"'-D CAMERA_CONFIG_PIN_Y9=48'",
"'-D CAMERA_CONFIG_PIN_Y8=11'",
"'-D CAMERA_CONFIG_PIN_Y7=12'",
"'-D CAMERA_CONFIG_PIN_Y6=14'",
"'-D CAMERA_CONFIG_PIN_Y5=16'",
"'-D CAMERA_CONFIG_PIN_Y4=18'",
"'-D CAMERA_CONFIG_PIN_Y3=17'",
"'-D CAMERA_CONFIG_PIN_Y2=15'",
"'-D CAMERA_CONFIG_PIN_VSYNC=38'",
"'-D CAMERA_CONFIG_PIN_HREF=47'",
"'-D CAMERA_CONFIG_PIN_PCLK=13'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=2'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_PSRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D I2C_MEMS_SDA=41'",
"'-D I2C_MEMS_SCL=42'",
"'-D TF_CS=21'",
"'-D TF_MOSI=10'",
"'-D TF_CLK=8'",
"'-D TF_MISO=9'"
],
"f_cpu": "240000000L",
"f_flash": "80000000L",
"flash_mode": "qio",
"hwids": [
[
"0x2886",
"0x0056"
],
[
"0x2886",
"0x8056"
]
],
"mcu": "esp32s3",
"variant": "esp32s3"
},
"connectivity": [
"bluetooth",
"wifi"
],
"debug": {
"openocd_target": "esp32s3.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "Seeed Studio XIAO ESP32S3 Sense",
"upload": {
"flash_size": "8MB",
"maximum_ram_size": 327680,
"maximum_size": 8388608,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.seeedstudio.com/XIAO-ESP32S3-p-5627.html",
"vendor": "Seeed Studio"
}

View File

@@ -0,0 +1,66 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_TTGO_T_CAMERA'",
"'-D CAMERA_CONFIG_PIN_PWDN=26'",
"'-D CAMERA_CONFIG_PIN_RESET=GPIO_NUM_NC'",
"'-D CAMERA_CONFIG_PIN_XCLK=32'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=13'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=12'",
"'-D CAMERA_CONFIG_PIN_Y9=39'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=23'",
"'-D CAMERA_CONFIG_PIN_Y6=18'",
"'-D CAMERA_CONFIG_PIN_Y5=15'",
"'-D CAMERA_CONFIG_PIN_Y4=4'",
"'-D CAMERA_CONFIG_PIN_Y3=14'",
"'-D CAMERA_CONFIG_PIN_Y2=5'",
"'-D CAMERA_CONFIG_PIN_VSYNC=27'",
"'-D CAMERA_CONFIG_PIN_HREF=25'",
"'-D CAMERA_CONFIG_PIN_PCLK=19'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=1'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_DRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'",
"'-D LCD_SSD1306_PIN_SDA=21'",
"'-D LCD_SSD1306_PIN_SCL=22'",
"'-D BUTTON_RIGHT_PIN=34'",
"'-D PIR_PIN=33'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM TTGO-T-CAMERA",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.lilygo.cc/products/",
"vendor": "LILYGO"
}

View File

@@ -0,0 +1,62 @@
{
"build": {
"arduino": {
"ldscript": "esp32_out.ld",
"partitions": "huge_app.csv"
},
"core": "esp32",
"extra_flags": [
"'-D ESP32CAM_TTGO_T_JOURNAL'",
"'-D CAMERA_CONFIG_PIN_PWDN=0'",
"'-D CAMERA_CONFIG_PIN_RESET=15'",
"'-D CAMERA_CONFIG_PIN_XCLK=27'",
"'-D CAMERA_CONFIG_PIN_SCCB_SDA=25'",
"'-D CAMERA_CONFIG_PIN_SCCB_SCL=23'",
"'-D CAMERA_CONFIG_PIN_Y9=19'",
"'-D CAMERA_CONFIG_PIN_Y8=36'",
"'-D CAMERA_CONFIG_PIN_Y7=18'",
"'-D CAMERA_CONFIG_PIN_Y6=39'",
"'-D CAMERA_CONFIG_PIN_Y5=5'",
"'-D CAMERA_CONFIG_PIN_Y4=34'",
"'-D CAMERA_CONFIG_PIN_Y3=35'",
"'-D CAMERA_CONFIG_PIN_Y2=17'",
"'-D CAMERA_CONFIG_PIN_VSYNC=22'",
"'-D CAMERA_CONFIG_PIN_HREF=26'",
"'-D CAMERA_CONFIG_PIN_PCLK=21'",
"'-D CAMERA_CONFIG_CLK_FREQ_HZ=20000000'",
"'-D CAMERA_CONFIG_LEDC_TIMER=LEDC_TIMER_0'",
"'-D CAMERA_CONFIG_LEDC_CHANNEL=LEDC_CHANNEL_0'",
"'-D CAMERA_CONFIG_FB_COUNT=1'",
"'-D CAMERA_CONFIG_FB_LOCATION=CAMERA_FB_IN_DRAM'",
"'-D CAMERA_CONFIG_SCCB_I2C_PORT=I2C_NUM_0'"
],
"f_cpu": "240000000L",
"f_flash": "40000000L",
"flash_mode": "dio",
"mcu": "esp32",
"variant": "esp32"
},
"connectivity": [
"wifi",
"bluetooth",
"ethernet",
"can"
],
"debug": {
"openocd_board": "esp-wroom-32.cfg"
},
"frameworks": [
"arduino",
"espidf"
],
"name": "ESP32-CAM TTGO-T-JOURNAL",
"upload": {
"flash_size": "4MB",
"maximum_ram_size": 327680,
"maximum_size": 4194304,
"require_upload_port": true,
"speed": 460800
},
"url": "https://www.lilygo.cc/products/",
"vendor": "LILYGO"
}

1
dotnet_riscv Submodule

Submodule dotnet_riscv added at 70e3cb657b

View File

@@ -1,5 +1,4 @@
. python3 -m pip install --upgrade pip setuptools wheel
. python3 -m pip install minify-html
. python3 ./minify.py ./html/index.html ./html/index.min.html
. python3 ./minify.py ./html/restart.html ./html/restart.min.html
. python3 ./minify.py ./html/index.html ./html/index.min.html

View File

@@ -3,5 +3,4 @@
python3 -m pip install --upgrade pip setuptools wheel
python3 -m pip install minify-html
python3 ./minify.py ./html/index.html ./html/index.min.html
python3 ./minify.py ./html/restart.html ./html/restart.min.html
python3 ./minify.py ./html/index.html ./html/index.min.html

View File

@@ -104,17 +104,11 @@
</h3>
</div>
{{#ConfigChanged}}
<div class="alert alert-danger">
<h3 class="text-center">
The configuration has been changed.<br>
It is recommended to restart the device.<br><br>
<button type="button" class="btn btn-danger" onclick="location.href='restart'">Restart</button>
</h3>
</div>
{{/ConfigChanged}}
<h2 class="text-center">ESP32</h2>
<div class="flex-table">
<div class="row">Board type:</div>
<div>{{BoardType}}</div>
<div class="row">SDK Version:</div>
<div>{{SDKVersion}}</div>
<div class="row">CPU model:</div>
@@ -135,8 +129,6 @@
<div class="flex-table">
<div class="row">Uptime:</div>
<div>{{Uptime}}</div>
<div class="row">Chip temperature:</div>
<div>{{Temperature}} &deg;C</div>
<div class="row">RTSP sessions:</div>
<div>{{NumRTSPSessions}}</div>
<div class="row">Free heap:</div>
@@ -145,14 +137,6 @@
<div>{{MaxAllocHeap}}</div>
</div>
<h2 class="text-center">Peripheral</h2>
<div class="flex-table">
<div class="row">Board type:</div>
<div>{{BoardType}}</div>
<div class="row">LED intensity:</div>
<div>{{LedIntensity}} [0-100]</div>
</div>
<h2 class="text-center">Network</h2>
<div class="flex-table">
<div class="row">Host name:</div>
@@ -166,9 +150,9 @@
<div class="row">Signal strength:</div>
<div>{{SignalStrength}} dbm</div>
<div class="row">IPv4 address:</div>
<div>{{IpV4}}</div>
<div>{{IPv4}}</div>
<div class="row">IPv6 address:</div>
<div>{{IpV6}}</div>
<div>{{IPv6}}</div>
</div>
{{#NetworkState.ApMode}}
@@ -191,10 +175,6 @@
<div>{{FrameSize}}</div>
<div class="row">JPEG quality:</div>
<div>{{JpegQuality}} [1-100]</div>
<div class="row">Enable PSRAM:</div>
<div>{{#EnablePSRAM}}Enabled{{/EnablePSRAM}}{{^EnablePSRAM}}Disabled{{/EnablePSRAM}}</div>
<div class="row">Number of frame buffers:</div>
<div>{{FrameBuffers}}</div>
<div class="row">Brightness:</div>
<div>{{Brightness}} [-2,2]</div>
<div class="row">Contrast:</div>
@@ -260,15 +240,11 @@
<h2 class="text-center">Special URLs / API</h2>
<div class="flex-table">
<div class="row">RTSP camera stream:</div>
<div><a href="rtsp://{{IpV4}}:{{RtspPort}}/mjpeg/1">rtsp://{{IpV4}}:{{RtspPort}}/mjpeg/1</a></div>
<div><a href="rtsp://{{IPv4}}:{{RtspPort}}/mjpeg/1">rtsp://{{IPv4}}:{{RtspPort}}/mjpeg/1</a></div>
<div class="row">JPEG Motion stream:</div>
<div><a href="http://{{IpV4}}/stream" target="_blank">http://{{IpV4}}/stream</a></div>
<div><a href="http://{{IPv4}}/stream" target="_blank" rel="noopener">http://{{IPv4}}/stream</a></div>
<div class="row">Snapshot of the camera:</div>
<div><a href="http://{{IpV4}}/snapshot " target="_blank">http://{{IpV4}}/snapshot</a> </div>
<div class="row">Intensity of the flash led (0-255):</div>
<div><a href="http://{{IpV4}}/flash?v=0">http://{{IpV4}}/flash?v=0</a> (Authentication required)</div>
<div class="row">Restart the camera:</div>
<div><a href="http://{{IpV4}}/restart">http://{{IpV4}}/restart</a> (Authentication required)</div>
<div><a href="http://{{IPv4}}/snapshot " target="_blank" rel="noopener">http://{{IPv4}}/snapshot</a> </div>
</div>
</body>

File diff suppressed because one or more lines are too long

View File

@@ -1,45 +0,0 @@
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, shrink-to-fit=no">
<meta http-equiv="refresh" content="10;url=/index.html">
<style>
html,
body {
color: #222;
font-size: 16px;
font-family: Arial, Verdana, Helvetica, sans-serif;
min-height: 100%;
}
.text-center {
text-align: center;
}
.alert-info {
color: #31708f;
background-color: #d9edf7;
border-color: #bce8f1;
}
</style>
<title>{{AppTitle}} v{{AppVersion}}</title>
</head>
<body>
<h1 class="text-center">{{ThingName}}</h1>
<hr>
<div class="alert-info">
<h3 class="text-center">Restarting</h3>
<h4 class="text-center">
The device is restarting...<br><br>
If this page takes longer than a minute, consider performing a power cycle.
</h4>
</div>
</body>
</html>

View File

@@ -1 +0,0 @@
<!doctypehtml><html lang=en><meta charset=utf-8><meta content=width=device-width,initial-scale=1,shrink-to-fit=no name=viewport><meta content=10;url=/index.html http-equiv=refresh><style>body,html{color:#222;font:16px Arial,Verdana,Helvetica,sans-serif;min-height:100%}.text-center{text-align:center}.alert-info{color:#31708f;background:#d9edf7;border:#bce8f1}</style><title>{{AppTitle}} v{{AppVersion}}</title><body><h1 class=text-center>{{ThingName}}</h1><hr><div class=alert-info><h3 class=text-center>Restarting</h3><h4 class=text-center>The device is restarting...<br><br> If this page takes longer than a minute, consider performing a power cycle.</h4></div>

View File

@@ -1,152 +0,0 @@
#pragma once
#include <string.h>
#include <esp_camera.h>
typedef struct
{
const char name[11];
const camera_config_t config;
} camera_config_entry_t;
constexpr camera_config_t esp32cam_settings = {
.pin_pwdn = -1,
.pin_reset = 15,
.pin_xclk = 27,
.pin_sscb_sda = 25,
.pin_sscb_scl = 23,
.pin_d7 = 19,
.pin_d6 = 36,
.pin_d5 = 18,
.pin_d4 = 39,
.pin_d3 = 5,
.pin_d2 = 34,
.pin_d1 = 35,
.pin_d0 = 17,
.pin_vsync = 22,
.pin_href = 26,
.pin_pclk = 21,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_SVGA,
.jpeg_quality = 12,
.fb_count = 2};
constexpr camera_config_t esp32cam_aithinker_settings = {
.pin_pwdn = 32,
.pin_reset = -1,
.pin_xclk = 0,
.pin_sscb_sda = 26,
.pin_sscb_scl = 27,
.pin_d7 = 35,
.pin_d6 = 34,
.pin_d5 = 39,
.pin_d4 = 36,
.pin_d3 = 21,
.pin_d2 = 19,
.pin_d1 = 18,
.pin_d0 = 5,
.pin_vsync = 25,
.pin_href = 23,
.pin_pclk = 22,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_1,
.ledc_channel = LEDC_CHANNEL_1,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_SVGA,
.jpeg_quality = 12,
.fb_count = 2};
constexpr camera_config_t esp32cam_ttgo_t_settings = {
.pin_pwdn = 26,
.pin_reset = -1,
.pin_xclk = 32,
.pin_sscb_sda = 13,
.pin_sscb_scl = 12,
.pin_d7 = 39,
.pin_d6 = 36,
.pin_d5 = 23,
.pin_d4 = 18,
.pin_d3 = 15,
.pin_d2 = 4,
.pin_d1 = 14,
.pin_d0 = 5,
.pin_vsync = 27,
.pin_href = 25,
.pin_pclk = 19,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_SVGA,
.jpeg_quality = 12,
.fb_count = 2};
constexpr camera_config_t esp32cam_m5stack_settings = {
.pin_pwdn = -1,
.pin_reset = 15,
.pin_xclk = 27,
.pin_sscb_sda = 25,
.pin_sscb_scl = 23,
.pin_d7 = 19,
.pin_d6 = 36,
.pin_d5 = 18,
.pin_d4 = 39,
.pin_d3 = 5,
.pin_d2 = 34,
.pin_d1 = 35,
.pin_d0 = 32,
.pin_vsync = 22,
.pin_href = 26,
.pin_pclk = 21,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_SVGA,
.jpeg_quality = 12,
.fb_count = 2};
constexpr camera_config_t esp32cam_wrover_kit_settings = {
.pin_pwdn = -1,
.pin_reset = -1,
.pin_xclk = 21,
.pin_sscb_sda = 26,
.pin_sscb_scl = 27,
.pin_d7 = 35,
.pin_d6 = 34,
.pin_d5 = 39,
.pin_d4 = 36,
.pin_d3 = 19,
.pin_d2 = 18,
.pin_d1 = 5,
.pin_d0 = 4,
.pin_vsync = 25,
.pin_href = 23,
.pin_pclk = 22,
.xclk_freq_hz = 20000000,
.ledc_timer = LEDC_TIMER_0,
.ledc_channel = LEDC_CHANNEL_0,
.pixel_format = PIXFORMAT_JPEG,
.frame_size = FRAMESIZE_SVGA,
.jpeg_quality = 12,
.fb_count = 2};
constexpr const camera_config_entry_t camera_configs[] = {
{"ESP32CAM", esp32cam_settings},
{"AI THINKER", esp32cam_aithinker_settings},
{"TTGO T-CAM", esp32cam_ttgo_t_settings},
{"M5 STACK", esp32cam_m5stack_settings},
{"WROVER KIT", esp32cam_wrover_kit_settings}};
const camera_config_t lookup_camera_config(const char *name)
{
// Lookup table for the frame name to framesize_t
for (const auto &entry : camera_configs)
if (strncmp(entry.name, name, sizeof(entry.name)) == 0)
return entry.config;
return camera_config_t{};
}

View File

@@ -5,23 +5,26 @@
#define WIFI_SSID "ESP32CAM-RTSP"
#define WIFI_PASSWORD nullptr
#define CONFIG_VERSION "1.5"
#define CONFIG_VERSION "1.6"
#define OTA_PASSWORD "ESP32CAM-RTSP"
// Time servers
#define NTP_SERVER_1 "nl.pool.ntp.org"
#define NTP_SERVER_2 "europe.pool.ntp.org"
#define NTP_SERVER_3 "time.nist.gov"
#define NTP_SERVERS NTP_SERVER_1, NTP_SERVER_2, NTP_SERVER_3
#define RTSP_PORT 554
#define DEFAULT_CAMERA_CONFIG "AI THINKER"
#define DEFAULT_ENABLE_PSRAM psramFound()
#define DEFAULT_BUFFERS (psramFound() ? 2 : 1)
#define DEFAULT_FRAME_DURATION 200
#define DEFAULT_FRAME_SIZE "VGA (640x480)"
#define DEFAULT_JPEG_QUALITY (psramFound() ? 12 : 14)
#define DEFAULT_BRIGHTNESS 0
#define DEFAULT_CONTRAST 0
#define DEFAULT_SATURATION 0
#define DEFAULT_EFFECT "Normal"
#define DEFAULT_BRIGHTNESS 0
#define DEFAULT_CONTRAST 0
#define DEFAULT_SATURATION 0
#define DEFAULT_EFFECT "Normal"
#define DEFAULT_WHITE_BALANCE true
#define DEFAULT_WHITE_BALANCE_GAIN true
#define DEFAULT_WHITE_BALANCE_MODE "Auto"
@@ -41,4 +44,4 @@
#define DEFAULT_DCW true
#define DEFAULT_COLORBAR false
#define DEFAULT_LED_INTENSITY 0
#define DEFAULT_LED_INTENSITY 0

View File

@@ -0,0 +1,18 @@
#include <stddef.h>
#include "jpg_section.h"
class jpg
{
public:
bool decode(const uint8_t *jpg, size_t size);
const jpg_section_dqt_t *quantization_table_luminance_;
const jpg_section_dqt_t *quantization_table_chrominance_;
const uint8_t *jpeg_data_start;
const uint8_t *jpeg_data_end;
private:
static const jpg_section_t *find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section_t::jpg_section_flag flag);
};

View File

@@ -0,0 +1,107 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// http://www.ietf.org/rfc/rfc2345.txt Each table is an array of 64 values given in zig-zag order, identical to the format used in a JFIF DQT marker segment.
constexpr size_t jpeg_quantization_table_length = 64;
typedef struct __attribute__((packed))
{
enum jpg_section_flag : uint8_t
{
DATA = 0x00,
SOF0 = 0xc0,
SOF1 = 0xc1,
SOF2 = 0xc2,
SOF3 = 0xc3,
DHT = 0xc4,
SOF5 = 0xc5,
SOF6 = 0xc6,
SOF7 = 0xc7,
JPG = 0xc8,
SOF9 = 0xc9,
SOF10 = 0xca,
SOF11 = 0xcb,
DAC = 0xcc,
SOF13 = 0xcd,
SOF14 = 0xce,
SOF15 = 0xcf,
RST0 = 0xd0,
RST1 = 0xd1,
RST2 = 0xd2,
RST3 = 0xd3,
RST4 = 0xd4,
RST5 = 0xd5,
RST6 = 0xd6,
RST7 = 0xd7,
SOI = 0xd8,
EOI = 0xd9,
SOS = 0xda,
DQT = 0xdb,
DNL = 0xdc,
DRI = 0xdd,
DHP = 0xde,
EXP = 0xdf,
APP0 = 0xe0,
APP1 = 0xe1,
APP2 = 0xe2,
APP3 = 0xe3,
APP4 = 0xe4,
APP5 = 0xe5,
APP6 = 0xe6,
APP7 = 0xe7,
APP8 = 0xe8,
APP9 = 0xe9,
APP10 = 0xea,
APP11 = 0xeb,
APP12 = 0xec,
APP13 = 0xed,
APP14 = 0xee,
APP15 = 0xef,
JPG0 = 0xf0,
JPG1 = 0xf1,
JPG2 = 0xf2,
JPG3 = 0xf3,
JPG4 = 0xf4,
JPG5 = 0xf5,
JPG6 = 0xf6,
JPG7 = 0xf7,
JPG8 = 0xf8,
JPG9 = 0xf9,
COM = 0xfe,
JPG10 = 0xfa,
JPG11 = 0xfb,
JPG12 = 0xfc,
JPG13 = 0xfd
};
const uint8_t framing; // 0xff
const jpg_section_flag flag;
const uint8_t length_msb;
const uint8_t length_lsb;
const uint8_t data[];
static bool is_valid_flag(const jpg_section_flag flag);
static const char *flag_name(const jpg_section_flag flag);
uint16_t data_length() const;
uint16_t section_length() const;
} jpg_section_t;
typedef struct __attribute__((packed)) // 0xffe0
{
char identifier[5] = {'J', 'F', 'I', 'F', 0}; // JFIF identifier, zero-terminated
uint8_t version_major = 1;
uint8_t version_minor = 1; // JFIF version 1.1
uint8_t density_units = 0; // no density units specified
uint16_t density_hor = 1;
uint16_t density_ver = 1; // density: 1 pixel "per pixel" horizontally and vertically
uint8_t thumbnail_hor = 0;
uint8_t thumbnail_ver = 0; // no thumbnail (size 0 x 0)
} jpg_section_app0_t;
typedef struct __attribute__((packed)) // 0xffdb
{
uint8_t id; // 0= quantLuminance, 1= quantChrominance
uint8_t data[jpeg_quantization_table_length];
} jpg_section_dqt_t;

View File

@@ -0,0 +1,14 @@
{
"name": "micro-jpg",
"version": "1.0.0",
"description": "JPEG library",
"keywords": "",
"repository": {
"type": "git",
"url": "https://github.com/rzeldent/"
},
"build": {
"srcDir": "src/",
"includeDir": "include/"
}
}

111
lib/micro-jpg/src/jpg.cpp Normal file
View File

@@ -0,0 +1,111 @@
#include <esp32-hal-log.h>
#include "jpg.h"
const jpg_section_t *jpg::find_jpg_section(const uint8_t **ptr, const uint8_t *end, jpg_section_t::jpg_section_flag flag)
{
log_d("find_jpeg_section 0x%02x (%s)", flag, jpg_section_t::flag_name(flag));
while (*ptr < end)
{
// flag, len MSB, len LSB
auto section = reinterpret_cast<const jpg_section_t *>((*ptr));
if (section->framing != 0xff)
{
log_e("Expected framing 0xff but found: 0x%02x", section->framing);
break;
}
if (!jpg_section_t::is_valid_flag(section->flag))
{
log_d("Unknown section 0x%02x", flag);
return nullptr;
}
// Advance pointer section has a length, so not SOI (0xd8) and EOI (0xd9)
*ptr += section->section_length();
if (section->flag == flag)
{
log_d("Found section 0x%02x (%s), %d bytes", flag, jpg_section_t::flag_name(section->flag), section->section_length());
return section;
}
log_d("Skipping section: 0x%02x (%s), %d bytes", section->flag, jpg_section_t::flag_name(section->flag), section->section_length());
}
// Not found
return nullptr;
}
// See https://create.stephan-brumme.com/toojpeg/
bool jpg::decode(const uint8_t *data, size_t size)
{
log_d("decode_jpeg");
// Look for start jpeg file (0xd8)
auto ptr = data;
auto end = ptr + size;
// Check for SOI (start of image) 0xff, 0xd8
if (!find_jpg_section(&ptr, end, jpg_section_t::jpg_section_flag::SOI))
{
log_e("No valid start of image marker found");
return false;
}
// First quantization table (Luminance - black & white images)
const jpg_section_t *quantization_table_section;
if (!(quantization_table_section = find_jpg_section(&ptr, end, jpg_section_t::jpg_section_flag::DQT)))
{
log_e("No quantization_table_luminance section found");
return false;
}
if (quantization_table_section->data_length() != sizeof(jpg_section_dqt_t))
{
log_w("Invalid length of quantization_table_luminance section. Expected %d but read %d", sizeof(jpg_section_dqt_t), quantization_table_section->data_length());
return false;
}
quantization_table_luminance_ = reinterpret_cast<const jpg_section_dqt_t *>(quantization_table_section->data);
// Second quantization table (Chrominance - color images)
if (!(quantization_table_section = find_jpg_section(&ptr, end, jpg_section_t::jpg_section_flag::DQT)))
{
log_w("No quantization_table_chrominance section found");
return false;
}
if (quantization_table_section->data_length() != sizeof(jpg_section_dqt_t))
{
log_w("Invalid length of quantization_table_chrominance section. Expected %d but read %d", sizeof(jpg_section_dqt_t), quantization_table_section->data_length());
return false;
}
quantization_table_chrominance_ = reinterpret_cast<const jpg_section_dqt_t *>(quantization_table_section->data);
// Start of scan
if (!find_jpg_section(&ptr, end, jpg_section_t::jpg_section_flag::SOS))
{
log_e("No start of scan section found");
return false;
}
// Start of the data sections
jpeg_data_start = ptr;
log_d("Skipping over data sections");
// Scan over all the sections. 0xff followed by not zero, is a new section
while (ptr < end - 1 && (ptr[0] != 0xff || ptr[1] == 0))
ptr++;
// Check if marker is an end of image marker
if (!find_jpg_section(&ptr, end, jpg_section_t::jpg_section_flag::EOI))
{
log_e("No end of image marker found");
return false;
}
jpeg_data_end = ptr;
log_d("Total jpeg data: %d bytes", jpeg_data_end - jpeg_data_start);
return true;
}

View File

@@ -0,0 +1,154 @@
#include "jpg_section.h"
uint16_t jpg_section_t::data_length() const
{
return (length_msb << 8) + length_lsb - sizeof(jpg_section_t::length_msb)- sizeof(jpg_section_t::length_lsb);
}
uint16_t jpg_section_t::section_length() const
{
return flag == SOI || flag == EOI ? sizeof(jpg_section_t::framing) + sizeof(jpg_section_t::flag) : sizeof(jpg_section_t::framing) + sizeof(jpg_section_t::flag) + (length_msb << 8) + length_lsb;
}
bool jpg_section_t::is_valid_flag(const jpg_section_flag flag)
{
return flag >= SOF0 && flag <= COM;
}
// from: https://www.disktuna.com/list-of-jpeg-markers/
const char *jpg_section_t::flag_name(const jpg_section_flag flag)
{
switch (flag)
{
case DATA:
return "DATA"; // DATA
case SOF0:
return "SOF0"; // Start of Frame 0 Baseline DCT
case SOF1:
return "SOF1"; // Start of Frame 1 Extended Sequential DCT
case SOF2:
return "SOF2"; // Start of Frame 2 Progressive DCT
case SOF3:
return "SOF3"; // Start of Frame 3 Lossless (sequential)
case DHT:
return "DHT"; // Define Huffman Table
case SOF5:
return "SOF5"; // Start of Frame 5 Differential sequential DCT
case SOF6:
return "SOF6"; // Start of Frame 6 Differential progressive DCT
case SOF7:
return "SOF7"; // Start of Frame 7 Differential lossless (sequential)
case JPG:
return "JPG"; // JPEG Extensions
case SOF9:
return "SOF9"; // Start of Frame 9 Extended sequential DCT, Arithmetic coding
case SOF10:
return "SOF10"; // Start of Frame 10 Progressive DCT, Arithmetic coding
case SOF11:
return "SOF11"; // Start of Frame 11 Lossless (sequential), Arithmetic coding
case DAC:
return "DAC"; // Define Arithmetic Coding
case SOF13:
return "SOF13"; // Start of Frame 13 Differential sequential DCT, Arithmetic coding
case SOF14:
return "SOF14"; // Start of Frame 14 Differential progressive DCT, Arithmetic coding
case SOF15:
return "SOF15"; // Start of Frame 15 Differential lossless (sequential), Arithmetic coding
case RST0:
return "RST0"; // Restart Marker 0
case RST1:
return "RST1"; // Restart Marker 1
case RST2:
return "RST2"; // Restart Marker 2
case RST3:
return "RST3"; // Restart Marker 3
case RST4:
return "RST4"; // Restart Marker 4
case RST5:
return "RST5"; // Restart Marker 5
case RST6:
return "RST6"; // Restart Marker 6
case RST7:
return "RST7"; // Restart Marker 7
case SOI:
return "SOI"; // Start of Image
case EOI:
return "EOI"; // End of Image
case SOS:
return "SOS"; // Start of Scan
case DQT:
return "DQT"; // Define Quantization Table
case DNL:
return "DNL"; // Define Number of Lines (Not common)
case DRI:
return "DRI"; // Define Restart Interval
case DHP:
return "DHP"; // Define Hierarchical Progression (Not common)
case EXP:
return "EXP"; // Expand Reference Component (Not common)
case APP0:
return "APP0"; // Application Segment 0 JFIF JFIF JPEG image, AVI1 Motion JPEG (MJPG)
case APP1:
return "APP1"; // Application Segment 1 EXIF Metadata, TIFF IFD format, JPEG Thumbnail (160×120) Adobe XMP
case APP2:
return "APP2"; // Application Segment 2 ICC color profile, FlashPix
case APP3:
return "APP3"; // Application Segment 3 (Not common) JPS Tag for Stereoscopic JPEG images
case APP4:
return "APP4"; // Application Segment 4 (Not common)
case APP5:
return "APP5"; // Application Segment 5 (Not common)
case APP6:
return "APP6"; // Application Segment 6 (Not common) NITF Lossles profile
case APP7:
return "APP7"; // Application Segment 7 (Not common)
case APP8:
return "APP8"; // Application Segment 8 (Not common)
case APP9:
return "APP9"; // Application Segment 9 (Not common)
case APP10:
return "APP10"; // Application Segment 10 PhoTags (Not common) ActiveObject (multimedia messages / captions)
case APP11:
return "APP11"; // Application Segment 11 (Not common) HELIOS JPEG Resources (OPI Postscript)
case APP12:
return "APP12"; // Application Segment 12 Picture Info (older digicams), Photoshop Save for Web: Ducky
case APP13:
return "APP13"; // Application Segment 13 Photoshop Save As: IRB, 8BIM, IPTC
case APP14:
return "APP14"; // Application Segment 14 (Not common)
case APP15:
return "APP15"; // Application Segment 15 (Not common)
case JPG0:
return "JPG0"; // JPEG Extension 0
case JPG1:
return "JPG1"; // JPEG Extension 1
case JPG2:
return "JPG2"; // JPEG Extension 2
case JPG3:
return "JPG3"; // JPEG Extension 3
case JPG4:
return "JPG4"; // JPEG Extension 4
case JPG5:
return "JPG5"; // JPEG Extension 5
case JPG6:
return "JPG6"; // JPEG Extension 6
case JPG7:
return "JPG7"; // SOF48 JPEG Extension 7 JPEG-LS Lossless JPEG
case JPG8:
return "JPG8"; // LSE JPEG Extension 8 JPEG-LS Extension Lossless JPEG Extension Parameters
case JPG9:
return "JPG9"; // JPEG Extension 9 (Not common)
case JPG10:
return "JPG10"; // JPEG Extension 10 (Not common)
case JPG11:
return "JPG11"; // JPEG Extension 11 (Not common)
case JPG12:
return "JPG12"; // JPEG Extension 12 (Not common)
case JPG13:
return "JPG13"; // JPEG Extension 13 (Not common)
case COM:
return "COM"; // Comment
}
return "Unknown";
}

View File

@@ -0,0 +1,25 @@
#pragma once
#include <micro_rtsp_source.h>
#include <esp_camera.h>
class micro_rtsp_camera : public micro_rtsp_source
{
public:
micro_rtsp_camera();
virtual ~micro_rtsp_camera();
esp_err_t initialize(camera_config_t *camera_config);
esp_err_t deinitialize();
virtual void update_frame();
virtual uint8_t *data() const { return fb_->buf; }
virtual size_t width() const { return fb_->width; }
virtual size_t height() const { return fb_->height; }
virtual size_t size() const { return fb_->len; }
private:
esp_err_t init_result_;
camera_fb_t *fb_;
};

View File

@@ -0,0 +1,56 @@
#pragma once
#include <map>
#include <string>
class micro_rtsp_requests
{
public:
std::string process_request(const std::string& request);
bool active() const { return stream_active_; }
private:
// enum rtsp_command
// {
// rtsp_command_unknown,
// rtsp_command_options, // OPTIONS
// rtsp_command_describe, // DESCRIBE
// rtsp_command_setup, // SETUP
// rtsp_command_play, // PLAY
// rtsp_command_teardown // TEARDOWN
// };
static const std::string available_stream_name_;
//rtsp_command parse_command(const std::string &request);
//static bool parse_cseq(const std::string &line, unsigned long &cseq);
bool parse_client_port(const std::string &request);
//bool parse_stream_url(const std::string &request);
//static std::string date_header();
static std::string handle_rtsp_error(unsigned long cseq, unsigned short code, const std::string &message);
static std::string handle_options(unsigned long cseq);
static std::string handle_describe(unsigned long cseq, const std::string &request);
std::string handle_setup(unsigned long cseq, const std::map<std::string, std::string> &request);
std::string handle_play(unsigned long cseq);
std::string handle_teardown(unsigned long cseq);
//unsigned long cseq_;
// std::string host_url_;
// unsigned short host_port_;
// std::string stream_name_;
bool tcp_transport_;
unsigned short start_client_port_;
unsigned short end_client_port_;
unsigned short rtp_streamer_port_;
unsigned short rtcp_streamer_port_;
unsigned long rtsp_session_id_;
bool stream_active_;
bool stream_stopped_;
};

View File

@@ -0,0 +1,45 @@
#pragma once
#include <Arduino.h>
#include <WiFiServer.h>
#include <string>
#include <list>
#include "micro_rtsp_camera.h"
#include "micro_rtsp_requests.h"
#include "micro_rtsp_streamer.h"
class micro_rtsp_server : WiFiServer
{
public:
micro_rtsp_server(micro_rtsp_source &source);
~micro_rtsp_server();
void begin(unsigned short port = 554);
void end();
unsigned get_frame_interval() const { return frame_interval_; }
unsigned set_frame_interval(unsigned value) { return frame_interval_ = value; }
void loop();
size_t clients() const { return clients_.size(); }
class rtsp_client : public WiFiClient, public micro_rtsp_requests
{
public:
rtsp_client(const WiFiClient &client);
~rtsp_client();
void handle_request();
};
private:
micro_rtsp_source &source_;
unsigned frame_interval_;
unsigned long next_frame_update_;
unsigned long next_check_client_;
micro_rtsp_streamer streamer_;
std::list<rtsp_client> clients_;
};

View File

@@ -0,0 +1,16 @@
#pragma once
#include <stddef.h>
#include <stdint.h>
// Interface for a video source
class micro_rtsp_source
{
public:
virtual void update_frame() = 0;
virtual uint8_t *data() const = 0;
virtual size_t width() const = 0;
virtual size_t height() const = 0;
virtual size_t size() const = 0;
};

View File

@@ -0,0 +1,43 @@
#pragma once
#include <jpg_section.h>
#include <micro_rtsp_camera.h> // Add this line to include the definition of micro_rtsp_camera
#include <micro_rtsp_structs.h>
// https://en.wikipedia.org/wiki/Maximum_transmission_unit
constexpr size_t max_wifi_mtu = 2304;
// Payload JPG - https://www.ietf.org/rfc/rfc1890.txt
constexpr uint8_t RTP_PAYLOAD_JPG = 26;
// One of the types below will be returned, the jpeg_packet_with_quantization_t for the first packet, then the jpeg_packet_t
typedef struct __attribute__((packed))
{
rtp_over_tcp_hdr_t rtp_over_tcp_hdr;
rtp_hdr_t rtp_hdr;
jpeg_hdr_t jpeg_hdr;
jpeg_hdr_qtable_t jpeg_hdr_qtable;
uint8_t quantization_table_luminance[jpeg_quantization_table_length];
uint8_t quantization_table_chrominance[jpeg_quantization_table_length];
uint8_t jpeg_data[];
} jpeg_packet_with_quantization_t;
typedef struct __attribute__((packed))
{
rtp_over_tcp_hdr_t rtp_over_tcp_hdr;
rtp_hdr_t rtp_hdr;
jpeg_hdr_t jpeg_hdr;
uint8_t jpeg_data[];
} jpeg_packet_t;
class micro_rtsp_streamer
{
public:
micro_rtsp_streamer(const micro_rtsp_source& source);
rtp_over_tcp_hdr_t *create_jpg_packet(const uint8_t *jpg_scan, const uint8_t *jpg_scan_end, uint8_t **jpg_offset, const uint32_t timestamp, const uint8_t *quantization_table_luminance, const uint8_t *quantization_table_chrominance);
private:
const micro_rtsp_source& source_;
uint32_t ssrc_;
uint16_t sequence_number_;
};

View File

@@ -0,0 +1,51 @@
#pragma once
#include <stdint.h>
// https://www.ietf.org/rfc/rfc2326#section-10.12
typedef struct __attribute__((packed))
{
char magic = '$'; // Magic encapsulation ASCII dollar sign (24 hexadecimal)
uint8_t channel; // Channel identifier
uint16_t length; // Network order
} rtp_over_tcp_hdr_t;
// RTP data header - http://www.ietf.org/rfc/rfc3550.txt
typedef struct __attribute__((packed))
{
uint16_t version : 2; // protocol version
uint16_t padding : 1; // padding flag
uint16_t extension : 1; // header extension flag
uint16_t cc : 4; // CSRC count
uint16_t marker : 1; // marker bit
uint16_t pt : 7; // payload type
uint16_t seq : 16; // sequence number
uint32_t ts; // timestamp
uint32_t ssrc; // synchronization source
} rtp_hdr_t;
// https://datatracker.ietf.org/doc/html/rfc2435
typedef struct __attribute__((packed))
{
uint32_t tspec : 8; // type-specific field
uint32_t off : 24; // fragment byte offset
uint8_t type; // id of jpeg decoder params
uint8_t q; // Q values 0-127 indicate the quantization tables. JPEG types 0 and 1 (and their corresponding types 64 and 65)
uint8_t width; // frame width in 8 pixel blocks
uint8_t height; // frame height in 8 pixel blocks
} jpeg_hdr_t;
typedef struct __attribute__((packed))
{
uint16_t dri;
uint16_t f : 1;
uint16_t l : 1;
uint16_t count : 14;
} jpeg_hdr_rst_t;
typedef struct __attribute__((packed))
{
uint8_t mbz;
uint8_t precision;
uint16_t length;
} jpeg_hdr_qtable_t;

View File

@@ -0,0 +1,20 @@
{
"name": "micro-rtsp-streamer",
"version": "1.0.0",
"description": "RTSP Server",
"keywords": "",
"repository": {
"type": "git",
"url": "https://github.com/rzeldent/micro-rtsp-streamer"
},
"build": {
"srcDir": "src/",
"includeDir": "include/"
},
"dependencies": {
"micro-jpg": "^1.0.0",
"espressif/esp32-camera": "^2.0.4"
}
}

View File

@@ -0,0 +1,39 @@
#include <esp32-hal-log.h>
#include "micro_rtsp_camera.h"
micro_rtsp_camera::micro_rtsp_camera()
{
init_result_ == ESP_FAIL;
}
micro_rtsp_camera::~micro_rtsp_camera()
{
deinitialize();
}
esp_err_t micro_rtsp_camera::initialize(camera_config_t *camera_config)
{
log_v("camera_config={.pin_pwdn:%u,.pin_reset:%u,.pin_xclk:%u,.pin_sccb_sda:%u,.pin_sccb_scl:%u,.pin_d7:%u,.pin_d6:%u,.pin_d5:%u,.pin_d4:%u,.pin_d3:%u,.pin_d2:%u,.pin_d1:%u,.pin_d0:%u,.pin_vsync:%u,.pin_href:%u,.pin_pclk:%u,.xclk_freq_hz:%d,.ledc_timer:%u,ledc_channel:%u,.pixel_format:%d,.frame_size:%d,.jpeg_quality:%d,.fb_count:%d,.fb_location%d,.grab_mode:%d,sccb_i2c_port:%d}", camera_config->pin_pwdn, camera_config->pin_reset, camera_config->pin_xclk, camera_config->pin_sccb_sda, camera_config->pin_sccb_scl, camera_config->pin_d7, camera_config->pin_d6, camera_config->pin_d5, camera_config->pin_d4, camera_config->pin_d3, camera_config->pin_d2, camera_config->pin_d1, camera_config->pin_d0, camera_config->pin_vsync, camera_config->pin_href, camera_config->pin_pclk, camera_config->xclk_freq_hz, camera_config->ledc_timer, camera_config->ledc_channel, camera_config->pixel_format, camera_config->frame_size, camera_config->jpeg_quality, camera_config->fb_count, camera_config->fb_location, camera_config->grab_mode, camera_config->sccb_i2c_port);
init_result_ = esp_camera_init(camera_config);
if (init_result_ == ESP_OK)
update_frame();
else
log_e("Camera initialization failed: 0x%02x", init_result_);
return init_result_;
}
esp_err_t micro_rtsp_camera::deinitialize()
{
return init_result_ == ESP_OK ? esp_camera_deinit() : ESP_OK;
}
void micro_rtsp_camera::update_frame()
{
if (fb_)
esp_camera_fb_return(fb_);
fb_ = esp_camera_fb_get();
}

View File

@@ -0,0 +1,217 @@
#include <esp32-hal-log.h>
#include <iomanip>
#include <unordered_map>
#include <regex>
#include "micro_rtsp_requests.h"
// https://datatracker.ietf.org/doc/html/rfc2326
const std::string micro_rtsp_requests::available_stream_name_ = "/mjpeg/1";
bool micro_rtsp_requests::parse_client_port(const std::string &request)
{
log_v("request: %s", request.c_str());
std::regex regex("client_port=([0-9]+)", std::regex_constants::icase);
std::smatch match;
if (!std::regex_match(request, match, regex))
{
log_e("client_port not found");
return false;
}
start_client_port_ = std::stoi(match[1].str());
return true;
}
std::string micro_rtsp_requests::handle_rtsp_error(unsigned long cseq, unsigned short code, const std::string &message)
{
log_e("code: %d, message: %s", code, message.c_str());
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 " << code << " " << message << "\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n";
return oss.str();
}
// OPTIONS rtsp://192.168.178.247:554/mjpeg/1 RTSP/1.0
// CSeq: 2
// User-Agent: LibVLC/3.0.20 (LIVE555 Streaming Media v2016.11.28)
std::string micro_rtsp_requests::handle_options(unsigned long cseq)
{
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 200 OK\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n"
<< "Content-Length: 0\r\n"
<< "Public: DESCRIBE, SETUP, TEARDOWN, PLAY, PAUSE\r\n"
<< "\r\n";
return oss.str();
}
// DESCRIBE rtsp://192.168.178.247:554/mjpeg/1 RTSP/1.0
// CSeq: 3
// User-Agent: LibVLC/3.0.20 (LIVE555 Streaming Media v2016.11.28)
// Accept: application/sdp
std::string micro_rtsp_requests::handle_describe(unsigned long cseq, const std::string &request)
{
// Parse the url
static const std::regex regex_url("rtsp:\\/\\/([^\\/:]+)(?::(\\d+))?(\\/.*)?\\s+RTSP\\/1\\.0", std::regex_constants::icase);
std::smatch match;
if (!std::regex_search(request, match, regex_url))
return handle_rtsp_error(cseq, 400, "Invalid URL");
auto host = match[1].str();
auto port = match[2].str().length() > 0 ? std::stoi(match[2].str()) : 554;
auto path = match[3].str();
log_i("host: %s, port: %d, path: %s", host.c_str(), port, path.c_str());
if (path != available_stream_name_)
return handle_rtsp_error(cseq, 404, "Stream Not Found");
std::ostringstream osbody;
osbody << "v=0\r\n"
<< "o=- " << std::rand() << " 1 IN IP4 " << host << "\r\n"
<< "s=\r\n"
<< "t=0 0\r\n" // start / stop - 0 -> unbounded and permanent session
<< "m=video 0 RTP/AVP 26\r\n" // currently we just handle UDP sessions
<< "c=IN IP4 0.0.0.0\r\n";
auto body = osbody.str();
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 200 OK\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n"
<< "Content-Base: rtsp://" << host << ":" << port << path << "/" << "\r\n"
<< "Content-Type: application/sdp\r\n"
<< "Content-Length: " << body.size() << "\r\n"
<< "\r\n"
<< body;
return oss.str();
}
// SETUP rtsp://192.168.178.247:554/mjpeg/1 RTSP/1.0
// CSeq: 0
// Transport: RTP/AVP;unicast;client_port=9058-9059
std::string micro_rtsp_requests::handle_setup(unsigned long cseq, const std::map<std::string, std::string> &lines)
{
log_v("request: %s", request.c_str());
auto it = lines.find("Transport");
if (it == lines.end())
return handle_rtsp_error(cseq, 400, "No Transport Header Found");
static const std::regex regex_transport("\\s+RTP\\/AVP(\\/TCP)?;unicast;client_port=(\\d+)-(\\d+)", std::regex_constants::icase);
std::smatch match;
if (!std::regex_search(it->second, match, regex_transport))
return handle_rtsp_error(cseq, 400, "Could Not Parse Transport");
tcp_transport_ = match[1].str().length() > 0;
start_client_port_ = std::stoi(match[2].str());
end_client_port_ = std::stoi(match[3].str());
log_i("tcp_transport: %d, start_client_port: %d, end_client_port: %d", tcp_transport_, start_client_port_, end_client_port_);
std::ostringstream ostransport;
if (tcp_transport_)
ostransport << "RTP/AVP/TCP;unicast;interleaved=0-1";
else
ostransport << "RTP/AVP;unicast;destination=127.0.0.1;source=127.0.0.1;client_port=" << start_client_port_ << "-" << end_client_port_ + 1 << ";server_port=" << rtp_streamer_port_ << "-" << rtp_streamer_port_/*rtcp_streamer_port_*/;
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 200 OK\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n"
<< "Transport: " << ostransport.str() << "\r\n"
<< "Session: " << rtsp_session_id_<< "\r\n";
return oss.str();
}
std::string micro_rtsp_requests::handle_play(unsigned long cseq)
{
log_v("request: %s", request.c_str());
stream_active_ = true;
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 200 OK\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n"
<< "Range: npt=0.000-\r\n"
<< "Session: " << rtsp_session_id_ << "\r\n"
<< "RTP-Info: url=rtsp://127.0.0.1:8554" << available_stream_name_ << "/track1" << "\r\n"
<< "\r\n";
return oss.str();
}
std::string micro_rtsp_requests::handle_teardown(unsigned long cseq)
{
log_v("request: %s", request.c_str());
stream_stopped_ = true;
auto now = time(nullptr);
std::ostringstream oss;
oss << "RTSP/1.0 200 OK\r\n"
<< "CSeq: " << cseq << "\r\n"
<< std::put_time(std::gmtime(&now), "Date: %a, %b %d %Y %H:%M:%S GMT") << "\r\n"
<< "\r\n";
return oss.str();
}
// Parse a request e.g.
// Request: OPTIONS rtsp://192.168.178.247:554/mjpeg/1 RTSP/1.0
// CSeq: 2
// User-Agent: LibVLC/3.0.20 (LIVE555 Streaming Media v2016.11.28)
std::string micro_rtsp_requests::process_request(const std::string &request)
{
log_v("request: %s", request.c_str());
std::stringstream ss(request);
// Get the request line
std::string request_line;
if (!std::getline(ss, request_line))
return handle_rtsp_error(0, 400, "No Request Found");
// Create a map with headers
std::string line;
std::map<std::string, std::string> headers;
std::size_t pos;
while (std::getline(ss, line))
{
if ((pos = line.find(':')) != std::string::npos)
headers[line.substr(0, pos)] = line.substr(pos + 1);
// else
// log_e("No : found for header: %s", line.c_str());
}
log_i("request_line: %s", request_line.c_str());
for (const auto &header : headers)
log_i("header: %s: %s", header.first.c_str(), header.second.c_str());
// Check for CSeq
const auto cseq_it = headers.find("CSeq");
if (cseq_it == headers.end())
return handle_rtsp_error(0, 400, "No Sequence Found");
auto cseq = std::stoul(cseq_it->second);
if (request_line.find("OPTIONS") == 0)
return handle_options(cseq);
if (request_line.find("DESCRIBE") == 0)
return handle_describe(cseq, request_line);
if (request_line.find("SETUP") == 0)
return handle_setup(cseq, headers);
if (request_line.find("PLAY") == 0)
return handle_play(cseq);
if (request_line.find("TEARDOWN") == 0)
return handle_teardown(cseq);
return handle_rtsp_error(cseq, 400, "Unknown Command or malformed request");
}

View File

@@ -0,0 +1,108 @@
#include <micro_rtsp_server.h>
#include <jpg.h>
#include <vector>
#include <memory>
// Check client connections every 100 milliseconds
#define CHECK_CLIENT_INTERVAL 10
micro_rtsp_server::micro_rtsp_server(micro_rtsp_source &source)
: source_(source), streamer_(source)
{
}
micro_rtsp_server::~micro_rtsp_server()
{
end();
}
void micro_rtsp_server::begin(unsigned short port /*= 554*/)
{
WiFiServer::begin(port);
}
void micro_rtsp_server::end()
{
WiFiServer::end();
}
void micro_rtsp_server::loop()
{
auto now = millis();
if (next_check_client_ < now)
{
log_v("Check for new client");
next_check_client_ = now + CHECK_CLIENT_INTERVAL;
// Check if a client wants to connect
auto client = accept();
if (client)
clients_.push_back(rtsp_client(client));
// Check for idle clients
clients_.remove_if([](rtsp_client &c)
{ return !c.connected(); });
for (auto client : clients_)
client.handle_request();
}
if (next_frame_update_ < now)
{
log_v("Stream frame t=%d", next_frame_update_);
next_frame_update_ = now + frame_interval_;
auto ts = time(nullptr);
// Get next jpg frame
source_.update_frame();
// Decode to get quantitation- and scan data
jpg jpg;
auto jpg_data = source_.data();
auto jpg_size = source_.size();
assert(jpg.decode(jpg_data, jpg_size));
auto jpg_scan_current = (uint8_t *)jpg.jpeg_data_start;
while (jpg_scan_current < jpg.jpeg_data_end)
{
auto packet = streamer_.create_jpg_packet(jpg.jpeg_data_start, jpg.jpeg_data_end, &jpg_scan_current, ts, jpg.quantization_table_luminance_->data, jpg.quantization_table_chrominance_->data);
for (auto client : clients_)
{
log_i("Stream frame to client: 0x%08x", client);
// RTP over TCP encapsulates in a $
client.write((const uint8_t *)packet, packet->length + sizeof(rtp_over_tcp_hdr_t));
// TODO: UDP
}
free(packet);
}
}
}
micro_rtsp_server::rtsp_client::rtsp_client(const WiFiClient &wifi_client)
: WiFiClient(wifi_client)
{
}
micro_rtsp_server::rtsp_client::~rtsp_client()
{
stop();
}
void micro_rtsp_server::rtsp_client::handle_request()
{
// Read if data available
auto bytes_available = available();
if (bytes_available > 0)
{
std::string request(bytes_available, '\0');
if (read((uint8_t *)&request[0], bytes_available) == bytes_available)
{
request.resize(bytes_available);
log_i("Request: %s", request.c_str());
auto response = process_request(request);
log_i("Response: %s", response.c_str());
println(response.c_str());
println();
}
}
}

View File

@@ -0,0 +1,82 @@
#include <stddef.h>
#include <memory.h>
#include <esp32-hal-log.h>
#include "micro_rtsp_streamer.h"
#include "esp_random.h"
micro_rtsp_streamer::micro_rtsp_streamer(const micro_rtsp_source &source)
: source_(source)
{
// Random number
ssrc_ = esp_random();
sequence_number_ = 0;
}
rtp_over_tcp_hdr_t *micro_rtsp_streamer::create_jpg_packet(const uint8_t *jpg_scan, const uint8_t *jpg_scan_end, uint8_t **jpg_offset, const uint32_t timestamp, const uint8_t *quantization_table_luminance, const uint8_t *quantization_table_chrominance)
{
log_v("jpg_scan:0x%08x, jpg_scan_end:0x%08x, jpg_offset:0x%08x, timestamp:%d, quantization_table_luminance:0x%08x, quantization_table_chrominance:0x%08x", jpg_scan, jpg_scan_end, jpg_offset, timestamp, quantization_table_luminance, quantization_table_chrominance);
// The MTU of wireless networks is 2,312 bytes. This size includes the packet headers.
const auto isFirstFragment = jpg_scan == *jpg_offset;
const auto include_quantization_tables = isFirstFragment && quantization_table_luminance != nullptr && quantization_table_chrominance != nullptr;
// Quantization tables musty be included in the first packet
const auto headers_size = include_quantization_tables ? sizeof(jpeg_packet_with_quantization_t) : sizeof(jpeg_packet_t);
const auto payload_size = max_wifi_mtu - headers_size;
const auto jpg_bytes_left = jpg_scan_end - *jpg_offset;
const bool isLastFragment = jpg_bytes_left <= payload_size;
const auto jpg_bytes = isLastFragment ? jpg_bytes_left : payload_size;
const uint16_t packet_size = headers_size + jpg_bytes;
const auto packet = static_cast<jpeg_packet_t *>(calloc(1, packet_size));
// 4 bytes RTP over TCP header
packet->rtp_over_tcp_hdr.channel = 0;
packet->rtp_over_tcp_hdr.length = packet_size;
log_v("rtp_over_tcp_hdr_t={.magic=%c,.channel=%u,.length=%u}", packet->rtp_over_tcp_hdr.magic, packet->rtp_over_tcp_hdr.channel, packet->rtp_over_tcp_hdr.length);
// 12 bytes RTP header
packet->rtp_hdr.version = 2;
packet->rtp_hdr.marker = isLastFragment;
packet->rtp_hdr.pt = RTP_PAYLOAD_JPG;
packet->rtp_hdr.seq = sequence_number_;
packet->rtp_hdr.ts = timestamp;
packet->rtp_hdr.ssrc = ssrc_;
log_v("rtp_hdr={.version:%u,.padding:%u,.extension:%u,.cc:%u,.marker:%u,.pt:%u,.seq:%u,.ts:%u,.ssrc:%u}", packet->rtp_hdr.version, packet->rtp_hdr.padding, packet->rtp_hdr.extension, packet->rtp_hdr.cc, packet->rtp_hdr.marker, packet->rtp_hdr.pt, packet->rtp_hdr.seq, packet->rtp_hdr.ts, packet->rtp_hdr.ssrc);
// 8 bytes JPEG payload header
packet->jpeg_hdr.tspec = 0; // type-specific field
packet->jpeg_hdr.off = (uint32_t)(*jpg_offset - jpg_scan); // fragment byte offset (24 bits in jpg)
packet->jpeg_hdr.type = 0; // id of jpeg decoder params
packet->jpeg_hdr.q = (uint8_t)(include_quantization_tables ? 0x80 : 0x5e); // quantization factor (or table id) 5eh=94d
packet->jpeg_hdr.width = (uint8_t)(source_.width() >> 3); // frame width in 8 pixel blocks
packet->jpeg_hdr.height = (uint8_t)(source_.height() >> 3); // frame height in 8 pixel blocks
log_v("jpeg_hdr={.tspec:%u,.off:0x%6x,.type:0x2%x,.q:%u,.width:%u.height:%u}", packet->jpeg_hdr.tspec, packet->jpeg_hdr.off, packet->jpeg_hdr.type, packet->jpeg_hdr.q, packet->jpeg_hdr.width, packet->jpeg_hdr.height);
// Only in first packet of the frame
if (include_quantization_tables)
{
auto packet_with_quantization = reinterpret_cast<jpeg_packet_with_quantization_t *>(packet);
packet_with_quantization->jpeg_hdr_qtable.mbz = 0;
packet_with_quantization->jpeg_hdr_qtable.precision = 0; // 8 bit precision
packet_with_quantization->jpeg_hdr_qtable.length = jpeg_quantization_table_length + jpeg_quantization_table_length;
log_v("jpeg_hdr_qtable={.mbz:%u,.precision:%u,.length:%u}", packet_with_quantization->jpeg_hdr_qtable.mbz, packet_with_quantization->jpeg_hdr_qtable.precision, packet_with_quantization->jpeg_hdr_qtable.length);
memcpy(packet_with_quantization->quantization_table_luminance, quantization_table_luminance, jpeg_quantization_table_length);
memcpy(packet_with_quantization->quantization_table_chrominance, quantization_table_chrominance, jpeg_quantization_table_length);
// Copy JPG data
memcpy(packet_with_quantization->jpeg_data, *jpg_offset, jpg_bytes);
}
else
{
// Copy JPG data
memcpy(packet->jpeg_data, *jpg_offset, jpg_bytes);
}
// Update JPG offset
*jpg_offset += jpg_bytes;
// Update sequence number
sequence_number_++;
return (rtp_over_tcp_hdr_t *)packet;
}

View File

@@ -1,8 +1,8 @@
{
"name": "RTSPServer",
"version": "1.0.0",
"description": "",
"description": "RTSP Server",
"dependencies": {
"contrem/arduino-timer": "^2.3.1"
}
}
}

View File

@@ -29,7 +29,7 @@ private:
std::shared_ptr<CRtspSession> session;
};
OV2640 cam_;
OV2640 cam_;
std::list<std::unique_ptr<rtsp_client>> clients_;
uintptr_t task_;
Timer<> timer_;

View File

@@ -8,38 +8,107 @@
; Please visit documentation for the other options and examples
; https://docs.platformio.org/page/projectconf.html
[env:esp32cam]
###############################################################################
[platformio]
default_envs = esp32cam_ai_thinker
#default_envs = esp32cam_espressif_esp_eye
#default_envs = esp32cam_espressif_esp32s2_cam_board
#default_envs = esp32cam_espressif_esp32s2_cam_header
#default_envs = esp32cam_espressif_esp32s3_cam_lcd
#default_envs = esp32cam_espressif_esp32s3_eye
#default_envs = esp32cam_freenove_wrover_kit
#default_envs = esp32cam_m5stack_camera_psram
#default_envs = esp32cam_m5stack_camera
#default_envs = esp32cam_m5stack_esp32cam
#default_envs = esp32cam_m5stack_unitcam
#default_envs = esp32cam_m5stack_unitcams3
#default_envs = esp32cam_m5stack_wide
#default_envs = esp32cam_seeed_xiao_esp32s3_sense
#default_envs = esp32cam_ttgo_t_camera
#default_envs = esp32cam_ttgo_t_journal
[env]
platform = espressif32
board = esp32cam
framework = arduino
test_framework = unity
#upload_protocol = espota
#upload_port = 192.168.50.222
#upload_flags =
# --auth='ESP32CAM-RTSP'
#upload_port = 192.168.178.223
#upload_flags = --auth='ESP32CAM-RTSP'
# Partition scheme for OTA
board_build.partitions = min_spiffs.csv
#board_build.partitions = max_spiffs.csv
monitor_speed = 115200
monitor_rts = 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 =
-O2
-D CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_VERBOSE
-D LED_FLASH=4
-D LED_BUILTIN=33
-D BOARD_HAS_PSRAM
-mfix-esp32-psram-cache-issue
-D IOTWEBCONF_PASSWORD_LEN=64
-Ofast
-D 'BOARD_NAME="${this.board}"'
-D 'CORE_DEBUG_LEVEL=ARDUHAL_LOG_LEVEL_INFO'
-D 'IOTWEBCONF_PASSWORD_LEN=64'
board_build.embed_txtfiles =
html/index.min.html
html/restart.min.html
lib_deps =
prampec/IotWebConf @ ^3.2.1
geeksville/Micro-RTSP @ ^0.1.6
rzeldent/micro-moustache@^1.0.1
prampec/IotWebConf@^3.2.1
geeksville/Micro-RTSP@^0.1.6
rzeldent/micro-moustache
rzeldent/micro-timezonedb
[env:esp32cam_ai_thinker]
board = esp32cam_ai_thinker
[env:esp32cam_espressif_esp_eye]
board = esp32cam_espressif_esp_eye
[env:esp32cam_espressif_esp32s2_cam_board]
# Use board connection
# The 18 pin header on the board has Y5 and Y3 swapped
board = esp32cam_espressif_esp32s2_cam_board
[env:esp32cam_espressif_esp32s2_cam_header]
# Use header connection
# The 18 pin header on the board has Y5 and Y3 swapped
board = esp32cam_espressif_esp32s2_cam_header
[env:esp32cam_espressif_esp32s3_cam_lcd]
board = esp32cam_espressif_esp32s3_cam_lcd
[env:esp32cam_espressif_esp32s3_eye]
board = esp32cam_espressif_esp32s3_eye
[env:esp32cam_freenove_wrover_kit]
board = esp32cam_freenove_wrover_kit
[env:esp32cam_m5stack_camera_psram]
board = esp32cam_m5stack_camera_psram
[env:esp32cam_m5stack_camera]
board = esp32cam_m5stack_camera
[env:esp32cam_m5stack_esp32cam]
board = esp32cam_m5stack_esp32cam
[env:esp32cam_m5stack_unitcam]
board = esp32cam_m5stack_unitcam
[env:esp32cam_m5stack_unitcams3]
board = esp32cam_m5stack_unitcams3
[env:esp32cam_m5stack_wide]
board = esp32cam_m5stack_wide
[env:esp32cam_seeed_xiao_esp32s3_sense]
board = esp32cam_seeed_xiao_esp32s3_sense
[env:esp32cam_ttgo_t_camera]
board = esp32cam_ttgo_t_camera
[env:esp32cam_ttgo_t_journal]
board = esp32cam_ttgo_t_journal

View File

@@ -1,13 +1,12 @@
#include <Arduino.h>
#include <ArduinoOTA.h>
#include <esp_wifi.h>
#include <soc/rtc_cntl_reg.h>
#include <driver/i2c.h>
#include <IotWebConf.h>
#include <IotWebConfTParameter.h>
#include <OV2640.h>
#include <ESPmDNS.h>
#include <rtsp_server.h>
#include <lookup_camera_config.h>
#include <lookup_camera_effect.h>
#include <lookup_camera_frame_size.h>
#include <lookup_camera_gainceiling.h>
@@ -17,21 +16,16 @@
#include <moustache.h>
#include <settings.h>
extern "C" uint8_t temprature_sens_read();
#include <micro_rtsp_camera.h>
#include <micro_rtsp_server.h>
// HTML files
extern const char index_html_min_start[] asm("_binary_html_index_min_html_start");
extern const char restart_html_min_start[] asm("_binary_html_restart_min_html_start");
auto param_group_board = iotwebconf::ParameterGroup("board", "Board settings");
auto param_board = iotwebconf::Builder<iotwebconf::SelectTParameter<sizeof(camera_configs[0])>>("bt").label("Board").optionValues((const char *)&camera_configs).optionNames((const char *)&camera_configs).optionCount(sizeof(camera_configs) / sizeof(camera_configs[0])).nameLength(sizeof(camera_configs[0])).defaultValue(DEFAULT_CAMERA_CONFIG).build();
auto param_group_camera = iotwebconf::ParameterGroup("camera", "Camera settings");
auto param_frame_duration = iotwebconf::Builder<iotwebconf::UIntTParameter<unsigned long>>("fd").label("Frame duration (ms)").defaultValue(DEFAULT_FRAME_DURATION).min(10).build();
auto param_frame_size = iotwebconf::Builder<iotwebconf::SelectTParameter<sizeof(frame_sizes[0])>>("fs").label("Frame size").optionValues((const char *)&frame_sizes).optionNames((const char *)&frame_sizes).optionCount(sizeof(frame_sizes) / sizeof(frame_sizes[0])).nameLength(sizeof(frame_sizes[0])).defaultValue(DEFAULT_FRAME_SIZE).build();
auto param_jpg_quality = iotwebconf::Builder<iotwebconf::UIntTParameter<byte>>("q").label("JPG quality").defaultValue(DEFAULT_JPEG_QUALITY).min(1).max(100).build();
auto param_enable_psram = iotwebconf::Builder<iotwebconf::CheckboxTParameter>("eps").label("Enable PSRAM if available").defaultValue(DEFAULT_ENABLE_PSRAM).build();
auto param_frame_buffers = iotwebconf::Builder<iotwebconf::IntTParameter<int>>("fb").label("Buffers").defaultValue(DEFAULT_BUFFERS).min(1).max(4).build();
auto param_brightness = iotwebconf::Builder<iotwebconf::IntTParameter<int>>("b").label("Brightness").defaultValue(DEFAULT_BRIGHTNESS).min(-2).max(2).build();
auto param_contrast = iotwebconf::Builder<iotwebconf::IntTParameter<int>>("c").label("Contrast").defaultValue(DEFAULT_CONTRAST).min(-2).max(2).build();
auto param_saturation = iotwebconf::Builder<iotwebconf::IntTParameter<int>>("s").label("Saturation").defaultValue(DEFAULT_SATURATION).min(-2).max(2).build();
@@ -55,36 +49,25 @@ auto param_vflip = iotwebconf::Builder<iotwebconf::CheckboxTParameter>("vm").lab
auto param_dcw = iotwebconf::Builder<iotwebconf::CheckboxTParameter>("dcw").label("Downsize enable").defaultValue(DEFAULT_DCW).build();
auto param_colorbar = iotwebconf::Builder<iotwebconf::CheckboxTParameter>("cb").label("Colorbar").defaultValue(DEFAULT_COLORBAR).build();
auto param_group_peripheral = iotwebconf::ParameterGroup("io", "peripheral settings");
auto param_led_intensity = iotwebconf::Builder<iotwebconf::UIntTParameter<byte>>("li").label("LED intensity").defaultValue(DEFAULT_LED_INTENSITY).min(0).max(100).build();
// Camera
OV2640 cam;
// OV2640 cam;
// DNS Server
DNSServer dnsServer;
// RTSP Server
std::unique_ptr<rtsp_server> camera_server;
// std::unique_ptr<rtsp_server> camera_server;
micro_rtsp_camera camera;
micro_rtsp_server server(camera);
// Web server
WebServer web_server(80);
auto thingName = String(WIFI_SSID) + "-" + String(ESP.getEfuseMac(), 16);
IotWebConf iotWebConf(thingName.c_str(), &dnsServer, &web_server, WIFI_PASSWORD, CONFIG_VERSION);
// Keep track of config changes. This will allow a reset of the device
bool config_changed = false;
// Camera initialization result
esp_err_t camera_init_result;
void stream_text_file_gzip(const unsigned char *content, size_t length, const char *mime_type)
{
// Cache for 86400 seconds (one day)
web_server.sendHeader("Cache-Control", "max-age=86400");
web_server.sendHeader("Content-encoding", "gzip");
web_server.setContentLength(length);
web_server.send(200, mime_type, "");
web_server.sendContent(reinterpret_cast<const char *>(content), length);
}
void handle_root()
{
log_v("Handle root");
@@ -102,12 +85,15 @@ void handle_root()
auto ipv4 = WiFi.getMode() == WIFI_MODE_AP ? WiFi.softAPIP() : WiFi.localIP();
auto ipv6 = WiFi.getMode() == WIFI_MODE_AP ? WiFi.softAPIPv6() : WiFi.localIPv6();
auto initResult = esp_err_to_name(camera_init_result);
if (initResult == nullptr)
initResult = "Unknown reason";
moustache_variable_t substitutions[] = {
// Config Changed?
{"ConfigChanged", String(config_changed)},
// Version / CPU
{"AppTitle", APP_TITLE},
{"AppVersion", APP_VERSION},
{"BoardType", BOARD_NAME},
{"ThingName", iotWebConf.getThingName()},
{"SDKVersion", ESP.getSdkVersion()},
{"ChipModel", ESP.getChipModel()},
@@ -119,31 +105,27 @@ void handle_root()
{"PsRamSize", format_memory(ESP.getPsramSize(), 0)},
// Diagnostics
{"Uptime", String(format_duration(millis() / 1000))},
{"Temperature", String((temprature_sens_read() - 32) / 1.8)},
{"FreeHeap", format_memory(ESP.getFreeHeap())},
{"MaxAllocHeap", format_memory(ESP.getMaxAllocHeap())},
{"NumRTSPSessions", camera_server != nullptr ? String(camera_server->num_connected()) : "RTSP server disabled"},
{"NumRTSPSessions", String(server.clients())},
// Network
{"HostName", hostname},
{"MacAddress", WiFi.macAddress()},
{"AccessPoint", WiFi.SSID()},
{"SignalStrength", String(WiFi.RSSI())},
{"WifiMode", wifi_modes[WiFi.getMode()]},
{"IpV4", ipv4.toString()},
{"IpV6", ipv6.toString()},
{"IPv4", ipv4.toString()},
{"IPv6", ipv6.toString()},
{"NetworkState.ApMode", String(iotWebConf.getState() == iotwebconf::NetworkState::ApMode)},
{"NetworkState.OnLine", String(iotWebConf.getState() == iotwebconf::NetworkState::OnLine)},
// Camera
{"BoardType", String(param_board.value())},
{"FrameSize", String(param_frame_size.value())},
{"FrameDuration", String(param_frame_duration.value())},
{"FrameFrequency", String(1000.0 / param_frame_duration.value(), 1)},
{"JpegQuality", String(param_jpg_quality.value())},
{"EnablePSRAM", String(param_enable_psram.value())},
{"FrameBuffers", String(param_frame_buffers.value())},
{"CameraInitialized", String(camera_init_result == ESP_OK)},
{"CameraInitResult", String(camera_init_result)},
{"CameraInitResultText", esp_err_to_name(camera_init_result)},
{"CameraInitResultText", initResult},
// Settings
{"Brightness", String(param_brightness.value())},
{"Contrast", String(param_contrast.value())},
@@ -167,8 +149,6 @@ void handle_root()
{"VFlip", String(param_vflip.value())},
{"Dcw", String(param_dcw.value())},
{"ColorBar", String(param_colorbar.value())},
// LED
{"LedIntensity", String(param_led_intensity.value())},
// RTSP
{"RtspPort", String(RTSP_PORT)}};
@@ -177,28 +157,6 @@ void handle_root()
web_server.send(200, "text/html", html);
}
void handle_restart()
{
log_v("Handle restart");
if (!web_server.authenticate("admin", iotWebConf.getApPasswordParameter()->valueBuffer))
{
web_server.requestAuthentication(BASIC_AUTH, APP_TITLE, "401 Unauthorized<br><br>The password is incorrect.");
return;
}
moustache_variable_t substitutions[] = {
{"AppTitle", APP_TITLE},
{"AppVersion", APP_VERSION},
{"ThingName", iotWebConf.getThingName()}};
auto html = moustache_render(restart_html_min_start, substitutions);
web_server.send(200, "text/html", html);
log_v("Restarting... Press refresh to connect again");
sleep(100);
ESP.restart();
}
void handle_snapshot()
{
log_v("handle_snapshot");
@@ -209,12 +167,12 @@ void handle_snapshot()
}
// Remove old images stored in the frame buffer
auto frame_buffers = param_frame_buffers.value();
auto frame_buffers = CAMERA_CONFIG_FB_COUNT;
while (frame_buffers--)
cam.run();
camera.update_frame();
auto fb_len = cam.getSize();
auto fb = (const char *)cam.getfb();
auto fb_len = camera.size();
auto fb = camera.data();
if (fb == nullptr)
{
web_server.send(404, "text/plain", "Unable to obtain frame buffer from the camera");
@@ -224,7 +182,7 @@ void handle_snapshot()
web_server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
web_server.setContentLength(fb_len);
web_server.send(200, "image/jpeg", "");
web_server.sendContent(fb, fb_len);
web_server.sendContent((const char *)fb, fb_len);
}
#define STREAM_CONTENT_BOUNDARY "123456789000000000000987654321"
@@ -246,11 +204,11 @@ void handle_stream()
while (client.connected())
{
client.write("\r\n--" STREAM_CONTENT_BOUNDARY "\r\n");
cam.run();
camera.update_frame();
client.write("Content-Type: image/jpeg\r\nContent-Length: ");
sprintf(size_buf, "%d\r\n\r\n", cam.getSize());
sprintf(size_buf, "%d\r\n\r\n", camera.size());
client.write(size_buf);
client.write(cam.getfb(), cam.getSize());
client.write(camera.data(), camera.size());
}
log_v("client disconnected");
@@ -258,64 +216,54 @@ void handle_stream()
log_v("stopped streaming");
}
void handle_flash()
{
log_v("handle_flash");
if (!web_server.authenticate("admin", iotWebConf.getApPasswordParameter()->valueBuffer))
{
web_server.requestAuthentication(BASIC_AUTH, APP_TITLE, "401 Unauthorized<br><br>The password is incorrect.");
return;
}
// If no value present, use value from config
if (web_server.hasArg("v"))
{
auto v = (uint8_t)min(web_server.arg("v").toInt(), 255L);
// If conversion fails, v = 0
analogWrite(LED_FLASH, v);
}
else
{
analogWrite(LED_FLASH, param_led_intensity.value());
}
web_server.sendHeader("Cache-Control", "no-cache, no-store, must-revalidate");
web_server.send(200);
}
esp_err_t initialize_camera()
{
log_v("initialize_camera");
log_i("Camera config: %s", param_board.value());
auto camera_config_template = lookup_camera_config(param_board.value());
// Copy the settings
camera_config_t camera_config;
memset(&camera_config, 0, sizeof(camera_config_t));
memcpy(&camera_config, &camera_config_template, sizeof(camera_config_t));
log_i("Frame size: %s", param_frame_size.value());
auto frame_size = lookup_frame_size(param_frame_size.value());
log_i("JPEG quality: %d", param_jpg_quality.value());
auto jpeg_quality = param_jpg_quality.value();
log_i("Frame duration: %d ms", param_frame_duration.value());
camera_config.frame_size = frame_size;
camera_config.jpeg_quality = param_jpg_quality.value();
camera_config.grab_mode = CAMERA_GRAB_LATEST;
log_i("Enable PSRAM: %d", param_enable_psram.value());
log_i("Frame buffers: %d", param_frame_buffers.value());
camera_config.fb_count = param_frame_buffers.value();
if (param_enable_psram.value() && psramFound())
{
camera_config.fb_location = CAMERA_FB_IN_PSRAM;
log_i("PSRAM enabled!");
}
else
{
camera_config.fb_location = CAMERA_FB_IN_DRAM;
log_i("PSRAM disabled");
}
// Set frame duration
server.set_frame_interval(param_frame_duration.value());
return cam.init(camera_config);
camera_config_t camera_config = {
.pin_pwdn = CAMERA_CONFIG_PIN_PWDN, // GPIO pin for camera power down line
.pin_reset = CAMERA_CONFIG_PIN_RESET, // GPIO pin for camera reset line
.pin_xclk = CAMERA_CONFIG_PIN_XCLK, // GPIO pin for camera XCLK line
.pin_sccb_sda = CAMERA_CONFIG_PIN_SCCB_SDA, // GPIO pin for camera SDA line
.pin_sccb_scl = CAMERA_CONFIG_PIN_SCCB_SCL, // GPIO pin for camera SCL line
.pin_d7 = CAMERA_CONFIG_PIN_Y9, // GPIO pin for camera D7 line
.pin_d6 = CAMERA_CONFIG_PIN_Y8, // GPIO pin for camera D6 line
.pin_d5 = CAMERA_CONFIG_PIN_Y7, // GPIO pin for camera D5 line
.pin_d4 = CAMERA_CONFIG_PIN_Y6, // GPIO pin for camera D4 line
.pin_d3 = CAMERA_CONFIG_PIN_Y5, // GPIO pin for camera D3 line
.pin_d2 = CAMERA_CONFIG_PIN_Y4, // GPIO pin for camera D2 line
.pin_d1 = CAMERA_CONFIG_PIN_Y3, // GPIO pin for camera D1 line
.pin_d0 = CAMERA_CONFIG_PIN_Y2, // GPIO pin for camera D0 line
.pin_vsync = CAMERA_CONFIG_PIN_VSYNC, // GPIO pin for camera VSYNC line
.pin_href = CAMERA_CONFIG_PIN_HREF, // GPIO pin for camera HREF line
.pin_pclk = CAMERA_CONFIG_PIN_PCLK, // GPIO pin for camera PCLK line
.xclk_freq_hz = CAMERA_CONFIG_CLK_FREQ_HZ, // Frequency of XCLK signal, in Hz. EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode
.ledc_timer = CAMERA_CONFIG_LEDC_TIMER, // LEDC timer to be used for generating XCLK
.ledc_channel = CAMERA_CONFIG_LEDC_CHANNEL, // LEDC channel to be used for generating XCLK
.pixel_format = PIXFORMAT_JPEG, // Format of the pixel data: PIXFORMAT_ + YUV422|GRAYSCALE|RGB565|JPEG
.frame_size = frame_size, // Size of the output image: FRAMESIZE_ + QVGA|CIF|VGA|SVGA|XGA|SXGA|UXGA
.jpeg_quality = jpeg_quality, // Quality of JPEG output. 0-63 lower means higher quality
.fb_count = CAMERA_CONFIG_FB_COUNT, // Number of frame buffers to be allocated. If more than one, then each frame will be acquired (double speed)
.fb_location = CAMERA_CONFIG_FB_LOCATION, // The location where the frame buffer will be allocated
.grab_mode = CAMERA_GRAB_LATEST, // When buffers should be filled
#if CONFIG_CAMERA_CONVERTER_ENABLED
conv_mode = CONV_DISABLE, // RGB<->YUV Conversion mode
#endif
.sccb_i2c_port = CAMERA_CONFIG_SCCB_I2C_PORT // If pin_sccb_sda is -1, use the already configured I2C bus by number
};
return camera.initialize(&camera_config);
// return cam.init(camera_config);
}
void update_camera_settings()
@@ -354,17 +302,16 @@ void update_camera_settings()
void start_rtsp_server()
{
log_v("start_rtsp_server");
camera_server = std::unique_ptr<rtsp_server>(new rtsp_server(cam, param_frame_duration.value(), RTSP_PORT));
server.begin(RTSP_PORT);
// Add RTSP service to mDNS
// HTTP is already set by iotWebConf
MDNS.addService("rtsp", "tcp", 554);
MDNS.addService("rtsp", "tcp", RTSP_PORT);
}
void on_connected()
{
log_v("on_connected");
// Start (OTA) Over The Air programming when connected
ArduinoOTA.begin();
// Start the RTSP Server if initialized
if (camera_init_result == ESP_OK)
start_rtsp_server();
@@ -375,11 +322,7 @@ void on_connected()
void on_config_saved()
{
log_v("on_config_saved");
// Set flash led intensity
analogWrite(LED_FLASH, param_led_intensity.value());
// Update camera setting
update_camera_settings();
config_changed = true;
}
void setup()
@@ -387,38 +330,32 @@ void setup()
// Disable brownout
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0);
// LED_BUILTIN (GPIO33) has inverted logic false => LED on
pinMode(LED_BUILTIN, OUTPUT);
digitalWrite(LED_BUILTIN, false);
pinMode(LED_FLASH, OUTPUT);
// Turn flash led off
analogWrite(LED_FLASH, 0);
#ifdef CORE_DEBUG_LEVEL
Serial.begin(115200);
Serial.setDebugOutput(true);
#ifdef USER_LED_GPIO
pinMode(USER_LED_GPIO, OUTPUT);
digitalWrite(USER_LED_GPIO, !USER_LED_ON_LEVEL);
#endif
Serial.begin(115200);
Serial.setDebugOutput(true);
#ifdef ARDUINO_USB_CDC_ON_BOOT
// Delay for USB to connect/settle
delay(5000);
#endif
log_i("Core debug level: %d", CORE_DEBUG_LEVEL);
log_i("CPU Freq: %d Mhz, %d core(s)", getCpuFrequencyMhz(), ESP.getChipCores());
log_i("Free heap: %d bytes", ESP.getFreeHeap());
log_i("SDK version: %s", ESP.getSdkVersion());
log_i("Board: %s", BOARD_NAME);
log_i("Starting " APP_TITLE "...");
if (psramFound())
{
psramInit();
log_v("PSRAM found and initialized");
}
param_group_board.addItem(&param_board);
iotWebConf.addParameterGroup(&param_group_board);
if (CAMERA_CONFIG_FB_LOCATION == CAMERA_FB_IN_PSRAM && !psramInit())
log_e("Failed to initialize PSRAM");
param_group_camera.addItem(&param_frame_duration);
param_group_camera.addItem(&param_frame_size);
param_group_camera.addItem(&param_jpg_quality);
param_group_camera.addItem(&param_enable_psram);
param_group_camera.addItem(&param_frame_buffers);
param_group_camera.addItem(&param_brightness);
param_group_camera.addItem(&param_contrast);
param_group_camera.addItem(&param_saturation);
@@ -443,67 +380,48 @@ void setup()
param_group_camera.addItem(&param_colorbar);
iotWebConf.addParameterGroup(&param_group_camera);
param_group_peripheral.addItem(&param_led_intensity);
iotWebConf.addParameterGroup(&param_group_peripheral);
iotWebConf.getApTimeoutParameter()->visible = true;
iotWebConf.setConfigSavedCallback(on_config_saved);
iotWebConf.setWifiConnectionCallback(on_connected);
iotWebConf.setStatusPin(LED_BUILTIN, LOW);
#ifdef USER_LED_GPIO
iotWebConf.setStatusPin(USER_LED_GPIO, USER_LED_ON_LEVEL);
#endif
iotWebConf.init();
camera_init_result = initialize_camera();
if (camera_init_result == ESP_OK)
update_camera_settings();
else
log_e("Failed to initialize camera: 0x%0x. Type: %s, frame size: %s, frame rate: %d ms, jpeg quality: %d", camera_init_result, param_board.value(), param_frame_size.value(), param_frame_duration.value(), param_jpg_quality.value());
// Set the time servers
configTime(0, 0, NTP_SERVERS);
// Try to initialize 3 times
for (auto i = 0; i < 3; i++)
{
log_i("Initializing camera...");
camera_init_result = initialize_camera();
if (camera_init_result == ESP_OK)
break;
esp_camera_deinit();
log_e("Failed to initialize camera. Error: 0x%04x. Frame size: %s, frame rate: %d ms, jpeg quality: %d", camera_init_result, param_frame_size.value(), param_frame_duration.value(), param_jpg_quality.value());
delay(500);
}
update_camera_settings();
// Set up required URL handlers on the web server
web_server.on("/", HTTP_GET, handle_root);
web_server.on("/config", []
{ iotWebConf.handleConfig(); });
web_server.on("/restart", HTTP_GET, handle_restart);
// Camera snapshot
web_server.on("/snapshot", HTTP_GET, handle_snapshot);
// Camera stream
web_server.on("/stream", HTTP_GET, handle_stream);
// Camera flash light
web_server.on("/flash", HTTP_GET, handle_flash);
web_server.onNotFound([]()
{ iotWebConf.handleNotFound(); });
ArduinoOTA
.setPassword(OTA_PASSWORD)
.onStart([]()
{ log_w("Starting OTA update: %s", ArduinoOTA.getCommand() == U_FLASH ? "sketch" : "filesystem"); })
.onEnd([]()
{ log_w("OTA update done!"); })
.onProgress([](unsigned int progress, unsigned int total)
{ log_i("OTA Progress: %u%%\r", (progress / (total / 100))); })
.onError([](ota_error_t error)
{
switch (error)
{
case OTA_AUTH_ERROR: log_e("OTA: Auth Failed"); break;
case OTA_BEGIN_ERROR: log_e("OTA: Begin Failed"); break;
case OTA_CONNECT_ERROR: log_e("OTA: Connect Failed"); break;
case OTA_RECEIVE_ERROR: log_e("OTA: Receive Failed"); break;
case OTA_END_ERROR: log_e("OTA: End Failed"); break;
default: log_e("OTA error: %u", error);
} });
// Set flash led intensity
analogWrite(LED_FLASH, param_led_intensity.value());
}
void loop()
{
iotWebConf.doLoop();
ArduinoOTA.handle();
if (camera_server)
camera_server->doLoop();
yield();
server.loop();
}

127
test/test_main.cpp Normal file

File diff suppressed because one or more lines are too long