geeksville / Micro-RTSP

A RTSP video server intended for very small CPUs (ESP32 etc)
MIT License
755 stars 199 forks source link

How to stream to YouTube? #19

Open SunboX opened 4 years ago

SunboX commented 4 years ago

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?

radzio commented 4 years ago

I'm also interested in that :)

bartlomiejcieszkowski commented 4 years ago

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

SunboX commented 4 years ago

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.

wistoff commented 4 years ago

Highly interested in this!

aieseres commented 3 years ago

I'm super interested in this

Adrianahwjsgsj commented 3 years ago

Did somebody find something? Or is it impossible?

jimthedj65 commented 3 years ago

you can import the camera rtsp to OBS and output to youtube from there

fazaio commented 3 years ago

Hy dude im interest too 😍 directly from esp32cam as client to youtube live as server 😍

znsoft commented 2 years ago

is any one solve it ?

ddamianus commented 2 years ago

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 ;)

arthurd2 commented 2 years ago

Another solution for that would be: use VLC to bridge the ESP32-CAM to the Youtube.

OPinedaCoink commented 1 year ago

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

StripeyType commented 1 year ago

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.

US4LKW commented 1 year ago

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.