From eb57c35ffc78a5dca931b085104d27b9b79acf93 Mon Sep 17 00:00:00 2001 From: loki Date: Sun, 8 Dec 2019 21:16:02 +0100 Subject: [PATCH] Fixed bug causing the video playback to freeze --- sunshine/queue.h | 6 ++++++ sunshine/stream.cpp | 33 +++++++++++++++++---------------- sunshine/video.cpp | 30 ++++++++++++++++++++---------- sunshine/video.h | 6 ++++-- 4 files changed, 47 insertions(+), 28 deletions(-) diff --git a/sunshine/queue.h b/sunshine/queue.h index c8525adb..cd76bed1 100644 --- a/sunshine/queue.h +++ b/sunshine/queue.h @@ -36,6 +36,12 @@ public: _cv.notify_all(); } + bool peek() { + std::lock_guard lg { _lock }; + + return !_queue.empty(); + } + status_t pop() { std::unique_lock ul{_lock}; diff --git a/sunshine/stream.cpp b/sunshine/stream.cpp index 1f6f6fbb..267c5659 100644 --- a/sunshine/stream.cpp +++ b/sunshine/stream.cpp @@ -173,7 +173,7 @@ public: std::vector full_payload; auto old_msg = std::move(_queue_packet); - TUPLE_2D(_, old_packet, std::move(_queue_packet)); + TUPLE_2D_REF(_, old_packet, old_msg); std::string_view new_payload { (char*)packet->data, packet->dataLength }; @@ -225,12 +225,12 @@ private: host_t _host; }; -class server_t { +class control_server_t { public: - server_t(server_t &&) noexcept = default; - server_t &operator=(server_t &&) noexcept = default; + control_server_t(control_server_t &&) noexcept = default; + control_server_t &operator=(control_server_t &&) noexcept = default; - explicit server_t(std::uint16_t port) : _host { host_create(_addr, port) } {} + explicit control_server_t(std::uint16_t port) : _host { host_create(_addr, port) } {} template void iterate(std::chrono::duration timeout) { @@ -271,7 +271,7 @@ public: } void map(uint16_t type, std::function cb); private: - std::unordered_map> _map_type_cb; + std::unordered_map> _map_type_cb; ENetAddress _addr; host_t _host; }; @@ -478,12 +478,12 @@ void rtsp_server_t::map(const std::string_view& cmd, std::function cb) { +void control_server_t::map(uint16_t type, std::function cb) { _map_type_cb.emplace(type, std::move(cb)); } -void controlThread() { - server_t server { CONTROL_PORT }; +void controlThread(video::event_queue_t idr_events) { + control_server_t server { CONTROL_PORT }; auto input = platf::input(); server.map(packetTypes[IDX_START_A], [](const std::string_view &payload) { @@ -516,7 +516,7 @@ void controlThread() { std::cout << "---end stats---" << std::endl; }); - server.map(packetTypes[IDX_INVALIDATE_REF_FRAMES], [](const std::string_view &payload) { + server.map(packetTypes[IDX_INVALIDATE_REF_FRAMES], [idr_events](const std::string_view &payload) { session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout; std::cout << "type [IDX_INVALIDATE_REF_FRAMES]"sv << std::endl; @@ -528,7 +528,7 @@ void controlThread() { std::cout << "firstFrame [" << firstFrame << ']' << std::endl; std::cout << "lastFrame [" << lastFrame << ']' << std::endl; - exit(100); + idr_events->push(std::make_pair(firstFrame, lastFrame)); }); server.map(packetTypes[IDX_INPUT_DATA], [&input](const std::string_view &payload) mutable { @@ -639,7 +639,7 @@ void audioThread() { captureThread.join(); } -void videoThread() { +void videoThread(video::event_queue_t idr_events) { auto &config = session.config; int lowseq = 0; @@ -652,9 +652,9 @@ void videoThread() { return; } - std::shared_ptr> packets{new safe::queue_t}; + video::packet_queue_t packets{new safe::queue_t}; - std::thread captureThread{video::capture_display, packets, config.monitor}; + std::thread captureThread{video::capture_display, packets, idr_events, config.monitor}; frame_queue_t packet_queue; uint16_t frame{1}; @@ -955,9 +955,10 @@ void cmd_announce(host_t &host, peer_t peer, msg_t &&req) { session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout; session.client_state = 1; + video::event_queue_t idr_events { new video::event_queue_t::element_type }; session.audioThread = std::thread {audioThread}; - session.videoThread = std::thread {videoThread}; - session.controlThread = std::thread {controlThread}; + session.videoThread = std::thread {videoThread, idr_events}; + session.controlThread = std::thread {controlThread, idr_events}; respond(host, peer, &option, 200, "OK", req->sequenceNumber, {}); } diff --git a/sunshine/video.cpp b/sunshine/video.cpp index d5d87256..4889c5ce 100644 --- a/sunshine/video.cpp +++ b/sunshine/video.cpp @@ -31,10 +31,10 @@ void free_packet(AVPacket *packet) { av_packet_free(&packet); } -using ctx_t = util::safe_ptr; -using frame_t = util::safe_ptr; - -using sws_t = util::safe_ptr; +using ctx_t = util::safe_ptr; +using frame_t = util::safe_ptr; +using sws_t = util::safe_ptr; +using img_queue_t = std::shared_ptr>; auto open_codec(ctx_t &ctx, AVCodec *codec, AVDictionary **options) { avcodec_open2(ctx.get(), codec, options); @@ -44,7 +44,7 @@ auto open_codec(ctx_t &ctx, AVCodec *codec, AVDictionary **options) { }); } -void encode(int64_t frame, ctx_t &ctx, sws_t &sws, frame_t &yuv_frame, platf::img_t &img, std::shared_ptr> &packets) { +void encode(int64_t frame, ctx_t &ctx, sws_t &sws, frame_t &yuv_frame, platf::img_t &img, packet_queue_t &packets) { av_frame_make_writable(yuv_frame.get()); const int linesizes[2] { @@ -83,8 +83,10 @@ void encode(int64_t frame, ctx_t &ctx, sws_t &sws, frame_t &yuv_frame, platf::im } void encodeThread( - std::shared_ptr> images, - std::shared_ptr> packets, config_t config) { + img_queue_t images, + packet_queue_t packets, + event_queue_t idr_events, + config_t config) { int framerate = config.framerate; auto codec = avcodec_find_encoder(AV_CODEC_ID_H264); @@ -140,18 +142,26 @@ void encodeThread( } while (auto img = images->pop()) { + if(idr_events->peek()) { + yuv_frame->pict_type = AV_PICTURE_TYPE_I; + + frame = idr_events->pop()->first; + } + encode(frame++, ctx, sws, yuv_frame, img, packets); + + yuv_frame->pict_type = AV_PICTURE_TYPE_NONE; } packets->stop(); } -void capture_display(std::shared_ptr> packets, config_t config) { +void capture_display(packet_queue_t packets, event_queue_t idr_events, config_t config) { int framerate = config.framerate; - std::shared_ptr> images { new safe::queue_t }; + img_queue_t images { new safe::queue_t }; - std::thread encoderThread { &encodeThread, images, packets, config }; + std::thread encoderThread { &encodeThread, images, packets, idr_events, config }; auto disp = platf::display(); diff --git a/sunshine/video.h b/sunshine/video.h index 1c392003..c07d1d26 100644 --- a/sunshine/video.h +++ b/sunshine/video.h @@ -11,7 +11,9 @@ struct AVPacket; namespace video { void free_packet(AVPacket *packet); -using packet_t = util::safe_ptr; +using packet_t = util::safe_ptr; +using packet_queue_t = std::shared_ptr>; +using event_queue_t = std::shared_ptr>>; struct config_t { int width; @@ -21,7 +23,7 @@ struct config_t { int slicesPerFrame; }; -void capture_display(std::shared_ptr> packets, config_t config); +void capture_display(packet_queue_t packets, event_queue_t idr_events, config_t config); } #endif //SUNSHINE_VIDEO_H