Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
20 changes: 14 additions & 6 deletions .github/workflows/build.yml
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,6 @@ on: [pull_request]

env:
APP_NAME: 'Camera Streamer'
IDF_TARGET: 'esp32'
IDF_VERSION: 'v5.5.1'
IDF_COMPONENT_MANAGER: "1" # whether to enable the component manager or not
FLASH_TOTAL_OVERRIDE: '2097152' # 2MB flash app partition for main app
Expand All @@ -14,25 +13,34 @@ jobs:

runs-on: ubuntu-latest

strategy:
fail-fast: false
matrix:
include:
- board: 'timer-cam'
target: 'esp32'
- board: 'xiao-esp32s3-sense'
target: 'esp32s3'

steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: true

- name: Build Main
- name: Build Main (${{ matrix.board }})
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: ${{ env.IDF_VERSION }}
target: ${{ env.IDF_TARGET }}
target: ${{ matrix.target }}
path: '.'

- name: Determine Size Delta
- name: Determine Size Delta (${{ matrix.board }})
uses: esp-cpp/esp-idf-size-delta@v1
with:
app_name: ${{ env.APP_NAME }}
app_name: '${{ env.APP_NAME }} (${{ matrix.board }})'
app_path: '.'
idf_target: ${{ env.IDF_TARGET }}
idf_target: ${{ matrix.target }}
idf_version: ${{ env.IDF_VERSION }}
idf_component_manager: ${{ env.IDF_COMPONENT_MANAGER }}
flash_total_override: ${{ env.FLASH_TOTAL_OVERRIDE }}
55 changes: 33 additions & 22 deletions .github/workflows/package_main.yml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,6 @@ on:

env:
APP_NAME: 'Camera Streamer'
IDF_TARGET: 'esp32'
IDF_VERSION: 'v5.5.1'
IDF_COMPONENT_MANAGER: "1" # whether to enable the component manager or not
FLASH_TOTAL_OVERRIDE: '2097152' # 2MB flash app partition for main app
Expand All @@ -20,27 +19,32 @@ jobs:
runs-on: ubuntu-latest
continue-on-error: false

outputs:
zipfile-id: ${{ steps.zip_step.outputs.artifact-id }}
strategy:
fail-fast: false
matrix:
include:
- board: 'timer-cam'
target: 'esp32'
- board: 'xiao-esp32s3-sense'
target: 'esp32s3'

steps:
- name: Checkout repo
uses: actions/checkout@v4
with:
submodules: true

- name: Build Main Code
- name: Build Main Code (${{ matrix.board }})
uses: espressif/esp-idf-ci-action@v1
with:
esp_idf_version: release-v5.4
target: esp32
esp_idf_version: ${{ env.IDF_VERSION }}
target: ${{ matrix.target }}
path: '.'

- name: Upload Build Outputs
- name: Upload Build Outputs (${{ matrix.board }})
uses: actions/upload-artifact@v4
id: zip_step
with:
name: build-artifacts
name: build-artifacts-${{ matrix.board }}
path: |
build/*.bin
build/*.elf
Expand All @@ -49,40 +53,47 @@ jobs:
build/flasher_args.json
build/flash_args

- name: Attach files to release
- name: Stage release files (${{ matrix.board }})
if: ${{ github.event.release && github.event.action == 'published' }}
run: |
mkdir -p release
cp build/camera-streamer.bin release/camera-streamer_${{ matrix.board }}.bin
cp build/camera-streamer.elf release/camera-streamer_${{ matrix.board }}.elf
cp build/bootloader/bootloader.bin release/bootloader_${{ matrix.board }}.bin
cp build/partition_table/partition-table.bin release/partition-table_${{ matrix.board }}.bin
cp build/flasher_args.json release/flasher_args_${{ matrix.board }}.json

- name: Attach files to release (${{ matrix.board }})
uses: softprops/action-gh-release@v2
if: ${{ github.event.release && github.event.action == 'published' }}
with:
files: |
build/*.bin
build/*.elf
build/bootloader/bootloader.bin
build/partition_table/partition-table.bin
build/flasher_args.json
build/flash_args
release/*

- name: Determine Size Delta
- name: Determine Size Delta (${{ matrix.board }})
# only run this if the release is published
if: ${{ github.event.release && github.event.action == 'published' }}
uses: esp-cpp/esp-idf-size-delta@v1
with:
app_name: ${{ env.APP_NAME }}
app_name: '${{ env.APP_NAME }} (${{ matrix.board }})'
app_path: "."
idf_target: ${{ env.IDF_TARGET }}
idf_target: ${{ matrix.target }}
idf_version: ${{ env.IDF_VERSION }}
idf_component_manager: ${{ env.IDF_COMPONENT_MANAGER }}
flash_total_override: ${{ env.FLASH_TOTAL_OVERRIDE }}
post_comment: 'false'

package:
name: Package the binaries into an executables for Windows, MacOS, and Linux (Ubuntu)
name: Package the binaries into executables for Windows, MacOS, and Linux (Ubuntu)
needs: build
strategy:
fail-fast: false
matrix:
os: [windows-latest, macos-latest, ubuntu-latest]
board: ['timer-cam', 'xiao-esp32s3-sense']
runs-on: ${{ matrix.os }}
steps:
- uses: esp-cpp/esp-packaged-programmer-action@v1.0.5
with:
zipfile-id: ${{ needs.build.outputs.zipfile-id }}
programmer-name: 'camera-streamer_programmer'
zipfile-name: build-artifacts-${{ matrix.board }}
programmer-name: 'camera-streamer_${{ matrix.board }}_programmer'
2 changes: 1 addition & 1 deletion .github/workflows/static_analysis.yml
Original file line number Diff line number Diff line change
Expand Up @@ -17,4 +17,4 @@ jobs:
use_cmake: false

# (Optional) cppcheck args
cppcheck_args: --force --enable=all --inline-suppr --inconclusive --platform=mips32 --std=c++17 --suppressions-list=$GITHUB_WORKSPACE/suppressions.txt
cppcheck_args: --force --enable=all --check-level=exhaustive --inline-suppr --inconclusive --platform=mips32 --std=c++17 --suppressions-list=$GITHUB_WORKSPACE/suppressions.txt
1 change: 1 addition & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -36,3 +36,4 @@ sdkconfig.old
.DS_Store
dependencies.lock
managed_components/
.cache/
10 changes: 4 additions & 6 deletions CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,10 @@ set(EXTRA_COMPONENT_DIRS

add_compile_definitions(BOARD_HAS_PSRAM)

set(
COMPONENTS
"main esptool_py esp_psram esp32-camera esp32-timer-cam mdns monitor nvs rtsp socket task wifi "
CACHE STRING
"List of components to include"
)
# The set of board-specific components (esp32-timer-cam vs xiao-esp32s3-sense)
# depends on the target chip, so component selection is handled by the
# component manager (main/idf_component.yml) and main/CMakeLists.txt REQUIRES
# rather than a hard-coded COMPONENTS list here.

project(camera-streamer)

Expand Down
76 changes: 71 additions & 5 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,8 +1,18 @@
# camera-streamer

Example for [ESP32 TimerCam](https://github.com/m5stack/TimerCam-idf) rebuilt using [ESPP](http://github.com/esp-cpp/espp) to stream video over the network
Camera streamer built using [ESPP](http://github.com/esp-cpp/espp) to stream
video (and, where available, audio) over the network. It supports two boards,
selected at build time by the target chip:

It uses RTSP + RTP (over UDP) to perform real-time streaming of the camera data over the network to multiple clients.
| Board | Target | Sensor | Streams |
|-------|--------|--------|---------|
| [M5Stack ESP32 TimerCam](https://github.com/m5stack/TimerCam-idf) | `esp32` | OV3660 | MJPEG video |
| [Seeed Studio XIAO ESP32S3 Sense](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/) | `esp32s3` | OV2640 + PDM mic | MJPEG video + L16 PCM audio |

It uses RTSP + RTP (over UDP) to perform real-time streaming of the camera data
over the network to multiple clients. On the XIAO ESP32S3 Sense, the onboard PDM
microphone is streamed as a second RTP track (L16 / 16 kHz mono) alongside the
video.

https://user-images.githubusercontent.com/213467/236601550-ba1a5ba1-4f1c-4dfa-9b64-94afbd46ef3f.mp4

Expand Down Expand Up @@ -115,7 +125,25 @@ documentation](https://docs.espressif.com/projects/esp-idf/en/v5.5.1/esp32s3/get

### Build and Flash

Build the project and flash it to the board, then run monitor tool to view serial output:
This project supports two boards, each tied to a specific chip. Select the board
by setting the matching target before building — ESP-IDF automatically applies
the corresponding `sdkconfig.defaults.<target>` (which selects the board in
Kconfig):

```
# M5Stack ESP32 TimerCam (the default target)
idf.py set-target esp32

# Seeed Studio XIAO ESP32S3 Sense (camera + microphone)
idf.py set-target esp32s3
```

You can also flip the board explicitly under `Camera Streamer Configuration ->
Target board` in `idf.py menuconfig` (only the board matching the current chip is
selectable).

Then build the project and flash it to the board, and run the monitor tool to
view serial output:

```
idf.py -p PORT flash monitor
Expand All @@ -125,13 +153,24 @@ idf.py -p PORT flash monitor

(To exit the serial monitor, type ``Ctrl-]``.)

> [!NOTE]
> When you switch targets, run `idf.py fullclean` first (or delete the `build/`
> and `sdkconfig` files) so the new target's defaults are applied cleanly.

See the Getting Started Guide for full steps to configure and use ESP-IDF to build projects.

## Hardware

This sample is designed to run on the ESP32 TimerCam ([Amazon Link](https://www.amazon.com/dp/B09W2RSPGL?psc=1&ref=ppx_yo2ov_dt_b_product_details)).
This sample runs on either the M5Stack ESP32 TimerCam or the Seeed Studio XIAO
ESP32S3 Sense. The board pin mappings come from the corresponding ESPP board
support package ([`esp32-timer-cam`](https://github.com/esp-cpp/espp/tree/main/components/esp32-timer-cam)
or [`xiao-esp32s3-sense`](https://github.com/esp-cpp/espp/tree/main/components/xiao-esp32s3-sense)),
so the pin tables below are informational.

The ESP32 TimerCam has the following specs:
### M5Stack ESP32 TimerCam

The ESP32 TimerCam ([Amazon Link](https://www.amazon.com/dp/B09W2RSPGL?psc=1&ref=ppx_yo2ov_dt_b_product_details))
has the following specs:

* 8MB PSRAM
* 4MB flash
Expand Down Expand Up @@ -193,6 +232,31 @@ From their actual code...
| LED | IO2 |
| Button | IO37 |

### Seeed Studio XIAO ESP32S3 Sense

The XIAO ESP32S3 Sense ([Seeed Studio Wiki](https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/))
pairs the XIAO ESP32S3 module with the "Sense" expansion board, which adds an
OV2640 camera and a PDM microphone.

The XIAO ESP32S3 Sense has the following specs:

* 8MB PSRAM, 8MB flash
* OV2640 image sensor (2MP), via the Sense expansion board (XCLK 20 MHz)
* PDM microphone, via the Sense expansion board
* microSD slot (SPI), via the Sense expansion board
* User LED + native USB-C (console runs over USB Serial/JTAG)

The camera, microphone, microSD, and LED pin mappings are provided by the ESPP
[`xiao-esp32s3-sense`](https://github.com/esp-cpp/espp/tree/main/components/xiao-esp32s3-sense)
board support package.

#### Microphone (PDM):

| Mic Pin | ESP32-S3 GPIO Number |
|---------|----------------------|
| CLK | IO42 |
| DATA | IO41 |


## Additional References

Expand All @@ -201,3 +265,5 @@ From their actual code...
* https://github.com/esp-cpp/espp
* https://github.com/m5stack/TimerCam-idf
* https://docs.m5stack.com/#/en/unit/timercam
* https://wiki.seeedstudio.com/xiao_esp32s3_getting_started/
* https://esp-cpp.github.io/espp/xiao_esp32s3_sense.html
Loading
Loading