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.
This commit is contained in:
Romain Vimont 2021-04-11 15:01:05 +02:00
parent 08b3086ffc
commit 6f5ad21f57
3 changed files with 70 additions and 14 deletions

View file

@ -4,12 +4,40 @@
#include "events.h" #include "events.h"
#include "video_buffer.h" #include "video_buffer.h"
#include "trait/frame_sink.h"
#include "util/log.h" #include "util/log.h"
/** Downcast packet_sink to decoder */ /** Downcast packet_sink to decoder */
#define DOWNCAST(SINK) container_of(SINK, struct decoder, packet_sink) #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_open(struct decoder *decoder, const AVCodec *codec) {
decoder->codec_ctx = avcodec_alloc_context3(codec); decoder->codec_ctx = avcodec_alloc_context3(codec);
if (!decoder->codec_ctx) { if (!decoder->codec_ctx) {
@ -31,16 +59,38 @@ decoder_open(struct decoder *decoder, const AVCodec *codec) {
return false; 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; return true;
} }
void static void
decoder_close(struct decoder *decoder) { decoder_close(struct decoder *decoder) {
decoder_close_sinks(decoder);
av_frame_free(&decoder->frame); av_frame_free(&decoder->frame);
avcodec_close(decoder->codec_ctx); avcodec_close(decoder->codec_ctx);
avcodec_free_context(&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 static bool
decoder_push(struct decoder *decoder, const AVPacket *packet) { decoder_push(struct decoder *decoder, const AVPacket *packet) {
bool is_config = packet->pts == AV_NOPTS_VALUE; 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); ret = avcodec_receive_frame(decoder->codec_ctx, decoder->frame);
if (!ret) { if (!ret) {
// a frame was received // 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 // A frame lost should not make the whole pipeline fail. The error, if
// any, is already logged. // any, is already logged.
(void) ok; (void) ok;
@ -87,9 +137,7 @@ decoder_packet_sink_push(struct sc_packet_sink *sink, const AVPacket *packet) {
} }
void void
decoder_init(struct decoder *decoder, struct video_buffer *vb) { decoder_init(struct decoder *decoder) {
decoder->video_buffer = vb;
static const struct sc_packet_sink_ops ops = { static const struct sc_packet_sink_ops ops = {
.open = decoder_packet_sink_open, .open = decoder_packet_sink_open,
.close = decoder_packet_sink_close, .close = decoder_packet_sink_close,
@ -98,3 +146,11 @@ decoder_init(struct decoder *decoder, struct video_buffer *vb) {
decoder->packet_sink.ops = &ops; 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;
}

View file

@ -8,24 +8,22 @@
#include <stdbool.h> #include <stdbool.h>
#include <libavformat/avformat.h> #include <libavformat/avformat.h>
struct video_buffer; #define DECODER_MAX_SINKS 1
struct decoder { struct decoder {
struct sc_packet_sink packet_sink; // packet sink trait 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; AVCodecContext *codec_ctx;
AVFrame *frame; AVFrame *frame;
}; };
void void
decoder_init(struct decoder *decoder, struct video_buffer *vb); decoder_init(struct decoder *decoder);
bool
decoder_open(struct decoder *decoder, const AVCodec *codec);
void void
decoder_close(struct decoder *decoder); decoder_add_sink(struct decoder *decoder, struct sc_frame_sink *sink);
#endif #endif

View file

@ -318,7 +318,7 @@ scrcpy(const struct scrcpy_options *options) {
file_handler_initialized = true; file_handler_initialized = true;
} }
decoder_init(&decoder, &video_buffer); decoder_init(&decoder);
dec = &decoder; dec = &decoder;
} }
@ -382,6 +382,8 @@ scrcpy(const struct scrcpy_options *options) {
} }
screen_initialized = true; screen_initialized = true;
decoder_add_sink(&decoder, &screen.frame_sink);
if (options->turn_screen_off) { if (options->turn_screen_off) {
struct control_msg msg; struct control_msg msg;
msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE; msg.type = CONTROL_MSG_TYPE_SET_SCREEN_POWER_MODE;