JDierkse преди 2 години
ревизия
1407b93895
променени са 15 файла, в които са добавени 386 реда и са изтрити 0 реда
  1. 4 0
      .gitignore
  2. 3 0
      .gitmodules
  3. 135 0
      API/WebAPI.cpp
  4. 26 0
      API/WebAPI.h
  5. 141 0
      Application/StreamRecoder.cc
  6. 46 0
      Application/Test.cc
  7. 1 0
      Libraries/CTPL
  8. 1 0
      Libraries/FFmpeg
  9. 1 0
      Libraries/Http
  10. 1 0
      Libraries/Logging
  11. 1 0
      Libraries/Utilities
  12. 1 0
      Makefile
  13. 23 0
      Makefile.conf
  14. 1 0
      Makefiles
  15. 1 0
      Recoder/Makefile

+ 4 - 0
.gitignore

@@ -0,0 +1,4 @@
+*.o.*
+*.d.*
+*.a.*
+.*.swp

+ 3 - 0
.gitmodules

@@ -0,0 +1,3 @@
+[submodule "Makefiles"]
+	path = Makefiles
+	url = https://gogs.dierkse.nl/JDierkse/Makefiles

+ 135 - 0
API/WebAPI.cpp

@@ -0,0 +1,135 @@
+#include "WebAPI.h"
+#include <StringAlgorithm.h>
+#include <iostream>
+#include <memory>
+
+
+namespace StreamRecoder {
+namespace API {
+
+// API Description
+
+// Status Query
+// Goal:	Provide status information based on POST data
+// Use:		DomoticaSite status update
+// URL:		http://<ip>/API/<action>/<brand>/<ipaddress>/<port>/<url(base64)>/<username>/<password>
+
+WebAPI::WebAPI()
+{
+}
+
+WebAPI::~WebAPI()
+{
+}
+
+Http::HttpServer::HttpReply WebAPI::ProcessQuery(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg, const std::string& uri, const std::vector<Http::HttpPostData>& postData)
+{
+	if (!StringAlgorithm::iequals(uri, "/api") && !StringAlgorithm::istarts_with(uri, "/api/"))
+	{
+		Http::HttpServer::HttpReply reply;
+		reply.status = Http::HttpServer::HttpReply::Status::Unauthorized;
+		return reply;
+	}
+
+	Http::HttpServer::HttpReply reply;
+	reply.status = Http::HttpServer::HttpReply::Status::InternalServerError;
+	reply.content = "{\"result\": \"error\"}\r\n";
+
+/*
+	try {
+		std::string apiURI = uri.substr(4);
+
+		std::vector<std::string> uriTokens = StringAlgorithm::split(apiURI, '/');
+
+		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.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;
+}
+
+} // namespace API
+} // namespace StreamRecoder

+ 26 - 0
API/WebAPI.h

@@ -0,0 +1,26 @@
+#ifndef API_WEBAPI_H
+#define API_WEBAPI_H
+
+#include <HttpPostData.h>
+#include <HttpServer.h>
+#include <ctpl_stl.h>
+#include <string>
+#include <vector>
+
+
+namespace StreamRecoder {
+namespace API {
+
+class WebAPI
+{
+public:
+	WebAPI();
+	~WebAPI();
+
+	static Http::HttpServer::HttpReply ProcessQuery(ctpl::thread_pool* pThreadPool, const std::string& ffmpeg, const std::string& uri, const std::vector<Http::HttpPostData>& postData);
+};
+
+} // namespace API
+} // namespace StreamRecoder
+
+#endif // API_WEBAPI_H

+ 141 - 0
Application/StreamRecoder.cc

@@ -0,0 +1,141 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <iostream>
+#include <fstream>
+#include <sstream>
+
+extern "C" {
+#include <libavcodec/avcodec.h>
+#include <libavformat/avformat.h>
+#include <libavformat/avio.h>
+#include <libswscale/swscale.h>
+}
+
+int main(int argc, char** argv) {
+
+	// Open the initial context variables that are needed
+	SwsContext *img_convert_ctx;
+	AVFormatContext* format_ctx = avformat_alloc_context();
+	AVCodecContext* codec_ctx = NULL;
+	int video_stream_index;
+
+	// Register everything
+	av_register_all();
+	avformat_network_init();
+
+	//open RTSP
+	if (avformat_open_input(&format_ctx, "rtsp://134.169.178.187:8554/h264.3gp",
+			NULL, NULL) != 0) {
+		return EXIT_FAILURE;
+	}
+
+	if (avformat_find_stream_info(format_ctx, NULL) < 0) {
+		return EXIT_FAILURE;
+	}
+
+	//search video stream
+	for (int i = 0; i < format_ctx->nb_streams; i++) {
+		if (format_ctx->streams[i]->codec->codec_type == AVMEDIA_TYPE_VIDEO)
+			video_stream_index = i;
+	}
+
+	AVPacket packet;
+	av_init_packet(&packet);
+
+	//open output file
+	AVFormatContext* output_ctx = avformat_alloc_context();
+
+	AVStream* stream = NULL;
+	int cnt = 0;
+
+	//start reading packets from stream and write them to file
+	av_read_play(format_ctx);	//play RTSP
+
+	// Get the codec
+	AVCodec *codec = NULL;
+	codec = avcodec_find_decoder(AV_CODEC_ID_H264);
+	if (!codec) {
+		exit(1);
+	}
+
+	// Add this to allocate the context by codec
+	codec_ctx = avcodec_alloc_context3(codec);
+
+	avcodec_get_context_defaults3(codec_ctx, codec);
+	avcodec_copy_context(codec_ctx, format_ctx->streams[video_stream_index]->codec);
+	std::ofstream output_file;
+
+	if (avcodec_open2(codec_ctx, codec, NULL) < 0)
+		exit(1);
+
+	img_convert_ctx = sws_getContext(codec_ctx->width, codec_ctx->height,
+			codec_ctx->pix_fmt, codec_ctx->width, codec_ctx->height, AV_PIX_FMT_RGB24,
+			SWS_BICUBIC, NULL, NULL, NULL);
+
+	int size = avpicture_get_size(AV_PIX_FMT_YUV420P, codec_ctx->width,
+			codec_ctx->height);
+	uint8_t* picture_buffer = (uint8_t*) (av_malloc(size));
+	AVFrame* picture = av_frame_alloc();
+	AVFrame* picture_rgb = av_frame_alloc();
+	int size2 = avpicture_get_size(AV_PIX_FMT_RGB24, codec_ctx->width,
+			codec_ctx->height);
+	uint8_t* picture_buffer_2 = (uint8_t*) (av_malloc(size2));
+	avpicture_fill((AVPicture *) picture, picture_buffer, AV_PIX_FMT_YUV420P,
+			codec_ctx->width, codec_ctx->height);
+	avpicture_fill((AVPicture *) picture_rgb, picture_buffer_2, AV_PIX_FMT_RGB24,
+			codec_ctx->width, codec_ctx->height);
+
+	while (av_read_frame(format_ctx, &packet) >= 0 && cnt < 1000) { //read ~ 1000 frames
+
+		std::cout << "1 Frame: " << cnt << std::endl;
+		if (packet.stream_index == video_stream_index) {	//packet is video
+			std::cout << "2 Is Video" << std::endl;
+			if (stream == NULL) {	//create stream in file
+				std::cout << "3 create stream" << std::endl;
+				stream = avformat_new_stream(output_ctx,
+						format_ctx->streams[video_stream_index]->codec->codec);
+				avcodec_copy_context(stream->codec,
+						format_ctx->streams[video_stream_index]->codec);
+				stream->sample_aspect_ratio =
+						format_ctx->streams[video_stream_index]->codec->sample_aspect_ratio;
+			}
+			int check = 0;
+			packet.stream_index = stream->id;
+			std::cout << "4 decoding" << std::endl;
+			int result = avcodec_decode_video2(codec_ctx, picture, &check, &packet);
+			std::cout << "Bytes decoded " << result << " check " << check
+					<< std::endl;
+			if (cnt > 100)	//cnt < 0)
+					{
+				sws_scale(img_convert_ctx, picture->data, picture->linesize, 0,
+						codec_ctx->height, picture_rgb->data, picture_rgb->linesize);
+				std::stringstream file_name;
+				file_name << "test" << cnt << ".ppm";
+				output_file.open(file_name.str().c_str());
+				output_file << "P3 " << codec_ctx->width << " " << codec_ctx->height
+						<< " 255\n";
+				for (int y = 0; y < codec_ctx->height; y++) {
+					for (int x = 0; x < codec_ctx->width * 3; x++)
+						output_file
+								<< (int) (picture_rgb->data[0]
+										+ y * picture_rgb->linesize[0])[x] << " ";
+				}
+				output_file.close();
+			}
+			cnt++;
+		}
+		av_free_packet(&packet);
+		av_init_packet(&packet);
+	}
+	av_free(picture);
+	av_free(picture_rgb);
+	av_free(picture_buffer);
+	av_free(picture_buffer_2);
+
+	av_read_pause(format_ctx);
+	avio_close(output_ctx->pb);
+	avformat_free_context(output_ctx);
+
+	return (EXIT_SUCCESS);
+}
+

+ 46 - 0
Application/Test.cc

@@ -0,0 +1,46 @@
+#include "API/WebAPI.h"
+#include <ctpl_stl.h>
+#include <Logging.h>
+#include <HttpServer.h>
+#include <iostream>
+#include <sstream>
+
+
+int main(int argc, char** argv)
+{
+	try
+	{
+		Logging::OpenLog();
+		Logging::SetLogMask(Logging::Severity::Debug);
+
+		int port(8000);
+		ctpl::thread_pool threadPool(6);
+		std::string ffmpeg = "ffmpeg";
+
+		Http::HttpServer::CallbackMethod callback = std::bind(&StreamRecoder::API::WebAPI::ProcessQuery, &threadPool, ffmpeg, std::placeholders::_1, std::placeholders::_2);
+
+		Http::HttpServer server(port, callback);
+		Logging::Log(Logging::Severity::Info, "Startup Complete");
+		server.Wait();
+
+		Logging::Log(Logging::Severity::Info, "Stopping StreamRecoder...");
+
+		Logging::CloseLog();
+	}
+	catch (const std::exception& e)
+	{
+		std::cerr << "Exception caught" << std::endl;
+
+		std::stringstream ss;
+		ss << "Type : " << typeid(e).name() << std::endl;
+		ss << "ERROR: " << e.what() << std::endl;
+
+		Logging::Log(Logging::Severity::Error, ss.str());
+
+		Logging::CloseLog();
+
+		return -1;
+	}
+
+	return 0;
+}

+ 1 - 0
Libraries/CTPL

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

+ 1 - 0
Libraries/FFmpeg

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

+ 1 - 0
Libraries/Http

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

+ 1 - 0
Libraries/Logging

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

+ 1 - 0
Libraries/Utilities

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

+ 1 - 0
Makefile

@@ -0,0 +1 @@
+Makefiles/Makefile

+ 23 - 0
Makefile.conf

@@ -0,0 +1,23 @@
+#
+# Makefile.conf
+#
+
+LIBRARIES += Http
+LIBRARIES += Logging
+LIBRARIES += Utilities
+
+CFLAGS += -I$(ROOTPATH)/Libraries/CTPL
+CFLAGS += -I$(ROOTPATH)/Libraries/FFmpeg
+
+LFLAGS += -pthread
+
+CFLAGS += -I$(ROOTPATH) -I$(ROOTPATH)/Libraries
+
+CFLAGS += -Wno-sign-compare -Wno-deprecated-declarations
+
+DEBUGDIR := .debug
+
+#DEFAULTARCH := x86_64-alpine
+DEFAULTARCH := x86_64
+TARGETS += StreamRecoder
+

+ 1 - 0
Makefiles

@@ -0,0 +1 @@
+Subproject commit df68de61fdca1ad55a2dd9b8c7e4eb88f60c45f0

+ 1 - 0
Recoder/Makefile

@@ -0,0 +1 @@
+../Makefile