summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Opalach <andrew@akon.city> 2025-09-08 18:36:05 -0400
committerAndrew Opalach <andrew@akon.city> 2025-09-08 18:36:05 -0400
commitf5038bc66041ba8a721cedb125cddc342a9a9e4b (patch)
treeefc1340642778b2481dd356038f74e159360b046
parentac3fd1a688202375612e905da9ee63bd6cd36a6f (diff)
downloadcamu-f5038bc66041ba8a721cedb125cddc342a9a9e4b.tar.gz
camu-f5038bc66041ba8a721cedb125cddc342a9a9e4b.tar.bz2
camu-f5038bc66041ba8a721cedb125cddc342a9a9e4b.zip
Fix FFmpeg decoder/demuxer deinit, misc cleanup
Signed-off-by: Andrew Opalach <andrew@akon.city>
-rw-r--r--src/cache/entry.h2
-rw-r--r--src/codec/codec.h21
-rw-r--r--src/codec/ffmpeg/decoder.c34
-rw-r--r--src/codec/ffmpeg/demuxer.c13
-rw-r--r--src/codec/ffmpeg/resampler.c3
-rw-r--r--src/fruits/cmsrv/ui.c2
-rw-r--r--src/server/server.c4
-rw-r--r--tests/cue_splitter.c7
8 files changed, 48 insertions, 38 deletions
diff --git a/src/cache/entry.h b/src/cache/entry.h
index 693e68b..ef2ee41 100644
--- a/src/cache/entry.h
+++ b/src/cache/entry.h
@@ -17,6 +17,7 @@
- cue + multiple files
- dvd/bluray (drive or iso)
- live source (radio antenna)
+ - remote resource
Chapters:
- Potential resources with chapters:
@@ -67,6 +68,7 @@
and loaded with different cds.
[ ] Separate cch_handler from cch_entry.
- Move waits to entry?
+ - Pick first entry in order as the unloaded entry, remove every other entry.
- Create cache entry with argument like file, cue, http, hls, etc.
- Handlers created internally, and run on different step.
[ ] Maybe rename cch_handler.
diff --git a/src/codec/codec.h b/src/codec/codec.h
index 9820316..0829847 100644
--- a/src/codec/codec.h
+++ b/src/codec/codec.h
@@ -425,18 +425,28 @@ static inline s32 camu_pixel_format_from_channels(s32 channels)
static inline void camu_codec_frame_discard(struct camu_codec_frame *frame)
{
+ switch (frame->mode) {
#ifdef CAMU_HAVE_FFMPEG
- if (frame->mode == CAMU_FFMPEG_COMPAT) av_frame_free(&frame->av.frame);
+ case CAMU_FFMPEG_COMPAT:
+ av_frame_free(&frame->av.frame);
+ break;
#endif
- if (frame->mode == CAMU_NORMAL && frame->data) al_free(frame->data);
+ case CAMU_NORMAL:
+ if (frame->data) al_free(frame->data);
+ break;
+ }
al_free(frame);
}
static inline s32 camu_guess_format(str *short_name, str *ext, str *mime_type)
{
- if (al_str_eq(ext, &al_str_c(".png"))) {
+ if ((ext && al_str_eq(ext, &al_str_c(".png"))) ||
+ (short_name && al_str_eq(short_name, &al_str_c("png"))) ||
+ (mime_type && al_str_eq(mime_type, &al_str_c("image/png")))) {
return CAMU_CODEC_PNG;
- } else if (al_str_eq(ext, &al_str_c(".jpeg")) || al_str_eq(ext, &al_str_c(".jpg"))) {
+ } else if ((ext && (al_str_eq(ext, &al_str_c(".jpeg")) || al_str_eq(ext, &al_str_c(".jpg")))) ||
+ (short_name && al_str_eq(short_name, &al_str_c("jpeg"))) ||
+ (mime_type && al_str_eq(mime_type, &al_str_c("image/jpeg")))) {
return CAMU_CODEC_JPEG;
}
#ifdef CAMU_HAVE_FFMPEG
@@ -450,9 +460,6 @@ static inline s32 camu_guess_format(str *short_name, str *ext, str *mime_type)
if (c_mime_type) al_free(c_mime_type);
// In FFmpeg AV_CODEC_ID_MJPEG also means "image2".
if (fmt) return (fmt->audio_codec != AV_CODEC_ID_NONE) ? fmt->audio_codec : fmt->video_codec;
-#else
- (void)short_name;
- (void)mime_type;
#endif
return -1;
}
diff --git a/src/codec/ffmpeg/decoder.c b/src/codec/ffmpeg/decoder.c
index 47bab44..6eff28b 100644
--- a/src/codec/ffmpeg/decoder.c
+++ b/src/codec/ffmpeg/decoder.c
@@ -60,6 +60,7 @@ static s32 get_buffer2(AVCodecContext *context, AVFrame *pic, s32 flags)
return ret;
}
+// This is currently untested.
static s32 init_hwframe_context(struct camu_ff_decoder *av, AVCodecContext *context, AVBufferRef *hw_device_context)
{
AVBufferRef *hw_frames_ref;
@@ -83,9 +84,11 @@ static s32 init_hwframe_context(struct camu_ff_decoder *av, AVCodecContext *cont
return ret;
}
+ context->hw_frames_ctx = hw_frames_ref;
+ /*
context->hw_frames_ctx = av_buffer_ref(hw_frames_ref);
-
av_buffer_unref(&hw_frames_ref);
+ */
return ret;
}
@@ -128,8 +131,6 @@ out:
static s32 init_hwdevice_context(struct camu_ff_decoder *av, AVCodecContext *context)
{
- av->hw_context = NULL;
-
s32 ret = av_hwdevice_ctx_create(&av->hw_context, av->hw_device_type, NULL, NULL, 0);
if (ret < 0) {
log_error("Failed to create specified HW device.");
@@ -208,12 +209,14 @@ static void close_internal(struct camu_ff_decoder *av)
{
if (av->codec_context) avcodec_free_context(&av->codec_context);
#ifdef CAMU_FF_DECODER_HWACCEL
- if (av->errored_hw_context) avcodec_free_context(&av->errored_hw_context);
+ if (av->hw_context) av_buffer_unref(&av->hw_context);
al_array_free(av->supported_hw_codecs);
al_array_free(av->supported_hw_devices);
+ if (av->errored_hw_context) avcodec_free_context(&av->errored_hw_context);
#endif
}
+// If decoder_init() fails, we should still expect decoder_free() to by called which will run close_internal().
static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *renderer, struct camu_codec_stream *stream,
void (*callback)(void *, struct camu_codec_frame *), void *userdata)
{
@@ -221,16 +224,17 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
av->codec_context = NULL;
#ifdef CAMU_FF_DECODER_HWACCEL
- av->errored_hw_context = NULL;
+ av->hw_context = NULL;
al_array_init(av->supported_hw_codecs);
al_array_init(av->supported_hw_devices);
+ av->errored_hw_context = NULL;
#endif
AVCodecParameters *codecpar = stream->av.stream->codecpar;
const AVCodec *codec = avcodec_find_decoder(codecpar->codec_id);
if (!codec) {
log_error("Failed to find decoder.");
- goto err;
+ return false;
}
bool is_video = codecpar->codec_type == AVMEDIA_TYPE_VIDEO && stream->duration > 0;
@@ -253,6 +257,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
const AVCodec *hw_codec;
al_array_foreach(av->supported_hw_codecs, i, hw_codec) {
if (hw_codec->id == codecpar->codec_id) {
+ // @TODO: hw_codec's without a hwdevice (v4l2m2m, cuvid, amf).
size_t length = al_strlen(hw_codec->wrapper_name);
av->hw_device_type = hw_device_supported_by_name(av, hw_codec->wrapper_name, length);
if (get_hwdevice_config(av, hw_codec, av->hw_device_type)) {
@@ -270,7 +275,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
#endif
if (!alloc_codec_context_internal(av, codec, codecpar)) {
- goto err;
+ return false;
}
#ifdef CAMU_FF_DECODER_HWACCEL
@@ -295,9 +300,10 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
if (av->hw_device_type == AV_HWDEVICE_TYPE_NONE) {
#endif
// FF_THREAD_FRAME or FF_THREAD_SLICE.
- // Both modes can get choked on certain videos, sometimes SLICE can squeeze
- // out a little more performance but a higher thread_count with FRAME seems
- // like the safest default.
+ // Both modes can get choked on certain videos, higher thread_count with
+ // FRAME seems like the safest default.
+ // @TODO: Check ffmpeg source, SLICE + FRAME?
+ // - https://ffmpeg.org/ffmpeg-codecs.html#Codec-Options
av->codec_context->thread_type = FF_THREAD_FRAME;
av->codec_context->thread_count = av->thread_count;
log_info("Using %i threads for decoder.", av->thread_count);
@@ -310,7 +316,7 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
//av->codec_context->flags2 |= AV_CODEC_FLAG2_FAST;
if (!open_avcodec_internal(av, codec)) {
- goto err;
+ return false;
}
log_info("Codec: %s (%s) %lldkbps.", codec->name,
@@ -321,15 +327,12 @@ static bool ff_decoder_init(struct camu_decoder *dec, struct camu_renderer *rend
av->userdata = userdata;
return true;
-err:
- close_internal(av);
- return false;
}
static s32 send_packet(struct camu_ff_decoder *av, AVPacket *pkt)
{
s32 ret = avcodec_send_packet(av->codec_context, pkt);
- if (ret < 0 && ret != AVERROR(EAGAIN) && ret != AVERROR_EOF) {
+ if (ret < 0 && !(ret == AVERROR(EAGAIN) || ret == AVERROR_EOF)) {
log_error("Error sending packet to the decoder (%s).", av_err2str(ret));
}
return ret;
@@ -361,6 +364,7 @@ static s32 receive_frames(struct camu_ff_decoder *av)
al_free(frame);
// Checking for EAGAIN should prevent an infinite loop.
if (ret == AVERROR(EAGAIN) || ret == AVERROR_EOF) break;
+ log_error("Error receiving packet from the decoder (%s).", av_err2str(ret));
continue;
}
if (avframe->best_effort_timestamp == AV_NOPTS_VALUE) {
diff --git a/src/codec/ffmpeg/demuxer.c b/src/codec/ffmpeg/demuxer.c
index a8f1df7..e5aa2f6 100644
--- a/src/codec/ffmpeg/demuxer.c
+++ b/src/codec/ffmpeg/demuxer.c
@@ -31,7 +31,7 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl
av->format_context = avformat_alloc_context();
if (!av->format_context) {
log_error("Failed to create format context.");
- goto err;
+ return false;
}
// This is meant to be the "block size" so, if I understand correctly, that would mean
@@ -40,7 +40,7 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl
av->io_context = avio_alloc_context(buf, al_page_size, 0, handle, camu_avio_read, NULL, camu_avio_seek);
if (!av->io_context) {
log_error("Failed to create custom io context.");
- goto err;
+ return false;
}
if (!cch_handle_can_seek(handle)) {
@@ -67,7 +67,7 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl
if (ret < 0) {
log_error("Failed to open input (%s).", av_err2str(ret));
av_dict_free(&opts);
- goto err;
+ return false;
}
av_dict_free(&opts);
@@ -75,12 +75,12 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl
ret = avformat_find_stream_info(av->format_context, NULL);
if (ret < 0) {
log_error("Failed to find stream info (%s).", av_err2str(ret));
- goto err;
+ return false;
}
if (!av->format_context->nb_streams) {
log_error("No streams found.");
- goto err;
+ return false;
}
s64 default_duration = (av->format_context->duration < 0) ? 0 : av->format_context->duration;
@@ -143,9 +143,6 @@ static bool ff_demuxer_init(struct camu_demuxer *demux, struct cch_handle *handl
av->eof = false;
return true;
-err:
- close_internal(av);
- return false;
}
static bool subscribed_to_index(struct camu_demuxer *demux, s32 index)
diff --git a/src/codec/ffmpeg/resampler.c b/src/codec/ffmpeg/resampler.c
index b141681..fa868c8 100644
--- a/src/codec/ffmpeg/resampler.c
+++ b/src/codec/ffmpeg/resampler.c
@@ -8,8 +8,9 @@
static bool ff_resampler_init(struct camu_resampler *resamp, struct camu_resampler_format *fmt)
{
struct camu_ff_resampler *av = (struct camu_ff_resampler *)resamp;
- al_assert(fmt->resampler_needed);
+ av->resample_context = NULL;
+ al_assert(fmt->resampler_needed);
camu_audio_format_copy(&av->fmt, &fmt->req);
SwrContext *swr = swr_alloc();
diff --git a/src/fruits/cmsrv/ui.c b/src/fruits/cmsrv/ui.c
index 1dd5fa2..e8fbc41 100644
--- a/src/fruits/cmsrv/ui.c
+++ b/src/fruits/cmsrv/ui.c
@@ -118,6 +118,7 @@ static void erase_lists(struct cmsrv_ui *ui)
if (n) ncplane_erase(n);
}
+#ifdef CAMU_HAVE_PORTAL
static void putnwstr_maxwidth_yx(struct ncplane *n, u32 y, u32 x, u32 maxwidth, wstr *w)
{
ncplane_cursor_move_yx(n, y, x);
@@ -126,6 +127,7 @@ static void putnwstr_maxwidth_yx(struct ncplane *n, u32 y, u32 x, u32 maxwidth,
ncplane_putwc(n, al_wstr_at(w, i));
}
}
+#endif
static void render_lists(struct cmsrv_ui *ui)
{
diff --git a/src/server/server.c b/src/server/server.c
index db55ae2..e76f6f4 100644
--- a/src/server/server.c
+++ b/src/server/server.c
@@ -330,7 +330,7 @@ static struct cch_entry *entry_from_post(struct camu_server *server, struct camu
}
}
if (!entry) {
- log_error("Failed to load post media %.*s %u.", al_str_x(&post->unique_id), index);
+ log_error("Failed to load media from post %.*s (index: %u).", al_str_x(&post->unique_id), index);
return NULL;
}
entry->handler->maybe_spawn_worker(entry->handler, 0);
@@ -467,7 +467,7 @@ static void list_callback(void *userdata, u8 op, struct lia_list_entry *entry, v
send_clients_entry_seeked(server, list, entry);
break;
case LIANA_META_ENTRY_ERRORED:
- log_error("Failed to load: %.*s.", al_str_x(&entry->brief));
+ log_error("Errored: %.*s.", al_str_x(&entry->brief));
break;
}
break;
diff --git a/tests/cue_splitter.c b/tests/cue_splitter.c
index 9b6561d..b5a8627 100644
--- a/tests/cue_splitter.c
+++ b/tests/cue_splitter.c
@@ -185,7 +185,7 @@ s32 main(s32 argc, char *argv[])
al_str_clone(&output_path, &output_dir);
al_str_cat(&output_path, &al_str_c("/"));
al_str_cat(&output_path, &info->filename);
- // start and length from libcue ignore all gaps.
+ // start and length from libcue ignores all gaps.
info->start = track_get_start(track);
info->length = track_get_length(track);
al_printf("start: %zd, length: %zd, %.*s\n", info->start, info->length, al_str_x(&output_path));
@@ -195,8 +195,5 @@ s32 main(s32 argc, char *argv[])
return EXIT_SUCCESS;
}
#else
-s32 main(void)
-{
- return EXIT_FAILURE;
-}
+s32 main(void) { return EXIT_FAILURE; }
#endif