2023-07-29

Display a stream from a server using QT

So i have a project that consist of two systems an ESP32 with camera and a QT App. I built the ESP32 to stream a video on a server hosted on the ESP32 board. I want now to get this video stream and show it on a QT app but I could not find a way to show the video. I used a GraphicsView to display the video but it think this approach is false. So any suggestions on how to do that?

Here is my code that I wrote to get the stream. I receive some data from the server but I could not display the streaming.

#include "mainwindow.h"
#include "ui_mainwindow.h"

MainWindow::MainWindow(QWidget *parent):QMainWindow(parent), ui(new Ui::MainWindow)
{
    ui->setupUi(this);

    // Create the QGraphicsScene and set it to the Graphics View
    scene = new QGraphicsScene(this);
    ui->VideoStreamer->setScene(scene);

    // Initialize the network manager
    networkManager = new QNetworkAccessManager(this);

    // Start the video streaming request
    QUrl videoUrl("http://192.168.8.228:81/stream");
    networkReply = networkManager->get(QNetworkRequest(videoUrl));

    // Connect the readyRead signal to the onVideoStreamReadyRead slot
    connect(networkReply, &QNetworkReply::readyRead, this, &MainWindow::onVideoStreamReadyRead);
}

MainWindow::~MainWindow()
{
  delete ui;
}

void MainWindow::onVideoStreamReadyRead()
{
   // Read the incoming video data and display it in the QGraphicsView
   if (networkReply->error() == QNetworkReply::NoError)
   {
      QByteArray data = networkReply->readAll();
      qDebug() << "Received data size:" << data.size(); //Add this line for debugging

      QPixmap pixmap;
      pixmap.loadFromData(data);
      scene->clear();
      scene->addPixmap(pixmap);
   }
   else
   {
      qDebug() << "Network error:" << networkReply->errorString(); // Add this line for debugging
   }
}

And this is the ESP32 code that creates the stream on the local server. The server can be opened in the browser if the computer is connected to the same wifi as the esp32 board.

//Configurations for the stream
#define PART_BOUNDARY "123456789000000000000987654321"
static const char* _STREAM_CONTENT_TYPE = "multipart/x-mixed-replace;boundary=" PART_BOUNDARY;
static const char* _STREAM_BOUNDARY = "\r\n--" PART_BOUNDARY "\r\n";
static const char* _STREAM_PART = "Content-Type: image/jpeg\r\nContent-Length: %u\r\n\r\n";

httpd_handle_t cameraHttpd = NULL;
httpd_handle_t streamHttpd = NULL; // Two servers for the stream and main one

esp_err_t HttpServerHandler::streamHandler(httpd_req_t *req){
  camera_fb_t * fb = NULL;
  esp_err_t res = ESP_OK;
  size_t _jpg_buf_len = 0;
  uint8_t * _jpg_buf = NULL;
  char * part_buf[64];

  res = httpd_resp_set_type(req, _STREAM_CONTENT_TYPE);
  if(res != ESP_OK){
    return res;
  }

  while(true){
    fb = esp_camera_fb_get();
    if (!fb) {
      Serial.println("Camera capture failed");
      res = ESP_FAIL;
    } else {
      if(fb->width > 400){
        if(fb->format != PIXFORMAT_JPEG){
          bool jpeg_converted = frame2jpg(fb, 80, &_jpg_buf, &_jpg_buf_len);
          esp_camera_fb_return(fb);
          fb = NULL;
          if(!jpeg_converted){
            Serial.println("JPEG compression failed");
            res = ESP_FAIL;
          }
        } else {
          _jpg_buf_len = fb->len;
          _jpg_buf = fb->buf;
        }
      }
    }
    if(res == ESP_OK){
      size_t hlen = snprintf((char *)part_buf, 64, _STREAM_PART, _jpg_buf_len);
      res = httpd_resp_send_chunk(req, (const char *)part_buf, hlen);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, (const char *)_jpg_buf, _jpg_buf_len);
    }
    if(res == ESP_OK){
      res = httpd_resp_send_chunk(req, _STREAM_BOUNDARY, strlen(_STREAM_BOUNDARY));
    }
    if(fb){
      esp_camera_fb_return(fb);
      fb = NULL;
      _jpg_buf = NULL;
    } else if(_jpg_buf){
      free(_jpg_buf);
      _jpg_buf = NULL;
    }
    if(res != ESP_OK){
      break;
    }
  }
  return res;
}

void HttpServerHandler::startServer()
{
    httpd_config_t config = HTTPD_DEFAULT_CONFIG();
  config.server_port = 80;
  httpd_uri_t stream_uri = {
    .uri       = "/stream",
    .method    = HTTP_GET,
    .handler   = streamHandler,
    .user_ctx  = NULL
  };
  if (httpd_start(&cameraHttpd, &config) == ESP_OK) {
    httpd_register_uri_handler(cameraHttpd, &index_uri);
    httpd_register_uri_handler(cameraHttpd, &cmd_uri);
  }
  config.server_port += 1;
  config.ctrl_port += 1;
  if (httpd_start(&streamHttpd, &config) == ESP_OK) {
    httpd_register_uri_handler(streamHttpd, &stream_uri);
  }
}

Streaming server opened in browser.



No comments:

Post a Comment