Open SunboX opened 5 years ago
I'm also interested in that :)
https://www.unifore.net/ip-video-surveillance/yoosee-wi-fi-camera-rtsp-stream-to-youtube-live.html https://www.stephenwagner.com/2016/11/10/rtsp-to-rtmp-ip-camera-to-youtube-live-streaming/ https://stackoverflow.com/questions/4010019/rtsp-to-rtmp-streaming
tl;dr: esp32-cam -> any pc with ffmpeg -> youtube
Without a PC. 😉 Should be possible with ESP32 only, but I don't know how. Should have enough power and it already can stream to a PC.
Highly interested in this!
I'm super interested in this
Did somebody find something? Or is it impossible?
you can import the camera rtsp to OBS and output to youtube from there
Hy dude im interest too 😍 directly from esp32cam as client to youtube live as server 😍
is any one solve it ?
Old post but, NOPE guys! RTMP is only protocol, but reciving server need A/V in supported codec i gues for twitch and youtube be the same so h.264 for video and AAC for audio. On ESP32-CAM and others we have only video. But simple they can not send video in h.264. This board send only pictures in mjpeg copresion. Cheapest solution is rpi zero ;)
Another solution for that would be: use VLC to bridge the ESP32-CAM to the Youtube.
If you use a web stream instead a rtsp stream you can send this stream to youtube https://www.youtube.com/watch?v=l_j71Dzhlx0&ab_channel=TheHackLife
Without a PC. wink Should be possible with ESP32 only, but I don't know how. Should have enough power and it already can stream to a PC.
You are asking about RTMP.
This software does RTSP.
These are not the same thing.
This Arduino code for ESP-32 CAM, sends the video to the specified server:
#include <WiFi.h>
#include <WiFiUdp.h>
#include "soc/soc.h"
#include "soc/rtc_cntl_reg.h"
#include "esp_camera.h"
const char * networkName = "SSID Wi-Fi";
const char * networkPswd = "PASSWORD Wi-Fi";
const char * udpAddress = "server IP-address"; // <= Here I entered the address of my VPS server on the Internet
const int udpPort = 20001; // <= Here UDP port on which PHP script listens
int counter = 1;
// Pin definition for CAMERA_MODEL_AI_THINKER
#define PWDN_GPIO_NUM 32
#define RESET_GPIO_NUM -1
#define XCLK_GPIO_NUM 0
#define SIOD_GPIO_NUM 26
#define SIOC_GPIO_NUM 27
#define Y9_GPIO_NUM 35
#define Y8_GPIO_NUM 34
#define Y7_GPIO_NUM 39
#define Y6_GPIO_NUM 36
#define Y5_GPIO_NUM 21
#define Y4_GPIO_NUM 19
#define Y3_GPIO_NUM 18
#define Y2_GPIO_NUM 5
#define VSYNC_GPIO_NUM 25
#define HREF_GPIO_NUM 23
#define PCLK_GPIO_NUM 22
void setupCamera()
{
camera_config_t config;
config.ledc_channel = LEDC_CHANNEL_0;
config.ledc_timer = LEDC_TIMER_0;
config.pin_d0 = Y2_GPIO_NUM;
config.pin_d1 = Y3_GPIO_NUM;
config.pin_d2 = Y4_GPIO_NUM;
config.pin_d3 = Y5_GPIO_NUM;
config.pin_d4 = Y6_GPIO_NUM;
config.pin_d5 = Y7_GPIO_NUM;
config.pin_d6 = Y8_GPIO_NUM;
config.pin_d7 = Y9_GPIO_NUM;
config.pin_xclk = XCLK_GPIO_NUM;
config.pin_pclk = PCLK_GPIO_NUM;
config.pin_vsync = VSYNC_GPIO_NUM;
config.pin_href = HREF_GPIO_NUM;
config.pin_sscb_sda = SIOD_GPIO_NUM;
config.pin_sscb_scl = SIOC_GPIO_NUM;
config.pin_pwdn = PWDN_GPIO_NUM;
config.pin_reset = RESET_GPIO_NUM;
config.xclk_freq_hz = 20000000;
config.pixel_format = PIXFORMAT_JPEG;
//
// WARNING!!! PSRAM IC required for UXGA resolution and high JPEG quality
// Ensure ESP32 Wrover Module or other board with PSRAM is selected
// Partial images will be transmitted if image exceeds buffer size
//
// if PSRAM IC present, init with UXGA resolution and higher JPEG quality
// for larger pre-allocated frame buffer.
if(psramFound()){ //是否有PSRAM(Psuedo SRAM)記憶體IC
config.frame_size = FRAMESIZE_UXGA;
config.jpeg_quality = 10;
config.fb_count = 2;
} else {
config.frame_size = FRAMESIZE_SVGA;
config.jpeg_quality = 12;
config.fb_count = 1;
}
//視訊初始化
esp_err_t err = esp_camera_init(&config);
if (err != ESP_OK) {
Serial.printf("Camera init failed with error 0x%x", err);
ESP.restart();
}
//可自訂視訊框架預設大小(解析度大小)
sensor_t * s = esp_camera_sensor_get();
// initial sensors are flipped vertically and colors are a bit saturated
if (s->id.PID == OV3660_PID) {
s->set_vflip(s, 1); // flip it back
s->set_brightness(s, 1); // up the brightness just a bit
s->set_saturation(s, -2); // lower the saturation
}
// drop down frame size for higher initial frame rate
s->set_framesize(s, FRAMESIZE_QVGA); //解析度 SVGA(800x600), VGA(640x480), CIF(400x296), QVGA(320x240), HQVGA(240x176), QQVGA(160x120), QXGA(2048x1564 for OV3660)
//s->set_vflip(s, 1); //垂直翻轉
//s->set_hmirror(s, 1); //水平鏡像
//閃光燈(GPIO4)
//ledcAttachPin(4, 4);
//ledcSetup(4, 5000, 8);
}
//Are we currently connected?
boolean connected = false;
//The udp library class
WiFiUDP udp;
void setup(){
WRITE_PERI_REG(RTC_CNTL_BROWN_OUT_REG, 0); //關閉電源不穩就重開機的設定
Serial.begin(115200);
randomSeed(micros());
setupCamera();
connectToWiFi(networkName, networkPswd);
}
void loop(){
delay(10);
if(connected){
camera_fb_t * fb = NULL;
fb = esp_camera_fb_get();
if(!fb) {
Serial.println("Camera capture failed");
delay(100);
ESP.restart();
}
udp.beginPacket(udpAddress,udpPort);
udp.write(fb->buf, fb->len);
udp.endPacket();
Serial.println(fb->len);
esp_camera_fb_return(fb);
fb = NULL;
}
}
void connectToWiFi(const char * ssid, const char * pwd){
Serial.println("Connecting to WiFi network: " + String(ssid));
// delete old config
WiFi.disconnect(true);
//register event handler
WiFi.onEvent(WiFiEvent);
//Initiate connection
WiFi.begin(ssid, pwd);
Serial.println("Waiting for WIFI connection...");
}
//wifi event handler
void WiFiEvent(WiFiEvent_t event){
switch(event) {
case SYSTEM_EVENT_STA_GOT_IP:
//When connected set
Serial.print("WiFi connected! IP address: ");
Serial.println(WiFi.localIP());
//initializes the UDP state
//This initializes the transfer buffer
udp.begin(WiFi.localIP(),udpPort);
connected = true;
break;
case SYSTEM_EVENT_STA_DISCONNECTED:
Serial.println("WiFi lost connection");
connected = false;
break;
default: break;
}
}
This is a PHP script that I have hosted on my VPS server:
<?php
//error_reporting(E_ALL);ini_set('display_errors', 1);
set_time_limit(200);
$start = time();
$boundary = 'boundary';
header('Content-type: multipart/x-mixed-replace; boundary=' . $boundary);
ob_implicit_flush();
if(!($socket = socket_create(AF_INET, SOCK_DGRAM, SOL_UDP))){
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Couldn't create socket: [$errorcode] $errormsg \n");
}
if( !socket_set_nonblock($socket) ){
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not nonblock socket : [$errorcode] $errormsg \n");
}
if( !socket_bind($socket, "XX.XX.XX.XX" , 20001 ) ){ // <=============My VPS Server IP
$errorcode = socket_last_error();
$errormsg = socket_strerror($errorcode);
die("Could not bind socket : [$errorcode] $errormsg \n");
}
socket_set_option($socket, SOL_SOCKET, SO_RCVTIMEO, array("sec"=>2, "usec"=>100));
socket_set_option($socket, SOL_SOCKET, SO_SNDTIMEO, array("sec"=>2, "usec"=>100));
$image = "";
$est_start = false;
$count_old = 0;
$r_bin = "";
$text = "";
$frlen = 0;
$chunk_arr = [];
$nulcount = 0;
$framecount = 1;
$time_start = microtime(true);
$fps = 0;
try {
while(1){
if (time()-$start>300) die; // время работы скрипта, можно убрать
usleep(0.0001 * 1000000); // 0.5 seconds
$r = socket_read($socket, 20000);
$r_hex = bin2hex($r);
if (strlen($r_hex)==0) {
$nulcount++;
}
if (strlen($r_hex)!=0){
if ($est_start) {
$image = $image.$r_hex;
$frlen = $frlen + strlen($r);
$chunk_arr[] = $r_hex;
}
if (substr($r_hex,0,4)=="ffd8"){ // если фрагмент это начало картинки
$chunk_arr = [];
$chunk_arr[] = $r_hex;
$est_start = true;
$image = $r_hex;
$text = "";
$frlen = strlen($r);
} else if (substr($r_hex,-4,4)=="ffd9" and $est_start){ // если фрагмент это конец картинки + перед этим было начало картинки
while(strlen($r_check = socket_read($socket, 30000))==0){
usleep(0.0001 * 1000000);
}
$r_check = bin2hex($r_check);
if (substr($r_check,0,4)!="ffd8"){
$skip_read_once = false;
$last_chunk = $chunk_arr[sizeof($chunk_arr)-1];
$chunk_arr[sizeof($chunk_arr)-1] = $r_check;
$chunk_arr[] = $last_chunk;
$image = implode("",$chunk_arr);
$text = " add prev chunk";
} else if (substr($r_check,0,4)=="ffd8"){
$image = implode("",$chunk_arr);
$chunk_arr = [];
$chunk_arr[] = $r_check;
$est_start = true;
$frlen = strlen($r);
}
$est_start = false;
if (microtime(true)-$time_start>1 and microtime(true)-$time_start<5){
$time_end = microtime(true)-$time_start;
$fps = intval($framecount/$time_end);
$framecount = 0;
$time_start = microtime(true);
}
echo 'Content-type: image/jpeg', PHP_EOL, PHP_EOL;
$framecount++;
$im = imagecreatefromstring(hex2bin($image));
$color = imagecolorallocate($im, 255, 255, 255);
imagestring($im, 5, 10, 20, "fps:".$fps." ".imagesx($im)."x".imagesy($im)." ".date("d.m.Y H:i:s")." ".$text, $color);
imagejpeg($im);
imagedestroy($im);
echo '--', $boundary, PHP_EOL;
$image = "";
$text = "";
$frlen = 0;
}
}
}
} finally {
socket_close($socket);
}
?>
When I turned on the ESP-32 CAM and then opened the page with the PHP script on my server, in the browser I saw an image from my ESP-32 CAM camera. I still didn't believe it worked. The author of the codes claims that the ESP-32 CAM works like an RSTP client that streams to the server. Now, just like you, I am looking for a way to stream video from my ESP-32 CAM to my server, because I do not have a permanent IP address for the ESP-32 CAM, so I am interested in the camera transmitting the stream to the server, because the server can't pick up the stream from the camera. Now I want to stream to the NGNX server, because it has a module for working with RTMP, I have already configured the server, I want to try streaming from this camera to my RTMP server. Video as work from the author of the scripts: https://www.youtube.com/watch?v=-BvSkXWC-EE I express special gratitude to the author of the video. He really did an incredible thing, he just took and streamed the video to the server! I just shared this, maybe it will be useful to someone. I hope that maybe someone will be able to adapt this script in order to send an RTMP stream to the NGNIX server or to send an RTSP stream.
Do you have any sample on how to stream the camera output to YouTube using a ESP32-CAM module?
rtmp://a.rtmp.youtube.com/live2/[your-secret-key-here]
Or is it impossible?