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:
parent
08b3086ffc
commit
6f5ad21f57
3 changed files with 70 additions and 14 deletions
|
@ -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;
|
||||||
|
}
|
||||||
|
|
|
@ -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
|
||||||
|
|
|
@ -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;
|
||||||
|
|
Loading…
Reference in a new issue