ソースを参照

Add RTSP Camera Type

JDierkse 4 年 前
コミット
269b300bfa
6 ファイル変更232 行追加68 行削除
  1. 89 68
      API/WebAPI.cpp
  2. 1 0
      Libraries/cppcodec
  3. 1 0
      Makefile.conf
  4. 99 0
      Recorder/RTSPRecorder.cpp
  5. 41 0
      Recorder/RTSPRecorder.h
  6. 1 0
      Recorder/Settings.h

+ 89 - 68
API/WebAPI.cpp

@@ -2,10 +2,13 @@
 #include "Recorder/Recorder.h"
 #include "Recorder/DigooRecorder.h"
 #include "Recorder/FoscamRecorder.h"
+#include "Recorder/RTSPRecorder.h"
 #include "Recorder/VStarCamRecorder.h"
 #include "Recorder/WatchBotRecorder.h"
 #include "Recorder/ZModoRecorder.h"
 #include <StringAlgorithm.h>
+#include <base64_url.hpp>
+#include <iostream>
 #include <memory>
 
 
@@ -17,7 +20,7 @@ namespace API {
 // Status Query
 // Goal:	Provide status information based on POST data
 // Use:		DomoticaSite status update
-// URL:		http://<ip>/API/<action>/<brand>/<ipaddress>/<port>/<username>/<password>
+// URL:		http://<ip>/API/<action>/<brand>/<ipaddress>/<port>/<url(base64)>/<username>/<password>
 
 WebAPI::WebAPI()
 {
@@ -40,78 +43,96 @@ Http::HttpServer::HttpReply WebAPI::ProcessQuery(ctpl::thread_pool* pThreadPool,
 	reply.status = Http::HttpServer::HttpReply::Status::InternalServerError;
 	reply.content = "{\"result\": \"error\"}\r\n";
 
-	std::string apiURI = uri.substr(4);
+	try {
+		std::string apiURI = uri.substr(4);
 
-	std::vector<std::string> uriTokens = StringAlgorithm::split(apiURI, '/');
+		std::vector<std::string> uriTokens = StringAlgorithm::split(apiURI, '/');
 
-	if (uriTokens.size() < 7)
+		if (uriTokens.size() < 7)
 			return reply;
 
-	std::string action = uriTokens[1];
-	std::string brand = uriTokens[2];
-
-	Recorder::Settings settings;
-	settings.Path = path;
-	settings.IpAddress = uriTokens[3];
-	settings.Port = uriTokens[4];
-	settings.Username = uriTokens[5];
-	settings.Password = uriTokens[6];
-
-	int numberOfImages = 5;
-	if (uriTokens.size() > 7)
-		numberOfImages = stoi(uriTokens[7]);
-
-	reply.status = Http::HttpServer::HttpReply::Status::Ok;
-	if (StringAlgorithm::iequals("Digoo", brand))
-	{
-		auto recorder = Recorder::DigooRecorder(pHttpClient, settings);
-		if (StringAlgorithm::iequals("Snapshot", action))
-			reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
-		else if (StringAlgorithm::iequals("MultiSnapshot", action))
-			reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
-		else if (StringAlgorithm::iequals("Video", action))
-			reply.content = recorder.Video(pThreadPool, ffmpeg);
-	}
-	else if (StringAlgorithm::iequals("Foscam", brand))
-	{
-		auto recorder = Recorder::FoscamRecorder(pHttpClient, settings);
-		if (StringAlgorithm::iequals("Snapshot", action))
-			reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
-		else if (StringAlgorithm::iequals("MultiSnapshot", action))
-			reply.content = recorder.MultiSnapshot(pThreadPool, numberOfImages);
-		else if (StringAlgorithm::iequals("Video", action))
-			reply.content = recorder.Video(pThreadPool, ffmpeg);
-	}
-	else if (StringAlgorithm::iequals("VStarCam", brand))
-	{
-		auto recorder = Recorder::VStarCamRecorder(pHttpClient, settings);
-		if (StringAlgorithm::iequals("Snapshot", action))
-			reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
-		else if (StringAlgorithm::iequals("MultiSnapshot", action))
-			reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
-		else if (StringAlgorithm::iequals("Video", action))
-			reply.content = recorder.Video(pThreadPool, ffmpeg);
-	}
-	else if (StringAlgorithm::iequals("WatchBot", brand))
-	{
-		auto recorder = Recorder::WatchBotRecorder(pHttpClient, settings);
-		if (StringAlgorithm::iequals("Snapshot", action))
-			reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
-		else if (StringAlgorithm::iequals("MultiSnapshot", action))
-			reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
-		else if (StringAlgorithm::iequals("Video", action))
-			reply.content = recorder.Video(pThreadPool, ffmpeg);
-	}
-	else if (StringAlgorithm::iequals("ZModo", brand))
-	{
-		auto recorder = Recorder::ZModoRecorder(pHttpClient, settings);
-		if (StringAlgorithm::iequals("Snapshot", action))
-			reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
-		else if (StringAlgorithm::iequals("MultiSnapshot", action))
-			reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
-		else if (StringAlgorithm::iequals("Video", action))
-			reply.content = recorder.Video(pThreadPool, ffmpeg);
+		std::string action = uriTokens[1];
+		std::string brand = uriTokens[2];
+
+		Recorder::Settings settings;
+		settings.Path = path;
+		settings.IpAddress = uriTokens[3];
+		settings.Port = uriTokens[4];
+		settings.URL = cppcodec::base64_url::decode<std::string>(uriTokens[5].c_str(), uriTokens[5].length());
+		settings.Username = uriTokens[6];
+		settings.Password = uriTokens[7];
+
+		int numberOfImages = 5;
+		if (uriTokens.size() > 8)
+			numberOfImages = stoi(uriTokens[8]);
+
+		reply.status = Http::HttpServer::HttpReply::Status::Ok;
+		if (StringAlgorithm::iequals("Digoo", brand))
+		{
+			auto recorder = Recorder::DigooRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
+		else if (StringAlgorithm::iequals("Foscam", brand))
+		{
+			auto recorder = Recorder::FoscamRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
+		else if (StringAlgorithm::iequals("RTSP", brand))
+		{
+			auto recorder = Recorder::RTSPRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
+		else if (StringAlgorithm::iequals("VStarCam", brand))
+		{
+			auto recorder = Recorder::VStarCamRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
+		else if (StringAlgorithm::iequals("WatchBot", brand))
+		{
+			auto recorder = Recorder::WatchBotRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
+		else if (StringAlgorithm::iequals("ZModo", brand))
+		{
+			auto recorder = Recorder::ZModoRecorder(pHttpClient, settings);
+			if (StringAlgorithm::iequals("Snapshot", action))
+				reply.content = recorder.Snapshot(pThreadPool, ffmpeg);
+			else if (StringAlgorithm::iequals("MultiSnapshot", action))
+				reply.content = recorder.MultiSnapshot(pThreadPool, ffmpeg, numberOfImages);
+			else if (StringAlgorithm::iequals("Video", action))
+				reply.content = recorder.Video(pThreadPool, ffmpeg);
+		}
 	}
+	catch (const std::exception& e)
+        {
+                std::cout << "WebAPI::ProcessQuery() - Error: " << e.what() << std::endl;
+                return reply;
+        }
 
 	return reply;
 }

+ 1 - 0
Libraries/cppcodec

@@ -0,0 +1 @@
+../../Libraries/cppcodec

+ 1 - 0
Makefile.conf

@@ -7,6 +7,7 @@ LIBRARIES += Logging
 LIBRARIES += Utilities
 LIBRARIES += Image
 
+CFLAGS += -I$(ROOTPATH)/Libraries/cppcodec/cppcodec
 CFLAGS += -I$(ROOTPATH)/Libraries/CTPL
 CFLAGS += -I$(ROOTPATH)/Libraries/filesystem
 CFLAGS += -I$(ROOTPATH)/Libraries/inih

+ 99 - 0
Recorder/RTSPRecorder.cpp

@@ -0,0 +1,99 @@
+#include "RTSPRecorder.h"
+#include "Util.h"
+#include <HttpClient.h>
+#include <Logging.h>
+
+
+namespace CameraRecorder {
+namespace Recorder {
+
+RTSPRecorder::RTSPRecorder(Http::HttpClient* pHttpClient, const Settings& settings) :
+	m_pHttpClient(pHttpClient),
+	m_settings(settings)
+{
+}
+
+RTSPRecorder::~RTSPRecorder()
+{
+}
+
+std::string RTSPRecorder::Snapshot(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg)
+{
+	Logging::Log(Logging::Severity::Debug, "RTSPRecorder Snapshot");
+
+	std::string dateTimeString = GetDateTimeString();
+	std::string fileName = GetFileName(m_settings, "jpg", dateTimeString, 0);
+
+	Http::HttpClient* pHttpClient = m_pHttpClient;
+	Settings settings = m_settings;
+	RTSPRecorder::Snapshots(ffmpeg, settings, dateTimeString, 1);
+
+	return fileName;
+}
+
+std::string RTSPRecorder::MultiSnapshot(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg, int numberOfImages)
+{
+	Logging::Log(Logging::Severity::Debug, "RTSPRecorder MultiSnapshot");
+
+	std::string dateTimeString = GetDateTimeString();
+	std::string fileName = GetFileName(m_settings, "jpg", dateTimeString, 0);
+
+	Http::HttpClient* pHttpClient = m_pHttpClient;
+	Settings settings = m_settings;
+	pThreadPool->push( [ffmpeg, settings, dateTimeString, numberOfImages](int) { RTSPRecorder::Snapshots(ffmpeg, settings, dateTimeString, numberOfImages); } );
+
+	return fileName;
+}
+
+std::string RTSPRecorder::Video(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg)
+{
+	Logging::Log(Logging::Severity::Debug, "RTSPRecorder Video");
+
+	std::stringstream url;
+	url << "rtsp://" << m_settings.Username << ":" << m_settings.Password << "@" << m_settings.IpAddress << ":" << m_settings.Port << m_settings.URL;
+
+	std::string dateTimeString = GetDateTimeString();
+	std::string fileName = GetFileName(m_settings, "mp4", dateTimeString, 0);
+
+	std::stringstream command;
+	command << ffmpeg << " -rtsp_transport tcp -i \"" << url.str() << "\" -t 30 -c:v copy -an -strict experimental " << fileName << " > /dev/null 2>&1 ; " << ffmpeg << " -i " << fileName << " -vf \"select=eq(n\\,0)\" -q:v 3 " << fileName << ".jpg > /dev/null 2>&1";
+
+	std::string cmd(command.str());
+	Logging::Log(Logging::Severity::Debug, cmd);
+	pThreadPool->push( [cmd](int) { int retval = std::system(cmd.c_str()); } );
+
+	return fileName;
+}
+
+std::string RTSPRecorder::GetFileName(const Settings& settings, const std::string& extension, const std::string& dateTimeString, int imageIndex)
+{
+	filesystem::path fileLocation(settings.Path);
+	fileLocation = fileLocation / filesystem::path(settings.IpAddress);
+
+	std::string fileName = std::string(dateTimeString).append(".").append(extension);
+	filesystem::path fullFileName = fileLocation / filesystem::path(fileName);
+
+	return fullFileName.str();
+}
+
+void RTSPRecorder::Snapshots(const std::string& ffmpeg, const Settings& settings, std::string dateTimeString, int numberOfImages)
+{
+	for (int i = 0; i < numberOfImages; ++i)
+		RTSPRecorder::Snapshot(ffmpeg, settings, RTSPRecorder::GetFileName(settings, "jpg", dateTimeString, i));
+}
+
+void RTSPRecorder::Snapshot(const std::string& ffmpeg, const Settings& settings, const filesystem::path& fileName)
+{
+	std::stringstream url;
+	url << "rtsp://" << settings.Username << ":" << settings.Password << "@" << settings.IpAddress << ":" << settings.Port << settings.URL;
+
+	std::stringstream command;
+	command << ffmpeg << " -rtsp_transport tcp -i \"" << url.str() << "\" -vframes 1 -qscale:v 2 " << fileName << " > /dev/null 2>&1";
+
+	std::string cmd(command.str());
+	Logging::Log(Logging::Severity::Debug, cmd);
+	int retval = std::system(cmd.c_str());
+}
+
+} // namespace Recorder
+} // namespace CameraRecorder

+ 41 - 0
Recorder/RTSPRecorder.h

@@ -0,0 +1,41 @@
+#ifndef RECORDER_RTSPRECORDER_H
+#define RECORDER_RTSPRECORDER_H
+
+#include "Recorder.h"
+#include "Settings.h"
+#include <filesystem/path.h>
+
+
+namespace Http {
+
+class HttpClient;
+
+} // namespace Http
+
+namespace CameraRecorder {
+namespace Recorder {
+
+class RTSPRecorder : public virtual Recorder
+{
+public:
+	RTSPRecorder(Http::HttpClient* pHttpClient, const Settings& settings);
+	~RTSPRecorder();
+
+	virtual std::string Snapshot(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg) override;
+	virtual std::string MultiSnapshot(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg, int numberOfImages) override;
+	virtual std::string Video(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg) override;
+
+private:
+	static std::string GetFileName(const Settings& settings, const std::string& extension, const std::string& dateTimeString, int imageIndex);
+	static void Snapshots(const std::string& ffmpeg, const Settings& settings, std::string dateTimeString, int numberOfImages);
+	static void Snapshot(const std::string& ffmpeg, const Settings& settings, const filesystem::path& fileName);
+
+private:
+	Http::HttpClient* m_pHttpClient;
+	Settings m_settings;
+};
+
+} // namespace Recorder
+} // namespace CameraRecorder
+
+#endif // RECORDER_RTSPRECORDER_H

+ 1 - 0
Recorder/Settings.h

@@ -12,6 +12,7 @@ struct Settings
 	std::string Path;
 	std::string IpAddress;
 	std::string Port;
+	std::string URL;
 	std::string Username;
 	std::string Password;
 };