{"id":26363400,"url":"https://github.com/dogusyuksel/esp32-cam","last_synced_at":"2026-05-19T02:05:19.365Z","repository":{"id":268577797,"uuid":"902878431","full_name":"dogusyuksel/esp32-cam","owner":"dogusyuksel","description":"Common Library for satellite cameras for earth observation mission","archived":false,"fork":false,"pushed_at":"2025-01-09T12:56:13.000Z","size":3759,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-03-16T18:27:35.685Z","etag":null,"topics":["camera","esp32","esp32-cam","espressif","http-server","idf"],"latest_commit_sha":null,"homepage":"","language":"C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dogusyuksel.png","metadata":{"files":{"readme":"README.md","changelog":"CHANGELOG.md","contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-13T13:05:38.000Z","updated_at":"2025-01-09T12:56:17.000Z","dependencies_parsed_at":"2024-12-17T16:44:22.094Z","dependency_job_id":"d5f9904b-5592-4c69-950a-5ff4e68d4564","html_url":"https://github.com/dogusyuksel/esp32-cam","commit_stats":null,"previous_names":["dogusyuksel/esp32-cam"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dogusyuksel/esp32-cam","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dogusyuksel%2Fesp32-cam","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dogusyuksel%2Fesp32-cam/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dogusyuksel%2Fesp32-cam/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dogusyuksel%2Fesp32-cam/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dogusyuksel","download_url":"https://codeload.github.com/dogusyuksel/esp32-cam/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dogusyuksel%2Fesp32-cam/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":264599696,"owners_count":23635311,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["camera","esp32","esp32-cam","espressif","http-server","idf"],"created_at":"2025-03-16T18:27:39.087Z","updated_at":"2026-05-19T02:05:19.335Z","avatar_url":"https://github.com/dogusyuksel.png","language":"C","funding_links":[],"categories":[],"sub_categories":[],"readme":"ESP32-camera module development environment\n==============\n\n# General View\n\n\u003cimg src=\"./docs/images/img1.jpeg\" width=\"200\" height=\"200\" /\u003e\n\u003cimg src=\"./docs/images/img2.jpeg\" width=\"200\" height=\"200\" /\u003e\n\n# PinOut\n\n\u003cimg src=\"./docs/images/img3.jpeg\" width=\"200\" height=\"200\" /\u003e\n\n# Helper Board for Flashing\n\n\u003cimg src=\"./docs/images/img4.jpeg\" width=\"200\" height=\"200\" /\u003e\n\n\n# Starting Point\n\n[Follow the steps in github actions](./.github/workflows/build-and-tests.yml)\n\n\n# How To Build\n\n* go into any project and type\n\n```\nidf.py build\n```\n\n# How To Flash\n\nUse the following command\n\n```\nidf.py -p /dev/ttyUSB0 flash\n```\n\n# How to See Output\n\n```\nroot:/workspace/ip_camera# idf.py -p /dev/ttyUSB0 flash monitor\n````\n\u003cdetails\u003e\u003csummary\u003eLogs\u003c/summary\u003eroot:/workspace/ip_camera# idf.py -p /dev/ttyUSB0 flash monitor\n\nI (30) boot: ESP-IDF v5.3.2 2nd stage bootloader\n\nI (30) boot: compile time Jan  3 2025 16:54:33\n\nI (30) boot: Multicore bootloader\n\nI (34) boot: chip revision: v1.1\n\nI (38) boot.esp32: SPI Speed      : 40MHz\n\nI (43) boot.esp32: SPI Mode       : DIO\n\nI (47) boot.esp32: SPI Flash Size : 2MB\n\nI (52) boot: Enabling RNG early entropy source...\n\nI (57) boot: Partition Table:\n\nI (61) boot: ## Label            Usage          Type ST Offset   Length\n\nI (68) boot:  0 nvs              WiFi data        01 02 00009000 00006000\n\nI (75) boot:  1 phy_init         RF data          01 01 0000f000 00001000\n\nI (83) boot:  2 factory          factory app      00 00 00010000 00100000\n\nI (90) boot: End of partition table\n\nI (95) esp_image: segment 0: paddr=00010020 vaddr=3f400020 size=25b80h (154496) map\n\nI (156) esp_image: segment 1: paddr=00035ba8 vaddr=3ffb0000 size=051e0h ( 20960) load\n\nI (164) esp_image: segment 2: paddr=0003ad90 vaddr=40080000 size=05288h ( 21128) load\n\nI (173) esp_image: segment 3: paddr=00040020 vaddr=400d0020 size=a4600h (673280) map\n\nI (403) esp_image: segment 4: paddr=000e4628 vaddr=40085288 size=18354h ( 99156) load\n\nI (457) boot: Loaded app from partition at offset 0x10000\n\nI (457) boot: Disabling RNG early entropy source...\n\nI (470) quad_psram: This chip is ESP32-D0WD\n\nI (472) esp_psram: Found 8MB PSRAM device\n\nI (472) esp_psram: Speed: 40MHz\n\nI (473) esp_psram: PSRAM initialized, cache is in low/high (2-core) mode.\n\nW (481) esp_psram: Virtual address not enough for PSRAM, map as much as we can. 4MB is mapped\n\nI (490) cpu_start: Multicore app\n\nI (1397) esp_psram: SPI SRAM memory test OK\n\nI (1405) cpu_start: Pro cpu start user code\n\nI (1405) cpu_start: cpu freq: 160000000 Hz\n\nI (1405) app_init: Application information:\n\nI (1408) app_init: Project name:     softap_sta\n\nI (1413) app_init: App version:      4f40319-dirty\n\nI (1419) app_init: Compile time:     Jan  4 2025 14:03:18\n\nI (1425) app_init: ELF file SHA256:  6469049c4...\n\nI (1430) app_init: ESP-IDF:          v5.3.2\n\nI (1435) efuse_init: Min chip rev:     v0.0\n\nI (1440) efuse_init: Max chip rev:     v3.99 \n\nI (1445) efuse_init: Chip rev:         v1.1\n\nI (1450) heap_init: Initializing. RAM available for dynamic allocation:\n\nI (1457) heap_init: At 3FFAE6E0 len 00001920 (6 KiB): DRAM\n\nI (1463) heap_init: At 3FFBB4B0 len 00024B50 (146 KiB): DRAM\n\nI (1469) heap_init: At 3FFE0440 len 00003AE0 (14 KiB): D/IRAM\n\nI (1476) heap_init: At 3FFE4350 len 0001BCB0 (111 KiB): D/IRAM\n\nI (1482) heap_init: At 4009D5DC len 00002A24 (10 KiB): IRAM\n\nI (1489) esp_psram: Adding pool of 4096K of PSRAM memory to heap allocator\n\nI (1498) spi_flash: detected chip: generic\n\nI (1501) spi_flash: flash io: dio\n\nW (1505) spi_flash: Detected size(4096k) larger than the size in the binary image header(2048k). Using the size in the binary image header.\n\nW (1518) i2c: This driver is an old driver, please migrate your application code to adapt `driver/i2c_master.h`\n\nI (1530) main_task: Started on CPU0\n\nI (1540) esp_psram: Reserving pool of 32K of internal memory for DMA/internal allocations\n\nI (1540) main_task: Calling app_main()\n\nI (1540) gpio: GPIO[25]| InputEn: 1| OutputEn: 0| OpenDrain: 0| Pullup: 1| Pulldown: 0| Intr:2 \n\nI (1550) cam_hal: cam init ok\n\nI (1560) sccb: pin_sda 26 pin_scl 27\n\nI (1560) sccb: sccb_i2c_port=1\n\nI (1560) gpio: GPIO[32]| InputEn: 0| OutputEn: 1| OpenDrain: 0| Pullup: 0| Pulldown: 0| Intr:0 \n\nI (1600) camera: Detected camera at address=0x30\n\nI (1600) camera: Detected OV2640 camera\n\nI (1600) camera: Camera PID=0x26 VER=0x42 MIDL=0x7f MIDH=0xa2\n\nI (1690) cam_hal: buffer_size: 32768, half_buffer_size: 4096, node_buffer_size: 2048, node_cnt: 16, total_cnt: 15\n\nI (1690) cam_hal: Allocating 61440 Byte frame buffer in PSRAM\n\nI (1690) cam_hal: cam config ok\n\nI (1700) ov2640: Set PLL: clk_2x: 0, clk_div: 0, pclk_auto: 0, pclk_div: 8\n\nI (1830) wifi:wifi driver task: 3ffd3e68, prio:23, stack:6656, core=0\n\nI (1840) wifi:wifi firmware version: b0fd6006b\n\nI (1840) wifi:wifi certification version: v7.0\n\nI (1840) wifi:config NVS flash: enabled\n\nI (1840) wifi:config nano formating: disabled\n\nI (1850) wifi:Init data frame dynamic rx buffer num: 32\n\nI (1850) wifi:Init static rx mgmt buffer num: 5\n\nI (1860) wifi:Init management short buffer num: 32\n\nI (1860) wifi:Init static tx buffer num: 16\n\nI (1870) wifi:Init tx cache buffer num: 32\n\nI (1870) wifi:Init static rx buffer size: 1600\n\nI (1870) wifi:Init static rx buffer num: 10\n\nI (1880) wifi:Init dynamic rx buffer num: 32\n\nI (1880) wifi_init: rx ba win: 6\n\nI (1890) wifi_init: accept mbox: 6\n\nI (1890) wifi_init: tcpip mbox: 32\n\nI (1890) wifi_init: udp mbox: 6\n\nI (1900) wifi_init: tcp mbox: 6\n\nI (1900) wifi_init: tcp tx win: 5760\n\nI (1910) wifi_init: tcp rx win: 5760\n\nI (1910) wifi_init: tcp mss: 1440\n\nI (1910) wifi_init: WiFi IRAM OP enabled\n\nI (1920) wifi_init: WiFi RX IRAM OP enabled\n\nI (1920) WiFi SoftAP: ESP_WIFI_MODE_AP\n\nI (1930) WiFi SoftAP: wifi_init_softap finished. SSID:dodossid password:mypassword channel:1\n\nI (1940) WiFi Sta: ESP_WIFI_MODE_STA\n\nI (1990) WiFi Sta: wifi_init_sta finished.\n\nI (1990) phy_init: phy_version 4840,02e0d70,Sep  2 2024,19:39:07\n\nI (2060) wifi:mode : sta (fc:b4:67:01:c1:80) + softAP (fc:b4:67:01:c1:81)\n\nI (2070) wifi:enable tsf\n\nI (2070) wifi:Total power save buffer number: 8\n\nI (2070) wifi:Init max length of beacon: 752/752\n\nI (2070) wifi:Init max length of beacon: 752/752\n\nI (2080) WiFi Sta: Station started\n\nI (2080) esp_netif_lwip: DHCP server started on interface WIFI_AP_DEF with IP: 192.168.4.1\n\nI (5190) wifi:ap channel adjust o:1,1 n:6,2\n\nI (5190) wifi:new:\u003c6,0\u003e, old:\u003c1,1\u003e, ap:\u003c6,2\u003e, sta:\u003c6,0\u003e, prof:1, snd_ch_cfg:0x0\n\nI (5200) wifi:state: init -\u003e auth (0xb0)\n\nI (5220) wifi:state: auth -\u003e assoc (0x0)\n\nI (5330) wifi:state: assoc -\u003e run (0x10)\n\nI (6430) wifi:connected with VM7326524, aid = 2, channel 6, BW20, bssid = 18:35:d1:a6:c1:c9\n\nI (6430) wifi:security: WPA2-PSK, phy: bgn, rssi: -54\n\nI (6450) wifi:pm start, type: 1\n\n\n\nI (6450) wifi:dp: 1, bi: 102400, li: 3, scale listen interval from 307200 us to 307200 us\n\nI (6450) wifi:AP's beacon interval = 102400 us, DTIM period = 1\n\nI (9130) wifi:\u003cba-add\u003eidx:0 (ifx:0, 18:35:d1:a6:c1:c9), tid:0, ssn:1, winSize:64\n\nI (9960) WiFi Sta: Got IP:192.168.0.29\n\nI (9960) camera_http_server: Starting webserver\n\nI (9960) camera_http_server: Starting server on port: '80'\n\nI (9960) WiFi Sta: connected to ap SSID:myssid password:mypassword\n\nI (9960) camera_http_server: Registering URI handlers\n\nI (9970) esp_netif_handlers: sta ip: 192.168.0.29, mask: 255.255.255.0, gw: 192.168.0.1\n\nW (9980) esp_netif_lwip: napt disabled on esp_netif:0x3ffdfc80\n\nI (9990) main_task: Returned from app_main()\n\nI (70880) camera_http_server: MJPG: 14KB 92ms (10.9fps)\n\nI (70950) camera_http_server: MJPG: 13KB 78ms (12.8fps)\n\nI (71030) camera_http_server: MJPG: 12KB 74ms (13.5fps)\n\nI (71130) camera_http_server: MJPG: 12KB 102ms (9.8fps)\n\nI (71350) camera_http_server: MJPG: 12KB 217ms (4.6fps)\n\nI (195940) camera_http_server: MJPG: 7KB 89ms (11.2fps)\n\nW (195990) httpd_txrx: httpd_sock_err: error in send : 104\n\nW (195990) httpd_uri: httpd_uri: uri handler execution failed\n\n\n\nDone\n\nroot:/workspace/ip_camera# \u003c/details\u003e\n\n## How to Test\n\nType \"http://\u003cIP_of_ESP\u003e/jpegstream\" to your browser\n\n```\nhttp://172.20.10.14/jpegstream\n```\n\nAnd then see the streamed result\n\n\u003cimg src=\"./docs/images/stream_result.jpeg\" width=\"300\" height=\"300\" /\u003e\n\n\n\nor execute the tools/http_client.py with sdp ip arg.\n\n```\npython3 tools/http_client.py \u003cESP_IP\u003e\n```\n\n### Supported Soc\n\n- ESP32\n- ESP32-S2\n- ESP32-S3\n\n### Supported Sensor\n\n| model   | max resolution | color type | output format                                                | Len Size |\n| ------- | -------------- | ---------- | ------------------------------------------------------------ | -------- |\n| OV2640  | 1600 x 1200    | color      | YUV(422/420)/YCbCr422\u003cbr\u003eRGB565/555\u003cbr\u003e8-bit compressed data\u003cbr\u003e8/10-bit Raw RGB data | 1/4\"     |\n| OV3660  | 2048 x 1536    | color      | raw RGB data\u003cbr/\u003eRGB565/555/444\u003cbr/\u003eCCIR656\u003cbr/\u003eYCbCr422\u003cbr/\u003ecompression | 1/5\"     |\n| OV5640  | 2592 x 1944    | color      | RAW RGB\u003cbr/\u003eRGB565/555/444\u003cbr/\u003eCCIR656\u003cbr/\u003eYUV422/420\u003cbr/\u003eYCbCr422\u003cbr/\u003ecompression | 1/4\"     |\n| OV7670  | 640 x 480      | color      | Raw Bayer RGB\u003cbr/\u003eProcessed Bayer RGB\u003cbr\u003eYUV/YCbCr422\u003cbr\u003eGRB422\u003cbr\u003eRGB565/555 | 1/6\"     |\n| OV7725  | 640 x 480      | color      | Raw RGB\u003cbr/\u003eGRB 422\u003cbr/\u003eRGB565/555/444\u003cbr/\u003eYCbCr 422         | 1/4\"     |\n| NT99141 | 1280 x 720     | color      | YCbCr 422\u003cbr/\u003eRGB565/555/444\u003cbr/\u003eRaw\u003cbr/\u003eCCIR656\u003cbr/\u003eJPEG compression | 1/4\"     |\n| GC032A  | 640 x 480      | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer\u003cbr/\u003eRGB565                        | 1/10\"    |\n| GC0308  | 640 x 480      | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer\u003cbr/\u003eRGB565\u003cbr/\u003eGrayscale                         | 1/6.5\"   |\n| GC2145  | 1600 x 1200    | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer\u003cbr/\u003eRGB565                        | 1/5\"     |\n| BF3005  | 640 x 480      | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer\u003cbr/\u003eRGB565                        | 1/4\"     |\n| BF20A6  | 640 x 480      | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer\u003cbr/\u003eOnly Y                        | 1/10\"    |\n| SC101IOT| 1280 x 720     | color      | YUV/YCbCr422\u003cbr/\u003eRaw RGB                                     | 1/4.2\"   |\n| SC030IOT| 640 x 480      | color      | YUV/YCbCr422\u003cbr/\u003eRAW Bayer                                   | 1/6.5\"   |\n| SC031GS | 640 x 480      | monochrome | RAW MONO\u003cbr/\u003eGrayscale                                       | 1/6\"     |\n\n## Important to Remember\n\n- Except when using CIF or lower resolution with JPEG, the driver requires PSRAM to be installed and activated.\n- Using YUV or RGB puts a lot of strain on the chip because writing to PSRAM is not particularly fast. The result is that image data might be missing. This is particularly true if WiFi is enabled. If you need RGB data, it is recommended that JPEG is captured and then turned into RGB using `fmt2rgb888` or `fmt2bmp`/`frame2bmp`.\n- When 1 frame buffer is used, the driver will wait for the current frame to finish (VSYNC) and start I2S DMA. After the frame is acquired, I2S will be stopped and the frame buffer returned to the application. This approach gives more control over the system, but results in longer time to get the frame.\n- When 2 or more frame bufers are used, I2S is running in continuous mode and each frame is pushed to a queue that the application can access. This approach puts more strain on the CPU/Memory, but allows for double the frame rate. Please use only with JPEG.\n\n## Installation Instructions\n\n\n### Using with ESP-IDF\n\n- Add a dependency on `espressif/esp32-camera` component:\n  ```bash\n  idf.py add-dependency \"espressif/esp32-camera\"\n  ```\n  (or add it manually in idf_component.yml of your project)\n- Enable PSRAM in `menuconfig` (also set Flash and PSRAM frequiencies to 80MHz)\n- Include `esp_camera.h` in your code\n\nThese instructions also work for PlatformIO, if you are using `framework=espidf`.\n\n\n## Examples\n\nThis component comes with a basic example illustrating how to get frames from the camera. You can try out the example using the following command:\n\n```\nidf.py create-project-from-example \"espressif/esp32-camera:camera_example\"\n```\n\nThis command will download the example into `camera_example` directory. It comes already pre-configured with the correct settings in menuconfig.\n\n### Initialization\n\n```c\n#include \"esp_camera.h\"\n\n//WROVER-KIT PIN Map\n#define CAM_PIN_PWDN    -1 //power down is not used\n#define CAM_PIN_RESET   -1 //software reset will be performed\n#define CAM_PIN_XCLK    21\n#define CAM_PIN_SIOD    26\n#define CAM_PIN_SIOC    27\n\n#define CAM_PIN_D7      35\n#define CAM_PIN_D6      34\n#define CAM_PIN_D5      39\n#define CAM_PIN_D4      36\n#define CAM_PIN_D3      19\n#define CAM_PIN_D2      18\n#define CAM_PIN_D1       5\n#define CAM_PIN_D0       4\n#define CAM_PIN_VSYNC   25\n#define CAM_PIN_HREF    23\n#define CAM_PIN_PCLK    22\n\nstatic camera_config_t camera_config = {\n    .pin_pwdn  = CAM_PIN_PWDN,\n    .pin_reset = CAM_PIN_RESET,\n    .pin_xclk = CAM_PIN_XCLK,\n    .pin_sccb_sda = CAM_PIN_SIOD,\n    .pin_sccb_scl = CAM_PIN_SIOC,\n\n    .pin_d7 = CAM_PIN_D7,\n    .pin_d6 = CAM_PIN_D6,\n    .pin_d5 = CAM_PIN_D5,\n    .pin_d4 = CAM_PIN_D4,\n    .pin_d3 = CAM_PIN_D3,\n    .pin_d2 = CAM_PIN_D2,\n    .pin_d1 = CAM_PIN_D1,\n    .pin_d0 = CAM_PIN_D0,\n    .pin_vsync = CAM_PIN_VSYNC,\n    .pin_href = CAM_PIN_HREF,\n    .pin_pclk = CAM_PIN_PCLK,\n\n    .xclk_freq_hz = 20000000,//EXPERIMENTAL: Set to 16MHz on ESP32-S2 or ESP32-S3 to enable EDMA mode\n    .ledc_timer = LEDC_TIMER_0,\n    .ledc_channel = LEDC_CHANNEL_0,\n\n    .pixel_format = PIXFORMAT_JPEG,//YUV422,GRAYSCALE,RGB565,JPEG\n    .frame_size = FRAMESIZE_UXGA,//QQVGA-UXGA, For ESP32, do not use sizes above QVGA when not JPEG. The performance of the ESP32-S series has improved a lot, but JPEG mode always gives better frame rates.\n\n    .jpeg_quality = 12, //0-63, for OV series camera sensors, lower number means higher quality\n    .fb_count = 1, //When jpeg mode is used, if fb_count more than one, the driver will work in continuous mode.\n    .grab_mode = CAMERA_GRAB_WHEN_EMPTY//CAMERA_GRAB_LATEST. Sets when buffers should be filled\n};\n\nesp_err_t camera_init(){\n    //power up the camera if PWDN pin is defined\n    if(CAM_PIN_PWDN != -1){\n        pinMode(CAM_PIN_PWDN, OUTPUT);\n        digitalWrite(CAM_PIN_PWDN, LOW);\n    }\n\n    //initialize the camera\n    esp_err_t err = esp_camera_init(\u0026camera_config);\n    if (err != ESP_OK) {\n        ESP_LOGE(TAG, \"Camera Init Failed\");\n        return err;\n    }\n\n    return ESP_OK;\n}\n\nesp_err_t camera_capture(){\n    //acquire a frame\n    camera_fb_t * fb = esp_camera_fb_get();\n    if (!fb) {\n        ESP_LOGE(TAG, \"Camera Capture Failed\");\n        return ESP_FAIL;\n    }\n    //replace this with your own function\n    process_image(fb-\u003ewidth, fb-\u003eheight, fb-\u003eformat, fb-\u003ebuf, fb-\u003elen);\n  \n    //return the frame buffer back to the driver for reuse\n    esp_camera_fb_return(fb);\n    return ESP_OK;\n}\n```\n\n### JPEG HTTP Capture\n\n```c\n#include \"esp_camera.h\"\n#include \"esp_http_server.h\"\n#include \"esp_timer.h\"\n\ntypedef struct {\n        httpd_req_t *req;\n        size_t len;\n} jpg_chunking_t;\n\nstatic size_t jpg_encode_stream(void * arg, size_t index, const void* data, size_t len){\n    jpg_chunking_t *j = (jpg_chunking_t *)arg;\n    if(!index){\n        j-\u003elen = 0;\n    }\n    if(httpd_resp_send_chunk(j-\u003ereq, (const char *)data, len) != ESP_OK){\n        return 0;\n    }\n    j-\u003elen += len;\n    return len;\n}\n\nesp_err_t jpg_httpd_handler(httpd_req_t *req){\n    camera_fb_t * fb = NULL;\n    esp_err_t res = ESP_OK;\n    size_t fb_len = 0;\n    int64_t fr_start = esp_timer_get_time();\n\n    fb = esp_camera_fb_get();\n    if (!fb) {\n        ESP_LOGE(TAG, \"Camera capture failed\");\n        httpd_resp_send_500(req);\n        return ESP_FAIL;\n    }\n    res = httpd_resp_set_type(req, \"image/jpeg\");\n    if(res == ESP_OK){\n        res = httpd_resp_set_hdr(req, \"Content-Disposition\", \"inline; filename=capture.jpg\");\n    }\n\n    if(res == ESP_OK){\n        if(fb-\u003eformat == PIXFORMAT_JPEG){\n            fb_len = fb-\u003elen;\n            res = httpd_resp_send(req, (const char *)fb-\u003ebuf, fb-\u003elen);\n        } else {\n            jpg_chunking_t jchunk = {req, 0};\n            res = frame2jpg_cb(fb, 80, jpg_encode_stream, \u0026jchunk)?ESP_OK:ESP_FAIL;\n            httpd_resp_send_chunk(req, NULL, 0);\n            fb_len = jchunk.len;\n        }\n    }\n    esp_camera_fb_return(fb);\n    int64_t fr_end = esp_timer_get_time();\n    ESP_LOGI(TAG, \"JPG: %uKB %ums\", (uint32_t)(fb_len/1024), (uint32_t)((fr_end - fr_start)/1000));\n    return res;\n}\n```\n\n### JPEG HTTP Stream\n\n```c\n#include \"esp_camera.h\"\n#include \"esp_http_server.h\"\n#include \"esp_timer.h\"\n\n#define PART_BOUNDARY \"123456789000000000000987654321\"\nstatic const char* _STREAM_CONTENT_TYPE = \"multipart/x-mixed-replace;boundary=\" PART_BOUNDARY;\nstatic const char* _STREAM_BOUNDARY = \"\\r\\n--\" PART_BOUNDARY \"\\r\\n\";\nstatic const char* _STREAM_PART = \"Content-Type: image/jpeg\\r\\nContent-Length: %u\\r\\n\\r\\n\";\n\nesp_err_t jpg_stream_httpd_handler(httpd_req_t *req){\n    camera_fb_t * fb = NULL;\n    esp_err_t res = ESP_OK;\n    size_t _jpg_buf_len;\n    uint8_t * _jpg_buf;\n    char * part_buf[64];\n    static int64_t last_frame = 0;\n    if(!last_frame) {\n        last_frame = esp_timer_get_time();\n    }\n\n    res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);\n    if(res != ESP_OK){\n        return res;\n    }\n\n    while(true){\n        fb = esp_camera_fb_get();\n        if (!fb) {\n            ESP_LOGE(TAG, \"Camera capture failed\");\n            res = ESP_FAIL;\n            break;\n        }\n        if(fb-\u003eformat != PIXFORMAT_JPEG){\n            bool jpeg_converted = frame2jpg(fb, 80, \u0026_jpg_buf, \u0026_jpg_buf_len);\n            if(!jpeg_converted){\n                ESP_LOGE(TAG, \"JPEG compression failed\");\n                esp_camera_fb_return(fb);\n                res = ESP_FAIL;\n            }\n        } else {\n            _jpg_buf_len = fb-\u003elen;\n            _jpg_buf = fb-\u003ebuf;\n        }\n\n        if(res == ESP_OK){\n            res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));\n        }\n        if(res == ESP_OK){\n            size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);\n\n            res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);\n        }\n        if(res == ESP_OK){\n            res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);\n        }\n        if(fb-\u003eformat != PIXFORMAT_JPEG){\n            free(_jpg_buf);\n        }\n        esp_camera_fb_return(fb);\n        if(res != ESP_OK){\n            break;\n        }\n        int64_t fr_end = esp_timer_get_time();\n        int64_t frame_time = fr_end - last_frame;\n        last_frame = fr_end;\n        frame_time /= 1000;\n        ESP_LOGI(TAG, \"MJPG: %uKB %ums (%.1ffps)\",\n            (uint32_t)(_jpg_buf_len/1024),\n            (uint32_t)frame_time, 1000.0 / (uint32_t)frame_time);\n    }\n\n    last_frame = 0;\n    return res;\n}\n```\n\n### BMP HTTP Capture\n\n```c\n#include \"esp_camera.h\"\n#include \"esp_http_server.h\"\n#include \"esp_timer.h\"\n\nesp_err_t bmp_httpd_handler(httpd_req_t *req){\n    camera_fb_t * fb = NULL;\n    esp_err_t res = ESP_OK;\n    int64_t fr_start = esp_timer_get_time();\n\n    fb = esp_camera_fb_get();\n    if (!fb) {\n        ESP_LOGE(TAG, \"Camera capture failed\");\n        httpd_resp_send_500(req);\n        return ESP_FAIL;\n    }\n\n    uint8_t * buf = NULL;\n    size_t buf_len = 0;\n    bool converted = frame2bmp(fb, \u0026buf, \u0026buf_len);\n    esp_camera_fb_return(fb);\n    if(!converted){\n        ESP_LOGE(TAG, \"BMP conversion failed\");\n        httpd_resp_send_500(req);\n        return ESP_FAIL;\n    }\n\n    res = httpd_resp_set_type(req, \"image/x-windows-bmp\")\n       || httpd_resp_set_hdr(req, \"Content-Disposition\", \"inline; filename=capture.bmp\")\n       || httpd_resp_send(req, (const char *)buf, buf_len);\n    free(buf);\n    int64_t fr_end = esp_timer_get_time();\n    ESP_LOGI(TAG, \"BMP: %uKB %ums\", (uint32_t)(buf_len/1024), (uint32_t)((fr_end - fr_start)/1000));\n    return res;\n}\n```\n\n# Important Links\n\n[ESP-IDF Programming Guide](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/index.html)\n\n[CESP Standard Toolchain Setup for Linux ](https://docs.espressif.com/projects/esp-idf/en/stable/esp32/get-started/linux-macos-setup.html)\n\n[esp-idf github](https://github.com/espressif/esp-idf)\n\n[esp32-camera github](https://github.com/espressif/esp32-camera)\n\n[How to Program / Upload Code to ESP32-CAM AI-Thinker (Arduino IDE)](https://randomnerdtutorials.com/program-upload-code-esp32-cam/)\n\n[ESP32 Cam Project Development Example on Ubuntu](https://reversepcb.com/esp32-cam-project-development-example-on-ubuntu/)\n\n[ESP32-CAM-Linux-Motion](https://github.com/xenpac/ESP32-CAM-Linux-Motion)\n\n[AI_Thinker-ESP32-cam](https://github.com/prusa3d/Prusa-Firmware-ESP32-Cam/blob/master/doc/AI_Thinker-ESP32-cam/README.md)\n\n[camera datasheet](./docs/ov2640_ds_1.8_.pdf)\n\n[schematic](./docs/esp32_cam_sch.pdf)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdogusyuksel%2Fesp32-cam","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdogusyuksel%2Fesp32-cam","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdogusyuksel%2Fesp32-cam/lists"}