2017-12-12 15:12:07 +01:00
|
|
|
#include "decoder.h"
|
|
|
|
|
|
2024-12-20 20:58:41 +01:00
|
|
|
#include <errno.h>
|
|
|
|
|
#include <libavcodec/packet.h>
|
|
|
|
|
#include <libavutil/avutil.h>
|
2017-12-12 15:12:07 +01:00
|
|
|
|
2019-11-24 11:53:00 +01:00
|
|
|
#include "util/log.h"
|
2017-12-12 15:12:07 +01:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
/** Downcast packet_sink to decoder */
|
2022-02-02 19:27:41 +01:00
|
|
|
#define DOWNCAST(SINK) container_of(SINK, struct sc_decoder, packet_sink)
|
2021-04-11 15:01:05 +02:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
static bool
|
2025-05-10 10:23:02 +02:00
|
|
|
sc_decoder_open(struct sc_decoder *decoder, AVCodecContext *ctx,
|
|
|
|
|
const struct sc_stream_session *session) {
|
2021-04-11 15:01:05 +02:00
|
|
|
decoder->frame = av_frame_alloc();
|
|
|
|
|
if (!decoder->frame) {
|
2021-11-24 22:06:11 +01:00
|
|
|
LOG_OOM();
|
2021-04-11 15:01:05 +02:00
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2025-05-10 10:23:02 +02:00
|
|
|
if (!sc_frame_source_sinks_open(&decoder->frame_source, ctx, session)) {
|
2021-04-11 15:01:05 +02:00
|
|
|
av_frame_free(&decoder->frame);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-10 19:25:45 +01:00
|
|
|
decoder->ctx = ctx;
|
|
|
|
|
|
2025-06-15 12:37:07 +02:00
|
|
|
// A video stream must have a session
|
|
|
|
|
assert(session || ctx->codec_type != AVMEDIA_TYPE_VIDEO);
|
|
|
|
|
|
|
|
|
|
if (session) {
|
|
|
|
|
decoder->session = *session;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
memset(&decoder->frame_size, 0, sizeof(decoder->frame_size));
|
|
|
|
|
|
2019-03-02 23:52:22 +01:00
|
|
|
return true;
|
2019-03-02 16:43:43 +01:00
|
|
|
}
|
2018-10-10 22:12:36 -07:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
static void
|
2022-02-02 19:27:41 +01:00
|
|
|
sc_decoder_close(struct sc_decoder *decoder) {
|
2023-03-02 09:37:36 +01:00
|
|
|
sc_frame_source_sinks_close(&decoder->frame_source);
|
2021-04-11 15:01:05 +02:00
|
|
|
av_frame_free(&decoder->frame);
|
2019-03-02 16:43:43 +01:00
|
|
|
}
|
2017-12-12 15:12:07 +01:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
static bool
|
2022-02-02 19:27:41 +01:00
|
|
|
sc_decoder_push(struct sc_decoder *decoder, const AVPacket *packet) {
|
2021-04-11 15:01:05 +02:00
|
|
|
bool is_config = packet->pts == AV_NOPTS_VALUE;
|
|
|
|
|
if (is_config) {
|
|
|
|
|
// nothing to do
|
|
|
|
|
return true;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-10 19:25:45 +01:00
|
|
|
int ret = avcodec_send_packet(decoder->ctx, packet);
|
2021-04-18 17:13:58 +02:00
|
|
|
if (ret < 0 && ret != AVERROR(EAGAIN)) {
|
2023-02-24 21:22:35 +01:00
|
|
|
LOGE("Decoder '%s': could not send video packet: %d",
|
|
|
|
|
decoder->name, ret);
|
2019-03-02 23:52:22 +01:00
|
|
|
return false;
|
2017-12-12 15:12:07 +01:00
|
|
|
}
|
2023-02-28 21:20:28 +01:00
|
|
|
|
|
|
|
|
for (;;) {
|
2023-03-10 19:25:45 +01:00
|
|
|
ret = avcodec_receive_frame(decoder->ctx, decoder->frame);
|
2023-02-28 21:20:28 +01:00
|
|
|
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) {
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (ret) {
|
|
|
|
|
LOGE("Decoder '%s', could not receive video frame: %d",
|
|
|
|
|
decoder->name, ret);
|
|
|
|
|
return false;
|
|
|
|
|
}
|
|
|
|
|
|
2019-03-02 16:43:43 +01:00
|
|
|
// a frame was received
|
2025-06-15 12:37:07 +02:00
|
|
|
|
|
|
|
|
if (decoder->ctx->codec_type == AVMEDIA_TYPE_VIDEO) {
|
|
|
|
|
assert(decoder->frame->width >= 0);
|
|
|
|
|
assert(decoder->frame->height >= 0);
|
|
|
|
|
struct sc_size frame_size = {
|
|
|
|
|
.width = decoder->frame->width,
|
|
|
|
|
.height = decoder->frame->height,
|
|
|
|
|
};
|
|
|
|
|
if (decoder->frame_size.width != frame_size.width
|
|
|
|
|
|| decoder->frame_size.height != frame_size.height) {
|
|
|
|
|
// The frame size has changed, check if it matches the session
|
|
|
|
|
uint32_t sw = decoder->session.video.width;
|
|
|
|
|
uint32_t sh = decoder->session.video.height;
|
|
|
|
|
if (frame_size.width != sw || frame_size.height != sh) {
|
|
|
|
|
LOGW("Unexpected video size: %" PRIu32 "x%" PRIu32
|
|
|
|
|
" (expected %" PRIu32 "x%" PRIu32 ")",
|
|
|
|
|
frame_size.width, frame_size.height, sw, sh);
|
|
|
|
|
|
|
|
|
|
LOGW("The encoder did not respect the requested size, "
|
|
|
|
|
"please retry with a lower resolution (-m/--max-size)");
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
decoder->frame_size = frame_size;
|
|
|
|
|
}
|
|
|
|
|
|
2023-03-02 09:37:36 +01:00
|
|
|
bool ok = sc_frame_source_sinks_push(&decoder->frame_source,
|
|
|
|
|
decoder->frame);
|
2021-04-26 18:05:43 +02:00
|
|
|
av_frame_unref(decoder->frame);
|
2023-03-03 00:42:51 +01:00
|
|
|
if (!ok) {
|
|
|
|
|
// Error already logged
|
|
|
|
|
return false;
|
|
|
|
|
}
|
2018-10-10 22:12:36 -07:00
|
|
|
}
|
2023-02-28 21:20:28 +01:00
|
|
|
|
2019-03-02 23:52:22 +01:00
|
|
|
return true;
|
2017-12-12 15:12:07 +01:00
|
|
|
}
|
2021-04-11 15:01:05 +02:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
static bool
|
2025-05-10 10:23:02 +02:00
|
|
|
sc_decoder_push_session(struct sc_decoder *decoder,
|
|
|
|
|
const struct sc_stream_session *session) {
|
2025-06-15 12:37:07 +02:00
|
|
|
decoder->session = *session;
|
2025-05-10 10:23:02 +02:00
|
|
|
return sc_frame_source_sinks_push_session(&decoder->frame_source, session);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
|
|
|
|
sc_decoder_packet_sink_open(struct sc_packet_sink *sink, AVCodecContext *ctx,
|
|
|
|
|
const struct sc_stream_session *session) {
|
2022-02-02 19:27:41 +01:00
|
|
|
struct sc_decoder *decoder = DOWNCAST(sink);
|
2025-05-10 10:23:02 +02:00
|
|
|
return sc_decoder_open(decoder, ctx, session);
|
2021-04-11 15:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void
|
2022-02-02 19:27:41 +01:00
|
|
|
sc_decoder_packet_sink_close(struct sc_packet_sink *sink) {
|
|
|
|
|
struct sc_decoder *decoder = DOWNCAST(sink);
|
|
|
|
|
sc_decoder_close(decoder);
|
2021-04-11 15:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static bool
|
2022-02-02 19:27:41 +01:00
|
|
|
sc_decoder_packet_sink_push(struct sc_packet_sink *sink,
|
|
|
|
|
const AVPacket *packet) {
|
|
|
|
|
struct sc_decoder *decoder = DOWNCAST(sink);
|
|
|
|
|
return sc_decoder_push(decoder, packet);
|
2021-04-11 15:01:05 +02:00
|
|
|
}
|
|
|
|
|
|
2025-05-10 10:23:02 +02:00
|
|
|
static bool
|
|
|
|
|
sc_decoder_packet_sink_push_session(struct sc_packet_sink *sink,
|
|
|
|
|
const struct sc_stream_session *session) {
|
|
|
|
|
|
|
|
|
|
struct sc_decoder *decoder = DOWNCAST(sink);
|
|
|
|
|
return sc_decoder_push_session(decoder, session);
|
|
|
|
|
}
|
|
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
void
|
2023-02-24 21:22:35 +01:00
|
|
|
sc_decoder_init(struct sc_decoder *decoder, const char *name) {
|
|
|
|
|
decoder->name = name; // statically allocated
|
2023-03-02 09:37:36 +01:00
|
|
|
sc_frame_source_init(&decoder->frame_source);
|
2021-05-28 21:23:10 +02:00
|
|
|
|
2021-04-11 15:01:05 +02:00
|
|
|
static const struct sc_packet_sink_ops ops = {
|
2022-02-02 19:27:41 +01:00
|
|
|
.open = sc_decoder_packet_sink_open,
|
|
|
|
|
.close = sc_decoder_packet_sink_close,
|
|
|
|
|
.push = sc_decoder_packet_sink_push,
|
2025-05-10 10:23:02 +02:00
|
|
|
.push_session = sc_decoder_packet_sink_push_session,
|
2021-04-11 15:01:05 +02:00
|
|
|
};
|
|
|
|
|
|
|
|
|
|
decoder->packet_sink.ops = &ops;
|
2021-04-11 15:01:05 +02:00
|
|
|
}
|