Fixed bug causing the video playback to freeze

This commit is contained in:
loki 2019-12-08 21:16:02 +01:00
parent 10cd1c0f2b
commit eb57c35ffc
4 changed files with 47 additions and 28 deletions

View File

@ -36,6 +36,12 @@ public:
_cv.notify_all(); _cv.notify_all();
} }
bool peek() {
std::lock_guard lg { _lock };
return !_queue.empty();
}
status_t pop() { status_t pop() {
std::unique_lock ul{_lock}; std::unique_lock ul{_lock};

View File

@ -173,7 +173,7 @@ public:
std::vector<char> full_payload; std::vector<char> full_payload;
auto old_msg = std::move(_queue_packet); 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 }; std::string_view new_payload { (char*)packet->data, packet->dataLength };
@ -225,12 +225,12 @@ private:
host_t _host; host_t _host;
}; };
class server_t { class control_server_t {
public: public:
server_t(server_t &&) noexcept = default; control_server_t(control_server_t &&) noexcept = default;
server_t &operator=(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<class T, class X> template<class T, class X>
void iterate(std::chrono::duration<T, X> timeout) { void iterate(std::chrono::duration<T, X> timeout) {
@ -271,7 +271,7 @@ public:
} }
void map(uint16_t type, std::function<void(const std::string_view&)> cb); void map(uint16_t type, std::function<void(const std::string_view&)> cb);
private: private:
std::unordered_map<std::uint8_t, std::function<void(const std::string_view&)>> _map_type_cb; std::unordered_map<std::uint16_t, std::function<void(const std::string_view&)>> _map_type_cb;
ENetAddress _addr; ENetAddress _addr;
host_t _host; host_t _host;
}; };
@ -478,12 +478,12 @@ void rtsp_server_t::map(const std::string_view& cmd, std::function<void(host_t&,
_map_cmd_cb.emplace(cmd, std::move(cb)); _map_cmd_cb.emplace(cmd, std::move(cb));
} }
void server_t::map(uint16_t type, std::function<void(const std::string_view &)> cb) { void control_server_t::map(uint16_t type, std::function<void(const std::string_view &)> cb) {
_map_type_cb.emplace(type, std::move(cb)); _map_type_cb.emplace(type, std::move(cb));
} }
void controlThread() { void controlThread(video::event_queue_t idr_events) {
server_t server { CONTROL_PORT }; control_server_t server { CONTROL_PORT };
auto input = platf::input(); auto input = platf::input();
server.map(packetTypes[IDX_START_A], [](const std::string_view &payload) { server.map(packetTypes[IDX_START_A], [](const std::string_view &payload) {
@ -516,7 +516,7 @@ void controlThread() {
std::cout << "---end stats---" << std::endl; 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; session.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
std::cout << "type [IDX_INVALIDATE_REF_FRAMES]"sv << std::endl; std::cout << "type [IDX_INVALIDATE_REF_FRAMES]"sv << std::endl;
@ -528,7 +528,7 @@ void controlThread() {
std::cout << "firstFrame [" << firstFrame << ']' << std::endl; std::cout << "firstFrame [" << firstFrame << ']' << std::endl;
std::cout << "lastFrame [" << lastFrame << ']' << 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 { server.map(packetTypes[IDX_INPUT_DATA], [&input](const std::string_view &payload) mutable {
@ -639,7 +639,7 @@ void audioThread() {
captureThread.join(); captureThread.join();
} }
void videoThread() { void videoThread(video::event_queue_t idr_events) {
auto &config = session.config; auto &config = session.config;
int lowseq = 0; int lowseq = 0;
@ -652,9 +652,9 @@ void videoThread() {
return; return;
} }
std::shared_ptr<safe::queue_t<video::packet_t>> packets{new safe::queue_t<video::packet_t>}; video::packet_queue_t packets{new safe::queue_t<video::packet_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; frame_queue_t packet_queue;
uint16_t frame{1}; 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.pingTimeout = std::chrono::steady_clock::now() + config::stream.ping_timeout;
session.client_state = 1; session.client_state = 1;
video::event_queue_t idr_events { new video::event_queue_t::element_type };
session.audioThread = std::thread {audioThread}; session.audioThread = std::thread {audioThread};
session.videoThread = std::thread {videoThread}; session.videoThread = std::thread {videoThread, idr_events};
session.controlThread = std::thread {controlThread}; session.controlThread = std::thread {controlThread, idr_events};
respond(host, peer, &option, 200, "OK", req->sequenceNumber, {}); respond(host, peer, &option, 200, "OK", req->sequenceNumber, {});
} }

View File

@ -31,10 +31,10 @@ void free_packet(AVPacket *packet) {
av_packet_free(&packet); av_packet_free(&packet);
} }
using ctx_t = util::safe_ptr<AVCodecContext, free_ctx>; using ctx_t = util::safe_ptr<AVCodecContext, free_ctx>;
using frame_t = util::safe_ptr<AVFrame, free_frame>; using frame_t = util::safe_ptr<AVFrame, free_frame>;
using sws_t = util::safe_ptr<SwsContext, sws_freeContext>;
using sws_t = util::safe_ptr<SwsContext, sws_freeContext>; using img_queue_t = std::shared_ptr<safe::queue_t<platf::img_t>>;
auto open_codec(ctx_t &ctx, AVCodec *codec, AVDictionary **options) { auto open_codec(ctx_t &ctx, AVCodec *codec, AVDictionary **options) {
avcodec_open2(ctx.get(), codec, 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<safe::queue_t<packet_t>> &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()); av_frame_make_writable(yuv_frame.get());
const int linesizes[2] { 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( void encodeThread(
std::shared_ptr<safe::queue_t<platf::img_t>> images, img_queue_t images,
std::shared_ptr<safe::queue_t<packet_t>> packets, config_t config) { packet_queue_t packets,
event_queue_t idr_events,
config_t config) {
int framerate = config.framerate; int framerate = config.framerate;
auto codec = avcodec_find_encoder(AV_CODEC_ID_H264); auto codec = avcodec_find_encoder(AV_CODEC_ID_H264);
@ -140,18 +142,26 @@ void encodeThread(
} }
while (auto img = images->pop()) { 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); encode(frame++, ctx, sws, yuv_frame, img, packets);
yuv_frame->pict_type = AV_PICTURE_TYPE_NONE;
} }
packets->stop(); packets->stop();
} }
void capture_display(std::shared_ptr<safe::queue_t<packet_t>> packets, config_t config) { void capture_display(packet_queue_t packets, event_queue_t idr_events, config_t config) {
int framerate = config.framerate; int framerate = config.framerate;
std::shared_ptr<safe::queue_t<platf::img_t>> images { new safe::queue_t<platf::img_t> }; img_queue_t images { new safe::queue_t<platf::img_t> };
std::thread encoderThread { &encodeThread, images, packets, config }; std::thread encoderThread { &encodeThread, images, packets, idr_events, config };
auto disp = platf::display(); auto disp = platf::display();

View File

@ -11,7 +11,9 @@ struct AVPacket;
namespace video { namespace video {
void free_packet(AVPacket *packet); void free_packet(AVPacket *packet);
using packet_t = util::safe_ptr<AVPacket, free_packet>; using packet_t = util::safe_ptr<AVPacket, free_packet>;
using packet_queue_t = std::shared_ptr<safe::queue_t<packet_t>>;
using event_queue_t = std::shared_ptr<safe::queue_t<std::pair<int64_t, int64_t>>>;
struct config_t { struct config_t {
int width; int width;
@ -21,7 +23,7 @@ struct config_t {
int slicesPerFrame; int slicesPerFrame;
}; };
void capture_display(std::shared_ptr<safe::queue_t<packet_t>> packets, config_t config); void capture_display(packet_queue_t packets, event_queue_t idr_events, config_t config);
} }
#endif //SUNSHINE_VIDEO_H #endif //SUNSHINE_VIDEO_H