Make stream push packets to sinks
Now that decoder and recorder implement the packet sink trait, make stream push packets to the sinks without depending on the concrete sink types.
This commit is contained in:
parent
cbed38799e
commit
f7a1b67d66
7 changed files with 82 additions and 65 deletions
|
@ -41,8 +41,14 @@ decoder_close(struct decoder *decoder) {
|
||||||
avcodec_free_context(&decoder->codec_ctx);
|
avcodec_free_context(&decoder->codec_ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
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;
|
||||||
|
if (is_config) {
|
||||||
|
// nothing to do
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) {
|
if ((ret = avcodec_send_packet(decoder->codec_ctx, packet)) < 0) {
|
||||||
LOGE("Could not send video packet: %d", ret);
|
LOGE("Could not send video packet: %d", ret);
|
||||||
|
|
|
@ -28,7 +28,4 @@ decoder_open(struct decoder *decoder, const AVCodec *codec);
|
||||||
void
|
void
|
||||||
decoder_close(struct decoder *decoder);
|
decoder_close(struct decoder *decoder);
|
||||||
|
|
||||||
bool
|
|
||||||
decoder_push(struct decoder *decoder, const AVPacket *packet);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -216,7 +216,7 @@ run_recorder(void *data) {
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
recorder_open(struct recorder *recorder, const AVCodec *input_codec) {
|
recorder_open(struct recorder *recorder, const AVCodec *input_codec) {
|
||||||
const char *format_name = recorder_get_format_name(recorder->format);
|
const char *format_name = recorder_get_format_name(recorder->format);
|
||||||
assert(format_name);
|
assert(format_name);
|
||||||
|
@ -277,7 +277,7 @@ recorder_open(struct recorder *recorder, const AVCodec *input_codec) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
static void
|
||||||
recorder_close(struct recorder *recorder) {
|
recorder_close(struct recorder *recorder) {
|
||||||
sc_mutex_lock(&recorder->mutex);
|
sc_mutex_lock(&recorder->mutex);
|
||||||
recorder->stopped = true;
|
recorder->stopped = true;
|
||||||
|
@ -290,7 +290,7 @@ recorder_close(struct recorder *recorder) {
|
||||||
avformat_free_context(recorder->ctx);
|
avformat_free_context(recorder->ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
static bool
|
||||||
recorder_push(struct recorder *recorder, const AVPacket *packet) {
|
recorder_push(struct recorder *recorder, const AVPacket *packet) {
|
||||||
sc_mutex_lock(&recorder->mutex);
|
sc_mutex_lock(&recorder->mutex);
|
||||||
assert(!recorder->stopped);
|
assert(!recorder->stopped);
|
||||||
|
|
|
@ -49,13 +49,4 @@ recorder_init(struct recorder *recorder, const char *filename,
|
||||||
void
|
void
|
||||||
recorder_destroy(struct recorder *recorder);
|
recorder_destroy(struct recorder *recorder);
|
||||||
|
|
||||||
bool
|
|
||||||
recorder_open(struct recorder *recorder, const AVCodec *input_codec);
|
|
||||||
|
|
||||||
void
|
|
||||||
recorder_close(struct recorder *recorder);
|
|
||||||
|
|
||||||
bool
|
|
||||||
recorder_push(struct recorder *recorder, const AVPacket *packet);
|
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -336,7 +336,15 @@ scrcpy(const struct scrcpy_options *options) {
|
||||||
|
|
||||||
av_log_set_callback(av_log_callback);
|
av_log_set_callback(av_log_callback);
|
||||||
|
|
||||||
stream_init(&stream, server.video_socket, dec, rec);
|
stream_init(&stream, server.video_socket);
|
||||||
|
|
||||||
|
if (dec) {
|
||||||
|
stream_add_sink(&stream, &dec->packet_sink);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (rec) {
|
||||||
|
stream_add_sink(&stream, &rec->packet_sink);
|
||||||
|
}
|
||||||
|
|
||||||
if (options->display) {
|
if (options->display) {
|
||||||
if (options->control) {
|
if (options->control) {
|
||||||
|
|
|
@ -66,25 +66,11 @@ notify_stopped(void) {
|
||||||
}
|
}
|
||||||
|
|
||||||
static bool
|
static bool
|
||||||
process_config_packet(struct stream *stream, AVPacket *packet) {
|
push_packet_to_sinks(struct stream *stream, const AVPacket *packet) {
|
||||||
if (stream->recorder && !recorder_push(stream->recorder, packet)) {
|
for (unsigned i = 0; i < stream->sink_count; ++i) {
|
||||||
LOGE("Could not send config packet to recorder");
|
struct sc_packet_sink *sink = stream->sinks[i];
|
||||||
return false;
|
if (!sink->ops->push(sink, packet)) {
|
||||||
}
|
LOGE("Could not send config packet to sink %d", i);
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
static bool
|
|
||||||
process_frame(struct stream *stream, AVPacket *packet) {
|
|
||||||
if (stream->decoder && !decoder_push(stream->decoder, packet)) {
|
|
||||||
return false;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (stream->recorder) {
|
|
||||||
packet->dts = packet->pts;
|
|
||||||
|
|
||||||
if (!recorder_push(stream->recorder, packet)) {
|
|
||||||
LOGE("Could not send packet to recorder");
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -111,9 +97,11 @@ stream_parse(struct stream *stream, AVPacket *packet) {
|
||||||
packet->flags |= AV_PKT_FLAG_KEY;
|
packet->flags |= AV_PKT_FLAG_KEY;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool ok = process_frame(stream, packet);
|
packet->dts = packet->pts;
|
||||||
|
|
||||||
|
bool ok = push_packet_to_sinks(stream, packet);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
LOGE("Could not process frame");
|
LOGE("Could not process packet");
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -156,7 +144,7 @@ stream_push_packet(struct stream *stream, AVPacket *packet) {
|
||||||
|
|
||||||
if (is_config) {
|
if (is_config) {
|
||||||
// config packet
|
// config packet
|
||||||
bool ok = process_config_packet(stream, packet);
|
bool ok = push_packet_to_sinks(stream, packet);
|
||||||
if (!ok) {
|
if (!ok) {
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -177,6 +165,33 @@ stream_push_packet(struct stream *stream, AVPacket *packet) {
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
stream_close_first_sinks(struct stream *stream, unsigned count) {
|
||||||
|
while (count) {
|
||||||
|
struct sc_packet_sink *sink = stream->sinks[--count];
|
||||||
|
sink->ops->close(sink);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static inline void
|
||||||
|
stream_close_sinks(struct stream *stream) {
|
||||||
|
stream_close_first_sinks(stream, stream->sink_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
static bool
|
||||||
|
stream_open_sinks(struct stream *stream, const AVCodec *codec) {
|
||||||
|
for (unsigned i = 0; i < stream->sink_count; ++i) {
|
||||||
|
struct sc_packet_sink *sink = stream->sinks[i];
|
||||||
|
if (!sink->ops->open(sink, codec)) {
|
||||||
|
LOGE("Could not open packet sink %d", i);
|
||||||
|
stream_close_first_sinks(stream, i);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
run_stream(void *data) {
|
run_stream(void *data) {
|
||||||
struct stream *stream = data;
|
struct stream *stream = data;
|
||||||
|
@ -193,22 +208,15 @@ run_stream(void *data) {
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->decoder && !decoder_open(stream->decoder, codec)) {
|
if (!stream_open_sinks(stream, codec)) {
|
||||||
LOGE("Could not open decoder");
|
LOGE("Could not open stream sinks");
|
||||||
goto finally_free_codec_ctx;
|
goto finally_free_codec_ctx;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (stream->recorder) {
|
|
||||||
if (!recorder_open(stream->recorder, codec)) {
|
|
||||||
LOGE("Could not open recorder");
|
|
||||||
goto finally_close_decoder;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
stream->parser = av_parser_init(AV_CODEC_ID_H264);
|
stream->parser = av_parser_init(AV_CODEC_ID_H264);
|
||||||
if (!stream->parser) {
|
if (!stream->parser) {
|
||||||
LOGE("Could not initialize parser");
|
LOGE("Could not initialize parser");
|
||||||
goto finally_close_recorder;
|
goto finally_close_sinks;
|
||||||
}
|
}
|
||||||
|
|
||||||
// We must only pass complete frames to av_parser_parse2()!
|
// We must only pass complete frames to av_parser_parse2()!
|
||||||
|
@ -238,14 +246,8 @@ run_stream(void *data) {
|
||||||
}
|
}
|
||||||
|
|
||||||
av_parser_close(stream->parser);
|
av_parser_close(stream->parser);
|
||||||
finally_close_recorder:
|
finally_close_sinks:
|
||||||
if (stream->recorder) {
|
stream_close_sinks(stream);
|
||||||
recorder_close(stream->recorder);
|
|
||||||
}
|
|
||||||
finally_close_decoder:
|
|
||||||
if (stream->decoder) {
|
|
||||||
decoder_close(stream->decoder);
|
|
||||||
}
|
|
||||||
finally_free_codec_ctx:
|
finally_free_codec_ctx:
|
||||||
avcodec_free_context(&stream->codec_ctx);
|
avcodec_free_context(&stream->codec_ctx);
|
||||||
end:
|
end:
|
||||||
|
@ -254,12 +256,18 @@ end:
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
stream_init(struct stream *stream, socket_t socket,
|
stream_init(struct stream *stream, socket_t socket) {
|
||||||
struct decoder *decoder, struct recorder *recorder) {
|
|
||||||
stream->socket = socket;
|
stream->socket = socket;
|
||||||
stream->decoder = decoder,
|
|
||||||
stream->recorder = recorder;
|
|
||||||
stream->has_pending = false;
|
stream->has_pending = false;
|
||||||
|
stream->sink_count = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
stream_add_sink(struct stream *stream, struct sc_packet_sink *sink) {
|
||||||
|
assert(stream->sink_count < STREAM_MAX_SINKS);
|
||||||
|
assert(sink);
|
||||||
|
assert(sink->ops);
|
||||||
|
stream->sinks[stream->sink_count++] = sink;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -8,14 +8,19 @@
|
||||||
#include <libavformat/avformat.h>
|
#include <libavformat/avformat.h>
|
||||||
#include <SDL2/SDL_atomic.h>
|
#include <SDL2/SDL_atomic.h>
|
||||||
|
|
||||||
|
#include "trait/packet_sink.h"
|
||||||
#include "util/net.h"
|
#include "util/net.h"
|
||||||
#include "util/thread.h"
|
#include "util/thread.h"
|
||||||
|
|
||||||
|
#define STREAM_MAX_SINKS 2
|
||||||
|
|
||||||
struct stream {
|
struct stream {
|
||||||
socket_t socket;
|
socket_t socket;
|
||||||
sc_thread thread;
|
sc_thread thread;
|
||||||
struct decoder *decoder;
|
|
||||||
struct recorder *recorder;
|
struct sc_packet_sink *sinks[STREAM_MAX_SINKS];
|
||||||
|
unsigned sink_count;
|
||||||
|
|
||||||
AVCodecContext *codec_ctx;
|
AVCodecContext *codec_ctx;
|
||||||
AVCodecParserContext *parser;
|
AVCodecParserContext *parser;
|
||||||
// successive packets may need to be concatenated, until a non-config
|
// successive packets may need to be concatenated, until a non-config
|
||||||
|
@ -25,8 +30,10 @@ struct stream {
|
||||||
};
|
};
|
||||||
|
|
||||||
void
|
void
|
||||||
stream_init(struct stream *stream, socket_t socket,
|
stream_init(struct stream *stream, socket_t socket);
|
||||||
struct decoder *decoder, struct recorder *recorder);
|
|
||||||
|
void
|
||||||
|
stream_add_sink(struct stream *stream, struct sc_packet_sink *sink);
|
||||||
|
|
||||||
bool
|
bool
|
||||||
stream_start(struct stream *stream);
|
stream_start(struct stream *stream);
|
||||||
|
|
Loading…
Reference in a new issue