From 130a0edc0405e53b45f8b2f8da0b94356480a644 Mon Sep 17 00:00:00 2001 From: Andrew Opalach Date: Mon, 1 Jan 2024 11:23:22 -0500 Subject: wip Signed-off-by: Andrew Opalach --- src/codec/libav/demuxer.c | 56 ++++++++++++++++++++++---------------------- src/codec/libav/packet_ext.h | 1 + src/codec/libav/scaler.c | 25 ++++++++++++-------- 3 files changed, 44 insertions(+), 38 deletions(-) (limited to 'src/codec/libav') diff --git a/src/codec/libav/demuxer.c b/src/codec/libav/demuxer.c index f7ff35c..d823d23 100644 --- a/src/codec/libav/demuxer.c +++ b/src/codec/libav/demuxer.c @@ -65,47 +65,30 @@ static bool lav_demuxer_init(struct camu_demuxer *demux, struct cch_handle *hand av->duration = 0; - bool audio_selected = false; - bool video_selected = false; +#define GUESS_STREAM_IS_IMAGE(stream) \ + (stream->duration >= 0 && stream->nb_frames <= 1 && (stream->avg_frame_rate.den == 0 && stream->r_frame_rate.den > 0)) for (u32 i = 0; i < av->format_context->nb_streams; i++) { AVStream *stream = av->format_context->streams[i]; enum AVMediaType type = stream->codecpar->codec_type; - if (!(type == AVMEDIA_TYPE_AUDIO || type == AVMEDIA_TYPE_VIDEO)) { - continue; - } - if (type == AVMEDIA_TYPE_AUDIO) { - if (audio_selected) continue; - else audio_selected = true; - } - if (type == AVMEDIA_TYPE_VIDEO) { - if (video_selected) continue; - else video_selected = true; - } // Try to detect attached images. - if (type == AVMEDIA_TYPE_VIDEO && stream->duration >= 0 && stream->nb_frames <= 1 && - (stream->avg_frame_rate.den == 0 && stream->r_frame_rate.den > 0)) { - stream->duration = 0; + if (type == AVMEDIA_TYPE_VIDEO && GUESS_STREAM_IS_IMAGE(stream)) { al_log_info("lav_demux", "Assuming stream #%i is an image.", i); + stream->duration = 0; } else if (stream->duration < 0) { + al_log_warn("lav_demux", "Stream #%i has invalid duration (%ld).", av->format_context->duration); if (av->format_context->duration < 0) { stream->duration = 0; } else { - // This could be completely wrong. In that case, it's still probably - // better than 0 (assuming the stream is not an image). - stream->duration = av_rescale_q(av->format_context->duration, - AV_TIME_BASE_Q, stream->time_base); + stream->duration = av_rescale_q(av->format_context->duration, AV_TIME_BASE_Q, stream->time_base); } - al_log_info("lav_demux", "Setting stream #%i to a duration of %.3fs.", - i, stream->duration * av_q2d(stream->time_base)); + al_log_info("lav_demux", "Setting stream #%i to a duration of %.3fs.", i, stream->duration * av_q2d(stream->time_base)); } if (stream->start_time < 0) { - stream->start_time = 0; + al_log_warn("lav_demux", "Stream has a negative start_time (%ld).", stream->start_time); } s64 duration = av_rescale_q(stream->duration, stream->time_base, AV_TIME_BASE_Q); - if (duration > av->duration) { - av->duration = duration; - } + if (duration > av->duration) av->duration = duration; al_array_push(av->demux.streams, ((struct camu_stream){ .type = CAMU_FFMPEG_COMPAT, .av.stream = stream @@ -125,6 +108,15 @@ err: return false; } +static bool subscribed_to_index(struct camu_demuxer *demux, s32 index) +{ + s32 subscribed; + al_array_foreach(demux->subscribed, i, subscribed) { + if (subscribed == index) return true; + } + return false; +} + static s32 lav_demuxer_get_packet(struct camu_demuxer *demux, struct camu_packet *packet) { struct camu_lav_demuxer *av = (struct camu_lav_demuxer *)demux; @@ -132,12 +124,19 @@ static s32 lav_demuxer_get_packet(struct camu_demuxer *demux, struct camu_packet s32 ret = 0; do { ret = av_read_frame(av->format_context, packet->av.pkt); - if (ret < 0 && ret != AVERROR_EOF) { + if (ret == AVERROR_EOF) { + av->eof = true; + break; + } + if (ret < 0) { al_log_error("lav_demuxer", "Failed to read frame (%s).", av_err2str(ret)); } + if (!subscribed_to_index(demux, packet->av.pkt->stream_index)) { + av_packet_unref(packet->av.pkt); + continue; + } break; } while (1); - if (ret == AVERROR_EOF) av->eof = true; return ret; } @@ -175,6 +174,7 @@ struct camu_demuxer *camu_lav_demuxer_create(void) struct camu_lav_demuxer *av = al_alloc_object(struct camu_lav_demuxer); av->demux.type = CAMU_FFMPEG_COMPAT; al_array_init(av->demux.streams); + al_array_init(av->demux.subscribed); av->demux.init = lav_demuxer_init; av->demux.get_packet = lav_demuxer_get_packet; av->demux.get_duration = lav_demuxer_get_duration; diff --git a/src/codec/libav/packet_ext.h b/src/codec/libav/packet_ext.h index e2f7cd5..ff6e337 100644 --- a/src/codec/libav/packet_ext.h +++ b/src/codec/libav/packet_ext.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include #include diff --git a/src/codec/libav/scaler.c b/src/codec/libav/scaler.c index 6146c69..882116f 100644 --- a/src/codec/libav/scaler.c +++ b/src/codec/libav/scaler.c @@ -9,6 +9,12 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, s32 width, s32 height) { AVFrame *frame = av_frame_alloc(); if (!frame) return NULL; + s32 ret = av_image_alloc(frame->data, frame->linesize, width, height, pix_fmt, 32); + if (ret < 0) { + al_log_error("lav_scaler", "Failed to allocate picture buffer (%s).", av_err2str(ret)); + return NULL; + } + /* s32 size = av_image_get_buffer_size(pix_fmt, width, height, 1); u8 *buffer = (u8 *)av_malloc(size); if (!buffer) { @@ -21,6 +27,7 @@ static AVFrame *alloc_picture(enum AVPixelFormat pix_fmt, s32 width, s32 height) av_free(frame); return NULL; } + */ frame->width = width; frame->height = height; frame->format = pix_fmt; @@ -31,32 +38,28 @@ bool camu_lav_scaler_init(struct camu_lav_scaler *scale, struct camu_lav_scale_f { al_memset(scale, 0, sizeof(struct camu_lav_scaler)); - /* if (fmt->in_width == fmt->req_width && fmt->in_height == fmt->req_height && fmt->in_format == fmt->req_format) { fmt->scaler_needed = false; return true; } - */ - - fmt->scaler_needed = true; + s32 flags = SWS_BITEXACT; scale->scaler_context = sws_getContext(fmt->in_width, fmt->in_height, fmt->in_format, - fmt->req_width, fmt->req_height, fmt->req_format, - SWS_BITEXACT, NULL, NULL, NULL); - + fmt->req_width, fmt->req_height, fmt->req_format, flags, NULL, NULL, NULL); if (!scale->scaler_context) { al_log_error("lav_scaler", "Failed to create scaler context."); return false; } scale->frame = alloc_picture(fmt->req_format, fmt->req_width, fmt->req_height); - if (!scale->frame) { al_log_error("lav_scaler", "Failed to allocate frame."); return false; } + fmt->scaler_needed = true; + scale->fmt = *fmt; return true; @@ -64,8 +67,8 @@ bool camu_lav_scaler_init(struct camu_lav_scaler *scale, struct camu_lav_scale_f bool camu_lav_scaler_scale(struct camu_lav_scaler *scale, const u8 **in_slice, s32 *in_strides) { - s32 ret = sws_scale(scale->scaler_context, in_slice, in_strides, 0, - scale->fmt.in_height, scale->frame->data, scale->frame->linesize); + s32 ret = sws_scale(scale->scaler_context, in_slice, in_strides, 0, scale->fmt.in_height, + scale->frame->data, scale->frame->linesize); if (ret != scale->fmt.req_height) { al_log_error("lav_scaler", "Failed to scale frame (%s).", av_err2str(ret)); return false; @@ -75,5 +78,7 @@ bool camu_lav_scaler_scale(struct camu_lav_scaler *scale, const u8 **in_slice, s void camu_lav_scaler_close(struct camu_lav_scaler *scale) { + av_freep(&scale->frame->data[0]); + av_frame_free(&scale->frame); sws_freeContext(scale->scaler_context); } -- cgit v1.2.3-101-g0448