当前位置:   article > 正文

ESP32-CAM网络摄像头系列-01-基于RTSP协议的局域网视频推流/拉流的简单实现_espcam 视频流传输

espcam 视频流传输

前言:

        由于项目需要,最近开始开坑关于ESP32-CAM系列的RTSP网络摄像头系列,该文章为该系列的第一篇文章。用于记录项目开发过程。

本文解决的问题:

        使用ESP32-CAM获取图像数据,并通过RTSP协议将获取到的视频流传输到上位机进行显示。

具体实现:

        使用ESP32-CAM进行视频推流,python端作为rtsp拉流,其中ESP32-CAM使用arduinoIDE开发,使用了安信可的支持库。支持包安装网址:

拉流效果:

一、推流部分

官方示例代码:

  1. #include "OV2640.h"
  2. #include <WiFi.h>
  3. #include <WebServer.h>
  4. #include <WiFiClient.h>
  5. #include "SimStreamer.h"
  6. #include "OV2640Streamer.h"
  7. #include "CRtspSession.h"
  8. #define ENABLE_RTSPSERVER
  9. OV2640 cam;
  10. #ifdef ENABLE_WEBSERVER
  11. WebServer server(80);
  12. #endif
  13. #ifdef ENABLE_RTSPSERVER
  14. WiFiServer rtspServer(8554);
  15. #endif
  16. #ifdef SOFTAP_MODE
  17. IPAddress apIP = IPAddress(192, 168, 1, 1);
  18. #else
  19. #include "wifikeys_template.h"
  20. #endif
  21. #ifdef ENABLE_WEBSERVER
  22. void handle_jpg_stream(void)
  23. {
  24. WiFiClient client = server.client();
  25. String response = "HTTP/1.1 200 OK\r\n";
  26. response += "Content-Type: multipart/x-mixed-replace; boundary=frame\r\n\r\n";
  27. server.sendContent(response);
  28. while (1)
  29. {
  30. cam.run();
  31. if (!client.connected())
  32. break;
  33. response = "--frame\r\n";
  34. response += "Content-Type: image/jpeg\r\n\r\n";
  35. server.sendContent(response);
  36. client.write((char *)cam.getfb(), cam.getSize());
  37. server.sendContent("\r\n");
  38. if (!client.connected())
  39. break;
  40. }
  41. }
  42. void handle_jpg(void)
  43. {
  44. WiFiClient client = server.client();
  45. cam.run();
  46. if (!client.connected())
  47. {
  48. return;
  49. }
  50. String response = "HTTP/1.1 200 OK\r\n";
  51. response += "Content-disposition: inline; filename=capture.jpg\r\n";
  52. response += "Content-type: image/jpeg\r\n\r\n";
  53. server.sendContent(response);
  54. client.write((char *)cam.getfb(), cam.getSize());
  55. }
  56. void handleNotFound()
  57. {
  58. String message = "Server is running!\n\n";
  59. message += "URI: ";
  60. message += server.uri();
  61. message += "\nMethod: ";
  62. message += (server.method() == HTTP_GET) ? "GET" : "POST";
  63. message += "\nArguments: ";
  64. message += server.args();
  65. message += "\n";
  66. server.send(200, "text/plain", message);
  67. }
  68. #endif
  69. #ifdef ENABLE_OLED
  70. #define LCD_MESSAGE(msg) lcdMessage(msg)
  71. #else
  72. #define LCD_MESSAGE(msg)
  73. #endif
  74. #ifdef ENABLE_OLED
  75. void lcdMessage(String msg)
  76. {
  77. if(hasDisplay) {
  78. display.clear();
  79. display.drawString(128 / 2, 32 / 2, msg);
  80. display.display();
  81. }
  82. }
  83. #endif
  84. CStreamer *streamer;
  85. void setup()
  86. {
  87. #ifdef ENABLE_OLED
  88. hasDisplay = display.init();
  89. if(hasDisplay) {
  90. display.flipScreenVertically();
  91. display.setFont(ArialMT_Plain_16);
  92. display.setTextAlignment(TEXT_ALIGN_CENTER);
  93. }
  94. #endif
  95. LCD_MESSAGE("booting");
  96. Serial.begin(115200);
  97. while (!Serial)
  98. {
  99. ;
  100. }
  101. cam.init(esp32cam_aithinker_config);
  102. IPAddress ip;
  103. #ifdef SOFTAP_MODE
  104. const char *hostname = "devcam";
  105. // WiFi.hostname(hostname); // FIXME - find out why undefined
  106. LCD_MESSAGE("starting softAP");
  107. WiFi.mode(WIFI_AP);
  108. WiFi.softAPConfig(apIP, apIP, IPAddress(255, 255, 255, 0));
  109. bool result = WiFi.softAP(hostname, "12345678", 1, 0);
  110. if (!result)
  111. {
  112. Serial.println("AP Config failed.");
  113. return;
  114. }
  115. else
  116. {
  117. Serial.println("AP Config Success.");
  118. Serial.print("AP MAC: ");
  119. Serial.println(WiFi.softAPmacAddress());
  120. ip = WiFi.softAPIP();
  121. }
  122. #else
  123. LCD_MESSAGE(String("join ") + ssid);
  124. WiFi.mode(WIFI_STA);
  125. WiFi.begin(ssid, password);
  126. while (WiFi.status() != WL_CONNECTED)
  127. {
  128. delay(500);
  129. Serial.print(F("."));
  130. }
  131. ip = WiFi.localIP();
  132. Serial.println(F("WiFi connected"));
  133. Serial.println("");
  134. Serial.println(ip);
  135. #endif
  136. LCD_MESSAGE(ip.toString());
  137. #ifdef ENABLE_WEBSERVER
  138. server.on("/", HTTP_GET, handle_jpg_stream);
  139. server.on("/jpg", HTTP_GET, handle_jpg);
  140. server.onNotFound(handleNotFound);
  141. server.begin();
  142. #endif
  143. #ifdef ENABLE_RTSPSERVER
  144. rtspServer.begin();
  145. //streamer = new SimStreamer(true); // our streamer for UDP/TCP based RTP transport
  146. streamer = new OV2640Streamer(cam); // our streamer for UDP/TCP based RTP transport
  147. #endif
  148. }
  149. void loop()
  150. {
  151. #ifdef ENABLE_WEBSERVER
  152. server.handleClient();
  153. #endif
  154. #ifdef ENABLE_RTSPSERVER
  155. uint32_t msecPerFrame = 100;
  156. static uint32_t lastimage = millis();
  157. // If we have an active client connection, just service that until gone
  158. streamer->handleRequests(0); // we don't use a timeout here,
  159. // instead we send only if we have new enough frames
  160. uint32_t now = millis();
  161. if(streamer->anySessions()) {
  162. if(now > lastimage + msecPerFrame || now < lastimage) { // handle clock rollover
  163. streamer->streamImage(now);
  164. lastimage = now;
  165. // check if we are overrunning our max frame rate
  166. now = millis();
  167. if(now > lastimage + msecPerFrame) {
  168. printf("warning exceeding max frame rate of %d ms\n", now - lastimage);
  169. }
  170. }
  171. }
  172. WiFiClient rtspClient = rtspServer.accept();
  173. if(rtspClient) {
  174. Serial.print("client: ");
  175. Serial.print(rtspClient.remoteIP());
  176. Serial.println();
  177. streamer->addSession(rtspClient);
  178. }
  179. #endif
  180. }

        对于ESP32的RTSP推流安信可官方已经给出了相应的示例代码,改代码使用宏定义的方式区分http和rtsp协议的不同代码。由于我们不需要用到基于http协议的视频推流,因此可以删去官方代码中不必要的部分。修改完的代码如下:

ESP32部分的代码由官方示例代码修改而来。只保留RTSP推流部分。

  1. #include "OV2640.h"
  2. #include <WiFi.h>
  3. #include <WebServer.h>
  4. #include <WiFiClient.h>
  5. #include "SimStreamer.h"
  6. #include "OV2640Streamer.h"
  7. #include "CRtspSession.h"
  8. // copy this file to wifikeys.h and edit
  9. const char *ssid = "YAN"; // Put your SSID here
  10. const char *password = "qwertyuiop"; // Put your PASSWORD here
  11. #define ENABLE_RTSPSERVER
  12. OV2640 cam;
  13. WiFiServer rtspServer(8554);
  14. CStreamer *streamer;
  15. void setup()
  16. {
  17. Serial.begin(115200);
  18. while (!Serial);
  19. cam.init(esp32cam_aithinker_config);
  20. IPAddress ip;
  21. WiFi.mode(WIFI_STA);
  22. WiFi.begin(ssid, password);
  23. while (WiFi.status() != WL_CONNECTED)
  24. {
  25. delay(500);
  26. Serial.print(F("."));
  27. }
  28. ip = WiFi.localIP();
  29. Serial.println(F("WiFi connected"));
  30. Serial.println("");
  31. Serial.println(ip);
  32. rtspServer.begin();
  33. //streamer = new SimStreamer(true); // our streamer for UDP/TCP based RTP transport
  34. streamer = new OV2640Streamer(cam); // our streamer for UDP/TCP based RTP transport
  35. }
  36. void loop()
  37. {
  38. uint32_t msecPerFrame = 100;
  39. static uint32_t lastimage = millis();
  40. // If we have an active client connection, just service that until gone
  41. streamer->handleRequests(0); // we don't use a timeout here,
  42. // instead we send only if we have new enough frames
  43. uint32_t now = millis();
  44. if(streamer->anySessions()) {
  45. if(now > lastimage + msecPerFrame || now < lastimage) { // handle clock rollover
  46. streamer->streamImage(now);
  47. lastimage = now;
  48. // check if we are overrunning our max frame rate
  49. now = millis();
  50. if(now > lastimage + msecPerFrame) {
  51. printf("warning exceeding max frame rate of %d ms\n", now - lastimage);
  52. }
  53. }
  54. }
  55. WiFiClient rtspClient = rtspServer.accept();
  56. if(rtspClient) {
  57. Serial.print("client: ");
  58. Serial.print(rtspClient.remoteIP());
  59. Serial.println();
  60. streamer->addSession(rtspClient);
  61. }
  62. }

ArduinoIDE串口监视器输出的初始化信息,我们需要将ESP32的IP地址安装RTSP协议推流的格式填入Python拉流代码中。

# RTSP 地址
rtsp_url = "rtsp://192.168.168.238:8554/mjpeg/2"

 二、拉流部分

        由于Opencv-python集成了RTSP协议拉流的库函数,因此我们需要下载Opencv-python的支持包。可以打开Pycharm的Terminal使用pip指令快速下载。

pip install opencv-python

 上位机python3拉流代码:

  1. import cv2
  2. # RTSP 地址
  3. rtsp_url = "rtsp://192.168.168.238:8554/mjpeg/2"
  4. # 打开 RTSP 视频流
  5. cap = cv2.VideoCapture(rtsp_url)
  6. # 检查视频是否成功打开
  7. if not cap.isOpened():
  8. print("Failed to open RTSP stream")
  9. exit()
  10. # 循环读取视频帧
  11. while True:
  12. # 读取视频帧
  13. ret, frame = cap.read()
  14. # 检查是否成功读取视频帧
  15. if not ret:
  16. break
  17. # 显示视频帧
  18. cv2.imshow("RTSP Stream", frame)
  19. # 按 'q' 键退出循环
  20. if cv2.waitKey(1) & 0xFF == ord('q'):
  21. break
  22. # 释放资源
  23. cap.release()
  24. cv2.destroyAllWindows()

PS:需要注意的是,进行RTSP拉流的上位机和推流的下位机都需要位于同一个局域网下才能进行推拉流传输。

声明:本文内容由网友自发贡献,不代表【wpsshop博客】立场,版权归原作者所有,本站不承担相应法律责任。如您发现有侵权的内容,请联系我们。转载请注明出处:https://www.wpsshop.cn/w/Cpp五条/article/detail/383359
推荐阅读
相关标签
  

闽ICP备14008679号