Loading debian/changelog +12 −0 Original line number Diff line number Diff line mediadb (20260422+64) unstable; urgency=low * Speed up preview generation (webp/jpeg): - Set probesize/max_analyze_duration before avformat_open_input so format detection reads less data over cluster I/O. - Use JPEG lowres decoding when target dimensions are much smaller than source (avoids full-resolution decode of large photos). - Tune WebP encoder: compression_level=0, quality=80, preset=photo for significantly faster encoding with minimal quality loss. -- Jan Koester <jan.koester@tuxist.de> Wed, 22 Apr 2026 00:00:00 +0200 mediadb (20260422+63) unstable; urgency=low * Speed up raw media data delivery: Loading src/preview.cpp +25 −5 Original line number Diff line number Diff line Loading @@ -577,9 +577,11 @@ std::optional<PreviewResult> FFmpegPreviewer::encode_frame(AVFrame* frame, const std::string mime = "image/jpeg"; AVPixelFormat encoder_pix_fmt = static_cast<AVPixelFormat>(frame->format); bool is_webp = false; if (fmt == "webp") { encoder = avcodec_find_encoder(AV_CODEC_ID_WEBP); mime = "image/webp"; is_webp = true; } else if (fmt == "png") { encoder = avcodec_find_encoder(AV_CODEC_ID_PNG); mime = "image/png"; Loading Loading @@ -611,7 +613,12 @@ std::optional<PreviewResult> FFmpegPreviewer::encode_frame(AVFrame* frame, const enc_ctx->pix_fmt = encoder_pix_fmt; enc_ctx->time_base = AVRational{1, 25}; if (fmt == "avif") { if (is_webp) { // Fastest compression — quality 80 is visually fine for previews. av_opt_set_int(enc_ctx->priv_data, "compression_level", 0, 0); av_opt_set_int(enc_ctx->priv_data, "quality", 80, 0); av_opt_set(enc_ctx->priv_data, "preset", "photo", 0); } else if (fmt == "avif") { enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; enc_ctx->bit_rate = 0; av_opt_set(enc_ctx->priv_data, "crf", "32", 0); Loading Loading @@ -796,6 +803,10 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& if (!format_ctx) { avio_context_free(&avio_ctx); error_out = "avformat_alloc_context failed"; return std::nullopt; } format_ctx->pb = avio_ctx; format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO; // Limit probing *before* open so format detection reads less data // over cluster I/O. format_ctx->probesize = 1024 * 1024; format_ctx->max_analyze_duration = 2 * AV_TIME_BASE; int rc = avformat_open_input(&format_ctx, nullptr, nullptr, nullptr); if (rc < 0) { Loading @@ -809,10 +820,6 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& }; std::unique_ptr<AVFormatContext, decltype(format_deleter)> format_guard(format_ctx, format_deleter); // Limit probe to 1 MB / 2s — avoids reading large amounts of data // over cluster I/O just to detect codec parameters. format_ctx->probesize = 1024 * 1024; format_ctx->max_analyze_duration = 2 * AV_TIME_BASE; rc = avformat_find_stream_info(format_ctx, nullptr); if (rc < 0) { error_out = "avformat_find_stream_info failed: " + ff_err2str(rc); Loading Loading @@ -840,6 +847,19 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& // Use multi-threaded decoding — significant speedup for H.264/H.265 dec_ctx->thread_count = 0; // auto-detect (usually hardware_concurrency) dec_ctx->thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE; // For JPEG/MJPEG: use lowres to decode at reduced resolution when the // target is much smaller than the source. Avoids decoding a 30 MP // photo at full resolution just to scale it down to 1280px. if (decoder->id == AV_CODEC_ID_MJPEG || decoder->id == AV_CODEC_ID_JPEG2000) { const int src_dim = std::max(stream->codecpar->width, stream->codecpar->height); const int tgt_dim = std::max(width, height); if (tgt_dim > 0 && src_dim > tgt_dim * 4) dec_ctx->lowres = (src_dim > tgt_dim * 8) ? 3 : 2; else if (tgt_dim > 0 && src_dim > tgt_dim * 2) dec_ctx->lowres = 1; } rc = avcodec_open2(dec_ctx, decoder, nullptr); if (rc < 0) { error_out = "avcodec_open2 decoder failed"; return std::nullopt; } Loading Loading
debian/changelog +12 −0 Original line number Diff line number Diff line mediadb (20260422+64) unstable; urgency=low * Speed up preview generation (webp/jpeg): - Set probesize/max_analyze_duration before avformat_open_input so format detection reads less data over cluster I/O. - Use JPEG lowres decoding when target dimensions are much smaller than source (avoids full-resolution decode of large photos). - Tune WebP encoder: compression_level=0, quality=80, preset=photo for significantly faster encoding with minimal quality loss. -- Jan Koester <jan.koester@tuxist.de> Wed, 22 Apr 2026 00:00:00 +0200 mediadb (20260422+63) unstable; urgency=low * Speed up raw media data delivery: Loading
src/preview.cpp +25 −5 Original line number Diff line number Diff line Loading @@ -577,9 +577,11 @@ std::optional<PreviewResult> FFmpegPreviewer::encode_frame(AVFrame* frame, const std::string mime = "image/jpeg"; AVPixelFormat encoder_pix_fmt = static_cast<AVPixelFormat>(frame->format); bool is_webp = false; if (fmt == "webp") { encoder = avcodec_find_encoder(AV_CODEC_ID_WEBP); mime = "image/webp"; is_webp = true; } else if (fmt == "png") { encoder = avcodec_find_encoder(AV_CODEC_ID_PNG); mime = "image/png"; Loading Loading @@ -611,7 +613,12 @@ std::optional<PreviewResult> FFmpegPreviewer::encode_frame(AVFrame* frame, const enc_ctx->pix_fmt = encoder_pix_fmt; enc_ctx->time_base = AVRational{1, 25}; if (fmt == "avif") { if (is_webp) { // Fastest compression — quality 80 is visually fine for previews. av_opt_set_int(enc_ctx->priv_data, "compression_level", 0, 0); av_opt_set_int(enc_ctx->priv_data, "quality", 80, 0); av_opt_set(enc_ctx->priv_data, "preset", "photo", 0); } else if (fmt == "avif") { enc_ctx->flags |= AV_CODEC_FLAG_GLOBAL_HEADER; enc_ctx->bit_rate = 0; av_opt_set(enc_ctx->priv_data, "crf", "32", 0); Loading Loading @@ -796,6 +803,10 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& if (!format_ctx) { avio_context_free(&avio_ctx); error_out = "avformat_alloc_context failed"; return std::nullopt; } format_ctx->pb = avio_ctx; format_ctx->flags |= AVFMT_FLAG_CUSTOM_IO; // Limit probing *before* open so format detection reads less data // over cluster I/O. format_ctx->probesize = 1024 * 1024; format_ctx->max_analyze_duration = 2 * AV_TIME_BASE; int rc = avformat_open_input(&format_ctx, nullptr, nullptr, nullptr); if (rc < 0) { Loading @@ -809,10 +820,6 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& }; std::unique_ptr<AVFormatContext, decltype(format_deleter)> format_guard(format_ctx, format_deleter); // Limit probe to 1 MB / 2s — avoids reading large amounts of data // over cluster I/O just to detect codec parameters. format_ctx->probesize = 1024 * 1024; format_ctx->max_analyze_duration = 2 * AV_TIME_BASE; rc = avformat_find_stream_info(format_ctx, nullptr); if (rc < 0) { error_out = "avformat_find_stream_info failed: " + ff_err2str(rc); Loading Loading @@ -840,6 +847,19 @@ std::optional<PreviewResult> FFmpegPreviewer::render_streaming(MediaBackendApi& // Use multi-threaded decoding — significant speedup for H.264/H.265 dec_ctx->thread_count = 0; // auto-detect (usually hardware_concurrency) dec_ctx->thread_type = FF_THREAD_FRAME | FF_THREAD_SLICE; // For JPEG/MJPEG: use lowres to decode at reduced resolution when the // target is much smaller than the source. Avoids decoding a 30 MP // photo at full resolution just to scale it down to 1280px. if (decoder->id == AV_CODEC_ID_MJPEG || decoder->id == AV_CODEC_ID_JPEG2000) { const int src_dim = std::max(stream->codecpar->width, stream->codecpar->height); const int tgt_dim = std::max(width, height); if (tgt_dim > 0 && src_dim > tgt_dim * 4) dec_ctx->lowres = (src_dim > tgt_dim * 8) ? 3 : 2; else if (tgt_dim > 0 && src_dim > tgt_dim * 2) dec_ctx->lowres = 1; } rc = avcodec_open2(dec_ctx, decoder, nullptr); if (rc < 0) { error_out = "avcodec_open2 decoder failed"; return std::nullopt; } Loading