From 6f5ad21f5757482b71a5d197f920ea39fb2f1167 Mon Sep 17 00:00:00 2001 From: Romain Vimont Date: Sun, 11 Apr 2021 15:01:05 +0200 Subject: [PATCH] Make decoder push frames to sinks Now that screen implements the packet sink trait, make decoder push packets to the sinks without depending on the concrete sink types. --- app/src/decoder.c | 68 ++++++++++++++++++++++++++++++++++++++++++----- app/src/decoder.h | 12 ++++----- app/src/scrcpy.c | 4 ++- 3 files changed, 70 insertions(+), 14 deletions(-) diff --git a/app/src/decoder.c b/app/src/decoder.c index 134ffd3c..34f2a15f 100644 --- a/app/src/decoder.c +++ b/app/src/decoder.c @@ -4,12 +4,40 @@ #include "events.h" #include "video_buffer.h" +#include "trait/frame_sink.h" #include "util/log.h" /** Downcast packet_sink to decoder */ #define DOWNCAST(SINK) container_of(SINK, struct decoder, packet_sink) -bool +static void +decoder_close_first_sinks(struct decoder *decoder, unsigned count) { + while (count) { + struct sc_frame_sink *sink = decoder->sinks[--count]; + sink->ops->close(sink); + } +} + +static inline void +decoder_close_sinks(struct decoder *decoder) { + decoder_close_first_sinks(decoder, decoder->sink_count); +} + +static bool +decoder_open_sinks(struct decoder *decoder) { + for (unsigned i = 0; i < decoder->sink_count; ++i) { + struct sc_frame_sink *sink = decoder->sinks[i]; + if (!sink->ops->open(sink)) { + LOGE("Could not open frame sink %d", i); + decoder_close_first_sinks(decoder, i); + return false; + } + } + + return true; +} + +static bool decoder_open(struct decoder *decoder, const AVCodec *codec) { decoder->codec_ctx = avcodec_alloc_context3(codec); if (!decoder->codec_ctx) { @@ -31,16 +59,38 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) { return false; } + if (!decoder_open_sinks(decoder)) { + LOGE("Could not open decoder sinks"); + av_frame_free(&decoder->frame); + avcodec_close(decoder->codec_ctx); + avcodec_free_context(&decoder->codec_ctx); + return false; + } + return true; } -void +static void decoder_close(struct decoder *decoder) { + decoder_close_sinks(decoder); av_frame_free(&decoder->frame); avcodec_close(decoder->codec_ctx); avcodec_free_context(&decoder->codec_ctx); } +static bool +push_frame_to_sinks(struct decoder *decoder, const AVFrame *frame) { + for (unsigned i = 0; i < decoder->sink_count; ++i) { + struct sc_frame_sink *sink = decoder->sinks[i]; + if (!sink->ops->push(sink, frame)) { + LOGE("Could not send frame to sink %d", i); + return false; + } + } + + return true; +} + static bool decoder_push(struct decoder *decoder, const AVPacket *packet) { bool is_config = packet->pts == AV_NOPTS_VALUE; @@ -57,7 +107,7 @@ decoder_push(struct decoder *decoder, const AVPacket *packet) { ret = avcodec_receive_frame(decoder->codec_ctx, decoder->frame); if (!ret) { // a frame was received - bool ok = video_buffer_push(decoder->video_buffer, decoder->frame); + bool ok = push_frame_to_sinks(decoder, decoder->frame); // A frame lost should not make the whole pipeline fail. The error, if // any, is already logged. (void) ok; @@ -87,9 +137,7 @@ decoder_packet_sink_push(struct sc_packet_sink *sink, const AVPacket *packet) { } void -decoder_init(struct decoder *decoder, struct video_buffer *vb) { - decoder->video_buffer = vb; - +decoder_init(struct decoder *decoder) { static const struct sc_packet_sink_ops ops = { .open = decoder_packet_sink_open, .close = decoder_packet_sink_close, @@ -98,3 +146,11 @@ decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder->packet_sink.ops = &ops; } + +void +decoder_add_sink(struct decoder *decoder, struct sc_frame_sink *sink) { + assert(decoder->sink_count < DECODER_MAX_SINKS); + assert(sink); + assert(sink->ops); + decoder->sinks[decoder->sink_count++] = sink; +} diff --git a/app/src/decoder.h b/app/src/decoder.h index e3730db5..bae97869 100644 --- a/app/src/decoder.h +++ b/app/src/decoder.h @@ -8,24 +8,22 @@ #include #include -struct video_buffer; +#define DECODER_MAX_SINKS 1 struct decoder { struct sc_packet_sink packet_sink; // packet sink trait - struct video_buffer *video_buffer; + struct sc_frame_sink *sinks[DECODER_MAX_SINKS]; + unsigned sink_count; AVCodecContext *codec_ctx; AVFrame *frame; }; void -decoder_init(struct decoder *decoder, struct video_buffer *vb); - -bool -decoder_open(struct decoder *decoder, const AVCodec *codec); +decoder_init(struct decoder *decoder); void -decoder_close(struct decoder *decoder); +decoder_add_sink(struct decoder *decoder, struct sc_frame_sink *sink); #endif diff --git a/app/src/scrcpy.c b/app/src/scrcpy.c index ad705c4a..e8715cbe 100644 --- a/app/src/scrcpy.c +++ b/app/src/scrcpy.c @@ -318,7 +318,7 @@ scrcpy(const struct scrcpy_options *options) { file_handler_initialized = true; } - decoder_init(&decoder, &video_buffer); + decoder_init(&decoder); dec = &decoder; } @@ -382,6 +382,8 @@ scrcpy(const struct scrcpy_options *options) { } screen_initialized = true; + decoder_add_sink(&decoder, &screen.frame_sink); + if (options->turn_screen_off) { struct control_msg msg; msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;