浏览代码

Implemented frame index log.

jcsyshc 2 年之前
父节点
当前提交
e8514eabfa

+ 1 - 2
src/frame_decoder/decoder_base.cpp

@@ -4,10 +4,9 @@
 
 using namespace simple_mq_singleton;
 
-void video_nal::create(void *_ptr, size_t _length, bool _idr) {
+void video_nal::create(void *_ptr, size_t _length) {
     free(ptr);
     length = _length;
-    idr = _idr;
     ptr = (uint8_t *) malloc(length);
     if (_ptr != nullptr) {
         memcpy(ptr, _ptr, length);

+ 3 - 2
src/frame_decoder/decoder_base.h

@@ -3,6 +3,8 @@
 
 #include <opencv2/core/cuda.hpp>
 
+#include <memory>
+
 enum decoder_type {
     DECODER_NVDEC,
     DECODER_JPEG
@@ -11,9 +13,8 @@ enum decoder_type {
 struct video_nal {
     uint8_t *ptr = nullptr;
     size_t length = 0;
-    bool idr = false;
 
-    void create(void *ptr, size_t length, bool idr);
+    void create(void *ptr, size_t length);
 
     ~video_nal();
 };

+ 24 - 0
src/frame_receiver/receiver_base.cpp

@@ -1,15 +1,35 @@
 #include "receiver_base.h"
+#include "simple_mq.h"
+#include "utility.hpp"
+#include "variable_defs.h"
 
+#include <fmt/chrono.h>
 #include <spdlog/spdlog.h>
 
+#include <fstream>
+
 using boost::asio::io_context;
+using namespace simple_mq_singleton;
 
 struct receiver_base::impl {
 
     std::unique_ptr<io_context> ctx;
+    std::ofstream log_file;
 
     impl() {
         ctx = std::make_unique<io_context>();
+
+        // create log file if requested
+        if (mq().query_variable<bool>(RECEIVER_ENABLE_LOG)) {
+            auto file_name = fmt::format("log_{:%Y_%m_%d_%H_%M_%S}.csv",
+                                         std::chrono::system_clock::now());
+            log_file.open(file_name);
+        }
+    }
+
+    void log_frame_received(uint64_t frame_id) {
+        if (!log_file.is_open()) return;
+        log_file << fmt::format("{},{}\n", frame_id, system_timestamp());
     }
 };
 
@@ -29,4 +49,8 @@ void receiver_base::run() {
 
 boost::asio::io_context *receiver_base::get_ctx() {
     return pimpl->ctx.get();
+}
+
+void receiver_base::log_frame_received(uint64_t frame_id) {
+    pimpl->log_frame_received(frame_id);
 }

+ 4 - 0
src/frame_receiver/receiver_base.h

@@ -29,6 +29,10 @@ public:
 
     boost::asio::io_context *get_ctx();
 
+protected:
+
+    void log_frame_received(uint64_t frame_id);
+
 private:
     struct impl;
     std::unique_ptr<impl> pimpl;

+ 28 - 5
src/frame_receiver/receiver_tcp.cpp

@@ -1,6 +1,8 @@
 #include "receiver_tcp.h"
+#include "simple_mq.h"
 #include "receiver_utility.hpp"
 #include "utility.hpp"
+#include "variable_defs.h"
 
 #include <boost/asio/ip/tcp.hpp>
 #include <boost/asio/read.hpp>
@@ -13,6 +15,7 @@ using boost::asio::buffer;
 using boost::asio::io_context;
 using boost::asio::post;
 using boost::asio::read;
+using namespace simple_mq_singleton;
 
 struct receiver_tcp::impl {
 
@@ -23,18 +26,38 @@ struct receiver_tcp::impl {
     smart_buffer<uint8_t> in_buf;
 
     void receive_one_frame() {
-        auto frame = std::make_unique<video_nal>();
-        in_buf.create(sizeof(frame->length));
+        // read packet length
+        uint64_t packet_length;
+        in_buf.create(sizeof(packet_length));
+        read(*socket, buffer(in_buf.ptr, in_buf.length));
+        read_binary_number(in_buf.ptr, &packet_length);
+
+        // read full packet
+        in_buf.create(packet_length);
         read(*socket, buffer(in_buf.ptr, in_buf.length));
-        read_binary_number(in_buf.ptr, &frame->length);
-        frame->create(nullptr, frame->length, true);
-        read(*socket, buffer(frame->ptr, frame->length));
+
+        // read frame id
+        uint64_t frame_id;
+        auto ptr = read_binary_number(in_buf.ptr, &frame_id);
+        auto frame_length = packet_length
+                            - sizeof(frame_id);
+
+        // read frame content
+        auto frame = std::make_unique<video_nal>();
+        frame->create(ptr, frame_length);
+        q_this->log_frame_received(frame_id);
         decoder->decode(std::move(frame));
+        SPDLOG_TRACE("Frame {} decoded.", frame_id);
     }
 
     void receive_frames() {
         try {
             for (;;) {
+                // check if stop requested
+                if (mq().query_variable<bool>(RECEIVER_SHOULD_STOP)) {
+                    return;
+                }
+
                 receive_one_frame();
             }
         } catch (std::exception &e) {

+ 5 - 1
src/frame_receiver/receiver_udp_fec.cpp

@@ -139,6 +139,8 @@ struct receiver_udp_fec::impl {
     static constexpr auto max_package_size = 64 * 1024; // 64KiB
     static constexpr auto udp_buffer_size = 10 * 1024 * 1024; // 10MiB
 
+    receiver_udp_fec *q_this = nullptr;
+
     std::unique_ptr<udp::socket> socket;
     decoder_base *decoder;
 
@@ -299,7 +301,8 @@ struct receiver_udp_fec::impl {
         // decode frame
         frame_cache.status = READY;
         auto frame = std::make_unique<video_nal>();
-        frame->create(frame_cache.data.ptr, frame_cache.data.length, is_idr_frame);
+        frame->create(frame_cache.data.ptr, frame_cache.data.length);
+        q_this->log_frame_received(header.frame_id);
         decoder->decode(std::move(frame));
         SPDLOG_TRACE("Frame {} decoded.", frame_cache.id);
         last_frame_id = frame_cache.id;
@@ -309,6 +312,7 @@ struct receiver_udp_fec::impl {
     static impl *create(const receiver_config &conf, receiver_udp_fec *q_this) {
         auto ret = std::make_unique<impl>();
         assert(conf.decoder != nullptr);
+        ret->q_this = q_this;
         ret->decoder = conf.decoder;
         ret->server_ep = udp::endpoint{address::from_string(conf.server_addr), conf.server_port};
         ret->socket = std::make_unique<udp::socket>(*q_this->get_ctx());

+ 1 - 1
src/frame_receiver/receiver_utility.hpp

@@ -11,7 +11,7 @@ struct smart_buffer {
     size_t length = 0;
 
     ~smart_buffer() {
-        free(ptr);
+        // delete ptr; // TODO: fix this problem
     }
 
     void create(size_t req_length) {

+ 5 - 0
src/main_controller.cpp

@@ -50,6 +50,7 @@ namespace controller_impl {
     uint16_t server_port = 5279;
     decoder_type chosen_decoder = DECODER_NVDEC;
     receiver_type chosen_receiver = RECEIVER_TCP;
+    bool enable_log = false;
     std::unique_ptr<bp::child> worker;
 
     void stop_worker() {
@@ -76,6 +77,7 @@ namespace controller_impl {
         config["server"] = server_config;
         config["receiver"] = (int) chosen_receiver;
         config["decoder"] = (int) chosen_decoder;
+        config["log"] = enable_log;
 
         // create worker
         auto config_str = config.dump();
@@ -178,6 +180,9 @@ void controller_main(const char *this_name) {
                 if (ImGui::RadioButton("UDP (FEC)", chosen_receiver == RECEIVER_UDP_FEC)) {
                     chosen_receiver = RECEIVER_UDP_FEC;
                 }
+
+                // log
+                ImGui::Checkbox("Enable Log", &enable_log);
             }
             ImGui::PopItemWidth();
         }

+ 8 - 4
src/main_player.cpp

@@ -74,8 +74,10 @@ void player_main(const json &config) {
     recv_conf.server_port = server_conf["port"].get<int>();
 
     // create receiver
-    std::unique_ptr<receiver_base> receiver;
+    auto receiver_enable_log = config["log"].get<bool>();
+    mq().update_variable(RECEIVER_ENABLE_LOG, receiver_enable_log);
     auto chosen_receiver = (receiver_type) config["receiver"].get<int>();
+    std::unique_ptr<receiver_base> receiver;
     switch (chosen_receiver) {
         case RECEIVER_TCP: {
             receiver.reset(receiver_tcp::create(recv_conf));
@@ -91,7 +93,7 @@ void player_main(const json &config) {
     }
 
     // working thread
-    mq().update_variable(RECEIVER_STOPPED, false);
+    mq().update_variable(RECEIVER_SHOULD_STOP, false);
     mq().update_variable(RENDER_BUSY, false);
     mq().update_variable_ptr<cv::cuda::GpuMat>(FRAME_OUT, nullptr);
     auto worker = std::make_unique<std::thread>([&] {
@@ -150,6 +152,8 @@ void player_main(const json &config) {
         glfwSwapBuffers(main_window);
     }
 
-    // ignore thread exception
-    exit(0);
+    // elegant stop
+    mq().update_variable(RECEIVER_SHOULD_STOP, true);
+    receiver->get_ctx()->stop();
+    worker->join();
 }

+ 6 - 0
src/utility.hpp

@@ -71,4 +71,10 @@ extern log_timer global_timer;
 #define RESET_TIMER global_timer.reset()
 #define RECORD_TIME(name) global_timer.record(name)
 
+inline auto system_timestamp() {
+    using namespace std::chrono;
+    auto time_point = high_resolution_clock::now();
+    return duration_cast<microseconds>(time_point.time_since_epoch()).count();
+}
+
 #endif //REMOTEAR3_UTILITY_HPP

+ 2 - 1
src/variable_defs.h

@@ -3,6 +3,7 @@
 
 constexpr auto FRAME_OUT = 0;
 constexpr auto RENDER_BUSY = 1;
-constexpr auto RECEIVER_STOPPED = 2;
+constexpr auto RECEIVER_SHOULD_STOP = 2;
+constexpr auto RECEIVER_ENABLE_LOG = 3;
 
 #endif //TINYPLAYER3_VARIABLE_DEFS_H