diff --git a/debian/patches/0001_fix-segment-muxer.patch b/debian/patches/0001_fix-segment-muxer.patch deleted file mode 100644 index d3b57793d..000000000 --- a/debian/patches/0001_fix-segment-muxer.patch +++ /dev/null @@ -1,37 +0,0 @@ -Index: jellyfin-ffmpeg/libavformat/segment.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/segment.c -+++ jellyfin-ffmpeg/libavformat/segment.c -@@ -87,6 +87,7 @@ typedef struct SegmentContext { - int64_t last_val; ///< remember last time for wrap around detection - int cut_pending; - int header_written; ///< whether we've already called avformat_write_header -+ int64_t start_pts; ///< pts of the very first packet processed, used to compute correct segment length - - char *entry_prefix; ///< prefix to add to list entry filenames - int list_type; ///< set the list type -@@ -712,6 +713,7 @@ static int seg_init(AVFormatContext *s) - if ((ret = parse_frames(s, &seg->frames, &seg->nb_frames, seg->frames_str)) < 0) - return ret; - } else { -+ seg->start_pts = -1; - if (seg->use_clocktime) { - if (seg->time <= 0) { - av_log(s, AV_LOG_ERROR, "Invalid negative segment_time with segment_atclocktime option set\n"); -@@ -889,7 +891,15 @@ calc_times: - seg->cut_pending = 1; - seg->last_val = wrapped_val; - } else { -- end_pts = seg->time * (seg->segment_count + 1); -+ if (seg->start_pts != -1) { -+ end_pts = seg->start_pts + seg->time * (seg->segment_count + 1); -+ } else if (pkt->stream_index == seg->reference_stream_index && pkt->pts != AV_NOPTS_VALUE) { -+ // this is the first packet of the reference stream we see, initialize start point -+ seg->start_pts = av_rescale_q(pkt->pts, st->time_base, AV_TIME_BASE_Q); -+ seg->cur_entry.start_time = (double)pkt->pts * av_q2d(st->time_base); -+ seg->cur_entry.start_pts = seg->start_pts; -+ end_pts = seg->start_pts + seg->time * (seg->segment_count + 1); -+ } - } - } - diff --git a/debian/patches/0002-lavfi-add-a-filter-for-uploading-normal-frames-to-VAAPI.patch b/debian/patches/0002-lavfi-add-a-filter-for-uploading-normal-frames-to-VAAPI.patch deleted file mode 100644 index 63eea729c..000000000 --- a/debian/patches/0002-lavfi-add-a-filter-for-uploading-normal-frames-to-VAAPI.patch +++ /dev/null @@ -1,241 +0,0 @@ -#From c1fb9225a1b8e26875cb9b4e2b3ae2f4d68c5630 Mon Sep 17 00:00:00 2001 -#From: nyanmisaka -#Date: Sun, 24 Jan 2021 19:58:04 +0800 -#Subject: [PATCH] lavfi: add a filter for uploading normal frames to VAAPI -Index: jellyfin-ffmpeg/configure -=================================================================== ---- jellyfin-ffmpeg.orig/configure -+++ jellyfin-ffmpeg/configure -@@ -3577,6 +3577,7 @@ fspp_filter_deps="gpl" - headphone_filter_select="fft" - histeq_filter_deps="gpl" - hqdn3d_filter_deps="gpl" -+hwupload_vaapi_filter_deps="vaapi" - interlace_filter_deps="gpl" - kerndeint_filter_deps="gpl" - ladspa_filter_deps="ladspa libdl" -Index: jellyfin-ffmpeg/libavfilter/Makefile -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/Makefile -+++ jellyfin-ffmpeg/libavfilter/Makefile -@@ -297,6 +297,7 @@ OBJS-$(CONFIG_HUE_FILTER) - OBJS-$(CONFIG_HWDOWNLOAD_FILTER) += vf_hwdownload.o - OBJS-$(CONFIG_HWMAP_FILTER) += vf_hwmap.o - OBJS-$(CONFIG_HWUPLOAD_CUDA_FILTER) += vf_hwupload_cuda.o -+OBJS-$(CONFIG_HWUPLOAD_VAAPI_FILTER) += vf_hwupload_vaapi.o - OBJS-$(CONFIG_HWUPLOAD_FILTER) += vf_hwupload.o - OBJS-$(CONFIG_HYSTERESIS_FILTER) += vf_hysteresis.o framesync.o - OBJS-$(CONFIG_IDENTITY_FILTER) += vf_identity.o -Index: jellyfin-ffmpeg/libavfilter/allfilters.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/allfilters.c -+++ jellyfin-ffmpeg/libavfilter/allfilters.c -@@ -282,6 +282,7 @@ extern AVFilter ff_vf_hwdownload; - extern AVFilter ff_vf_hwmap; - extern AVFilter ff_vf_hwupload; - extern AVFilter ff_vf_hwupload_cuda; -+extern AVFilter ff_vf_hwupload_vaapi; - extern AVFilter ff_vf_hysteresis; - extern AVFilter ff_vf_identity; - extern AVFilter ff_vf_idet; -Index: jellyfin-ffmpeg/libavfilter/vf_hwupload_vaapi.c -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/vf_hwupload_vaapi.c -@@ -0,0 +1,196 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "libavutil/buffer.h" -+#include "libavutil/hwcontext.h" -+#include "libavutil/log.h" -+#include "libavutil/opt.h" -+ -+#include "avfilter.h" -+#include "formats.h" -+#include "internal.h" -+#include "video.h" -+ -+typedef struct VaapiUploadContext { -+ const AVClass *class; -+ int device_idx; -+ -+ AVBufferRef *hwdevice; -+ AVBufferRef *hwframe; -+} VaapiUploadContext; -+ -+static av_cold int vaapiupload_init(AVFilterContext *ctx) -+{ -+ VaapiUploadContext *s = ctx->priv; -+ return av_hwdevice_ctx_create(&s->hwdevice, AV_HWDEVICE_TYPE_VAAPI, NULL, NULL, 0); -+} -+ -+static av_cold void vaapiupload_uninit(AVFilterContext *ctx) -+{ -+ VaapiUploadContext *s = ctx->priv; -+ -+ av_buffer_unref(&s->hwframe); -+ av_buffer_unref(&s->hwdevice); -+} -+ -+static int vaapiupload_query_formats(AVFilterContext *ctx) -+{ -+ int ret; -+ -+ static const enum AVPixelFormat input_pix_fmts[] = { -+ AV_PIX_FMT_NV12, AV_PIX_FMT_YUV420P, AV_PIX_FMT_YUV422P, -+ AV_PIX_FMT_UYVY422, AV_PIX_FMT_YUYV422, AV_PIX_FMT_Y210, -+ AV_PIX_FMT_YUV411P, AV_PIX_FMT_YUV440P, AV_PIX_FMT_YUV444P, -+ AV_PIX_FMT_GRAY8, AV_PIX_FMT_P010, AV_PIX_FMT_BGRA, -+ AV_PIX_FMT_BGR0, AV_PIX_FMT_RGBA, AV_PIX_FMT_RGB0, -+ AV_PIX_FMT_ABGR, AV_PIX_FMT_0BGR, AV_PIX_FMT_ARGB, -+ AV_PIX_FMT_0RGB, AV_PIX_FMT_NONE, -+ }; -+ static const enum AVPixelFormat output_pix_fmts[] = { -+ AV_PIX_FMT_VAAPI, AV_PIX_FMT_NONE, -+ }; -+ AVFilterFormats *in_fmts = ff_make_format_list(input_pix_fmts); -+ AVFilterFormats *out_fmts; -+ -+ ret = ff_formats_ref(in_fmts, &ctx->inputs[0]->outcfg.formats); -+ if (ret < 0) -+ return ret; -+ -+ out_fmts = ff_make_format_list(output_pix_fmts); -+ -+ ret = ff_formats_ref(out_fmts, &ctx->outputs[0]->incfg.formats); -+ if (ret < 0) -+ return ret; -+ -+ return 0; -+} -+ -+static int vaapiupload_config_output(AVFilterLink *outlink) -+{ -+ AVFilterContext *ctx = outlink->src; -+ AVFilterLink *inlink = ctx->inputs[0]; -+ VaapiUploadContext *s = ctx->priv; -+ -+ AVHWFramesContext *hwframe_ctx; -+ int ret; -+ -+ av_buffer_unref(&s->hwframe); -+ s->hwframe = av_hwframe_ctx_alloc(s->hwdevice); -+ if (!s->hwframe) -+ return AVERROR(ENOMEM); -+ -+ hwframe_ctx = (AVHWFramesContext*)s->hwframe->data; -+ hwframe_ctx->format = AV_PIX_FMT_VAAPI; -+ if (inlink->hw_frames_ctx) { -+ AVHWFramesContext *in_hwframe_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; -+ hwframe_ctx->sw_format = in_hwframe_ctx->sw_format; -+ } else { -+ hwframe_ctx->sw_format = inlink->format; -+ } -+ hwframe_ctx->width = inlink->w; -+ hwframe_ctx->height = inlink->h; -+ -+ ret = av_hwframe_ctx_init(s->hwframe); -+ if (ret < 0) -+ return ret; -+ -+ outlink->hw_frames_ctx = av_buffer_ref(s->hwframe); -+ if (!outlink->hw_frames_ctx) -+ return AVERROR(ENOMEM); -+ -+ return 0; -+} -+ -+static int vaapiupload_filter_frame(AVFilterLink *link, AVFrame *in) -+{ -+ AVFilterContext *ctx = link->dst; -+ AVFilterLink *outlink = ctx->outputs[0]; -+ -+ AVFrame *out = NULL; -+ int ret; -+ -+ out = ff_get_video_buffer(outlink, outlink->w, outlink->h); -+ if (!out) { -+ ret = AVERROR(ENOMEM); -+ goto fail; -+ } -+ -+ out->width = in->width; -+ out->height = in->height; -+ -+ ret = av_hwframe_transfer_data(out, in, 0); -+ if (ret < 0) { -+ av_log(ctx, AV_LOG_ERROR, "Error transferring data to the GPU\n"); -+ goto fail; -+ } -+ -+ ret = av_frame_copy_props(out, in); -+ if (ret < 0) -+ goto fail; -+ -+ av_frame_free(&in); -+ -+ return ff_filter_frame(ctx->outputs[0], out); -+fail: -+ av_frame_free(&in); -+ av_frame_free(&out); -+ return ret; -+} -+ -+static const AVClass vaapiupload_class = { -+ .class_name = "vaapiupload", -+ .item_name = av_default_item_name, -+ .option = NULL, -+ .version = LIBAVUTIL_VERSION_INT, -+}; -+ -+static const AVFilterPad vaapiupload_inputs[] = { -+ { -+ .name = "default", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .filter_frame = vaapiupload_filter_frame, -+ }, -+ { NULL } -+}; -+ -+static const AVFilterPad vaapiupload_outputs[] = { -+ { -+ .name = "default", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .config_props = vaapiupload_config_output, -+ }, -+ { NULL } -+}; -+ -+AVFilter ff_vf_hwupload_vaapi = { -+ .name = "hwupload_vaapi", -+ .description = NULL_IF_CONFIG_SMALL("Upload a system memory frame to a VAAPI device."), -+ -+ .init = vaapiupload_init, -+ .uninit = vaapiupload_uninit, -+ -+ .query_formats = vaapiupload_query_formats, -+ -+ .priv_size = sizeof(VaapiUploadContext), -+ .priv_class = &vaapiupload_class, -+ -+ .inputs = vaapiupload_inputs, -+ .outputs = vaapiupload_outputs, -+ -+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, -+}; diff --git a/debian/patches/0003-fix-for-the-broken-tonemap_vaapi-filter.patch b/debian/patches/0003-fix-for-the-broken-tonemap_vaapi-filter.patch deleted file mode 100644 index b5be1c3af..000000000 --- a/debian/patches/0003-fix-for-the-broken-tonemap_vaapi-filter.patch +++ /dev/null @@ -1,259 +0,0 @@ -# Fix for the broken tonemap_vaapi filter -# avfilter/tonemap_vaapi: pass filter parameters to VA parameter buffer -# avfilter: Add H2H support in tonemap_vaapi -Index: jellyfin-ffmpeg/libavfilter/vf_tonemap_vaapi.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_tonemap_vaapi.c -+++ jellyfin-ffmpeg/libavfilter/vf_tonemap_vaapi.c -@@ -41,7 +41,11 @@ typedef struct HDRVAAPIContext { - enum AVColorTransferCharacteristic color_transfer; - enum AVColorSpace color_matrix; - -+ char *master_display; -+ char *content_light; -+ - VAHdrMetaDataHDR10 in_metadata; -+ VAHdrMetaDataHDR10 out_metadata; - - AVFrameSideData *src_display; - AVFrameSideData *src_light; -@@ -148,6 +152,107 @@ static int tonemap_vaapi_save_metadata(A - return 0; - } - -+static int tonemap_vaapi_update_sidedata(AVFilterContext *avctx, AVFrame *output_frame) -+{ -+ HDRVAAPIContext *ctx = avctx->priv; -+ AVFrameSideData *metadata; -+ AVMasteringDisplayMetadata *hdr_meta; -+ AVFrameSideData *metadata_lt; -+ AVContentLightMetadata *hdr_meta_lt; -+ -+ int i; -+ const int mapping[3] = {1, 2, 0}; //green, blue, red -+ const int chroma_den = 50000; -+ const int luma_den = 10000; -+ -+ metadata = av_frame_get_side_data(output_frame, -+ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); -+ if (metadata) { -+ av_frame_remove_side_data(output_frame, -+ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA); -+ metadata = av_frame_new_side_data(output_frame, -+ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, -+ sizeof(AVMasteringDisplayMetadata)); -+ } else { -+ metadata = av_frame_new_side_data(output_frame, -+ AV_FRAME_DATA_MASTERING_DISPLAY_METADATA, -+ sizeof(AVMasteringDisplayMetadata)); -+ } -+ -+ hdr_meta = (AVMasteringDisplayMetadata *)metadata->data; -+ -+ for (i = 0; i < 3; i++) { -+ const int j = mapping[i]; -+ hdr_meta->display_primaries[j][0].num = ctx->out_metadata.display_primaries_x[i]; -+ hdr_meta->display_primaries[j][0].den = chroma_den; -+ -+ hdr_meta->display_primaries[j][1].num = ctx->out_metadata.display_primaries_y[i]; -+ hdr_meta->display_primaries[j][1].den = chroma_den; -+ } -+ -+ hdr_meta->white_point[0].num = ctx->out_metadata.white_point_x; -+ hdr_meta->white_point[0].den = chroma_den; -+ -+ hdr_meta->white_point[1].num = ctx->out_metadata.white_point_y; -+ hdr_meta->white_point[1].den = chroma_den; -+ hdr_meta->has_primaries = 1; -+ -+ hdr_meta->max_luminance.num = ctx->out_metadata.max_display_mastering_luminance; -+ hdr_meta->max_luminance.den = luma_den; -+ -+ hdr_meta->min_luminance.num = ctx->out_metadata.min_display_mastering_luminance; -+ hdr_meta->min_luminance.den = luma_den; -+ hdr_meta->has_luminance = 1; -+ -+ av_log(avctx, AV_LOG_DEBUG, -+ "Mastering Display Metadata(out luminance):\n"); -+ av_log(avctx, AV_LOG_DEBUG, -+ "min_luminance=%u, max_luminance=%u\n", -+ ctx->out_metadata.min_display_mastering_luminance, -+ ctx->out_metadata.max_display_mastering_luminance); -+ -+ av_log(avctx, AV_LOG_DEBUG, -+ "Mastering Display Metadata(out primaries):\n"); -+ av_log(avctx, AV_LOG_DEBUG, -+ "G(%u,%u) B(%u,%u) R(%u,%u) WP(%u,%u)\n", -+ ctx->out_metadata.display_primaries_x[0], -+ ctx->out_metadata.display_primaries_y[0], -+ ctx->out_metadata.display_primaries_x[1], -+ ctx->out_metadata.display_primaries_y[1], -+ ctx->out_metadata.display_primaries_x[2], -+ ctx->out_metadata.display_primaries_y[2], -+ ctx->out_metadata.white_point_x, -+ ctx->out_metadata.white_point_y); -+ -+ metadata_lt = av_frame_get_side_data(output_frame, -+ AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); -+ if (metadata_lt) { -+ av_frame_remove_side_data(output_frame, -+ AV_FRAME_DATA_CONTENT_LIGHT_LEVEL); -+ metadata_lt = av_frame_new_side_data(output_frame, -+ AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, -+ sizeof(AVContentLightMetadata)); -+ } else { -+ metadata_lt = av_frame_new_side_data(output_frame, -+ AV_FRAME_DATA_CONTENT_LIGHT_LEVEL, -+ sizeof(AVContentLightMetadata)); -+ } -+ -+ hdr_meta_lt = (AVContentLightMetadata *)metadata_lt->data; -+ -+ hdr_meta_lt->MaxCLL = FFMIN(ctx->out_metadata.max_content_light_level, 65535); -+ hdr_meta_lt->MaxFALL = FFMIN(ctx->out_metadata.max_pic_average_light_level, 65535); -+ -+ av_log(avctx, AV_LOG_DEBUG, -+ "Mastering Content Light Level (out):\n"); -+ av_log(avctx, AV_LOG_DEBUG, -+ "MaxCLL(%u) MaxFALL(%u)\n", -+ ctx->out_metadata.max_content_light_level, -+ ctx->out_metadata.max_pic_average_light_level); -+ -+ return 0; -+} -+ - static int tonemap_vaapi_set_filter_params(AVFilterContext *avctx, AVFrame *input_frame) - { - VAAPIVPPContext *vpp_ctx = avctx->priv; -@@ -210,15 +315,26 @@ static int tonemap_vaapi_build_filter_pa - return AVERROR(EINVAL); - } - -- for (i = 0; i < num_query_caps; i++) { -- if (VA_TONE_MAPPING_HDR_TO_SDR & hdr_cap[i].caps_flag) -- break; -- } -- -- if (i >= num_query_caps) { -- av_log(avctx, AV_LOG_ERROR, -- "VAAPI driver doesn't support HDR to SDR\n"); -- return AVERROR(EINVAL); -+ if (ctx->color_transfer == AVCOL_TRC_SMPTE2084) { -+ for (i = 0; i < num_query_caps; i++) { -+ if (VA_TONE_MAPPING_HDR_TO_HDR & hdr_cap[i].caps_flag) -+ break; -+ } -+ if (i >= num_query_caps) { -+ av_log(avctx, AV_LOG_ERROR, -+ "VAAPI driver doesn't support HDR to HDR\n"); -+ return AVERROR(EINVAL); -+ } -+ } else { -+ for (i = 0; i < num_query_caps; i++) { -+ if (VA_TONE_MAPPING_HDR_TO_SDR & hdr_cap[i].caps_flag) -+ break; -+ } -+ if (i >= num_query_caps) { -+ av_log(avctx, AV_LOG_ERROR, -+ "VAAPI driver doesn't support HDR to SDR\n"); -+ return AVERROR(EINVAL); -+ } - } - - hdrtm_param.type = VAProcFilterHighDynamicRangeToneMapping; -@@ -243,6 +359,8 @@ static int tonemap_vaapi_filter_frame(AV - VAProcPipelineParameterBuffer params; - int err; - -+ VAHdrMetaData out_hdr_metadata; -+ - av_log(avctx, AV_LOG_DEBUG, "Filter input: %s, %ux%u (%"PRId64").\n", - av_get_pix_fmt_name(input_frame->format), - input_frame->width, input_frame->height, input_frame->pts); -@@ -291,11 +409,26 @@ static int tonemap_vaapi_filter_frame(AV - if (ctx->color_matrix != AVCOL_SPC_UNSPECIFIED) - output_frame->colorspace = ctx->color_matrix; - -+ if (output_frame->color_trc == AVCOL_TRC_SMPTE2084) { -+ err = tonemap_vaapi_update_sidedata(avctx, output_frame); -+ if (err < 0) -+ goto fail; -+ -+ out_hdr_metadata.metadata_type = VAProcHighDynamicRangeMetadataHDR10; -+ out_hdr_metadata.metadata = &ctx->out_metadata; -+ out_hdr_metadata.metadata_size = sizeof(VAHdrMetaDataHDR10); -+ -+ params.output_hdr_metadata = &out_hdr_metadata; -+ } -+ - err = ff_vaapi_vpp_init_params(avctx, ¶ms, - input_frame, output_frame); - if (err < 0) - goto fail; - -+ params.filters = &vpp_ctx->filter_buffers[0]; -+ params.num_filters = vpp_ctx->nb_filter_buffers; -+ - err = ff_vaapi_vpp_render_picture(avctx, ¶ms, output_frame); - if (err < 0) - goto fail; -@@ -355,6 +488,46 @@ static av_cold int tonemap_vaapi_init(AV - STRING_OPTION(color_transfer, color_transfer, AVCOL_TRC_UNSPECIFIED); - STRING_OPTION(color_matrix, color_space, AVCOL_SPC_UNSPECIFIED); - -+ if (ctx->color_transfer == AVCOL_TRC_SMPTE2084) { -+ if (!ctx->master_display) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Option mastering-display input invalid\n"); -+ return AVERROR(EINVAL); -+ } -+ -+ if (10 != sscanf(ctx->master_display, -+ "G(%hu|%hu)B(%hu|%hu)R(%hu|%hu)WP(%hu|%hu)L(%u|%u)", -+ &ctx->out_metadata.display_primaries_x[0], -+ &ctx->out_metadata.display_primaries_y[0], -+ &ctx->out_metadata.display_primaries_x[1], -+ &ctx->out_metadata.display_primaries_y[1], -+ &ctx->out_metadata.display_primaries_x[2], -+ &ctx->out_metadata.display_primaries_y[2], -+ &ctx->out_metadata.white_point_x, -+ &ctx->out_metadata.white_point_y, -+ &ctx->out_metadata.min_display_mastering_luminance, -+ &ctx->out_metadata.max_display_mastering_luminance)) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Option mastering-display input invalid\n"); -+ return AVERROR(EINVAL); -+ } -+ -+ if (!ctx->content_light) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Option content-light input invalid\n"); -+ return AVERROR(EINVAL); -+ } -+ -+ if (2 != sscanf(ctx->content_light, -+ "CLL(%hu)FALL(%hu)", -+ &ctx->out_metadata.max_content_light_level, -+ &ctx->out_metadata.max_pic_average_light_level)) { -+ av_log(avctx, AV_LOG_ERROR, -+ "Option content-light input invalid\n"); -+ return AVERROR(EINVAL); -+ } -+ } -+ - return 0; - } - -@@ -380,10 +553,11 @@ static const AVOption tonemap_vaapi_opti - { "t", "Output color transfer characteristics set", - OFFSET(color_transfer_string), AV_OPT_TYPE_STRING, - { .str = NULL }, .flags = FLAGS, "transfer" }, -+ { "display", "set master display", OFFSET(master_display), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, -+ { "light", "set content light", OFFSET(content_light), AV_OPT_TYPE_STRING, {.str=NULL}, CHAR_MIN, CHAR_MAX, FLAGS }, - { NULL } - }; - -- - AVFILTER_DEFINE_CLASS(tonemap_vaapi); - - static const AVFilterPad tonemap_vaapi_inputs[] = { diff --git a/debian/patches/0004-cuda-format-converter-impl.patch b/debian/patches/0004-cuda-format-converter-impl.patch deleted file mode 100644 index a01c782d5..000000000 --- a/debian/patches/0004-cuda-format-converter-impl.patch +++ /dev/null @@ -1,1438 +0,0 @@ -Index: jellyfin-ffmpeg/compat/cuda/cuda_runtime.h -=================================================================== ---- jellyfin-ffmpeg.orig/compat/cuda/cuda_runtime.h -+++ jellyfin-ffmpeg/compat/cuda/cuda_runtime.h -@@ -49,16 +49,6 @@ typedef struct __device_builtin__ __alig - unsigned short x, y; - } ushort2; - --typedef struct __device_builtin__ __align__(8) float2 --{ -- float x, y; --} float2; -- --typedef struct __device_builtin__ __align__(8) int2 --{ -- int x, y; --} int2; -- - typedef struct __device_builtin__ uint3 - { - unsigned int x, y, z; -@@ -66,6 +56,11 @@ typedef struct __device_builtin__ uint3 - - typedef struct uint3 dim3; - -+typedef struct __device_builtin__ __align__(8) int2 -+{ -+ int x, y; -+} int2; -+ - typedef struct __device_builtin__ __align__(4) uchar4 - { - unsigned char x, y, z, w; -@@ -81,11 +76,6 @@ typedef struct __device_builtin__ __alig - int x, y, z, w; - } int4; - --typedef struct __device_builtin__ __align__(16) float4 --{ -- float x, y, z, w; --} float4; -- - // Accessors for special registers - #define GETCOMP(reg, comp) \ - asm("mov.u32 %0, %%" #reg "." #comp ";" : "=r"(tmp)); \ -@@ -110,31 +100,24 @@ GET(getThreadIdx, tid) - #define threadIdx (getThreadIdx()) - - // Basic initializers (simple macros rather than inline functions) --#define make_int2(a, b) ((int2){.x = a, .y = b}) - #define make_uchar2(a, b) ((uchar2){.x = a, .y = b}) - #define make_ushort2(a, b) ((ushort2){.x = a, .y = b}) --#define make_float2(a, b) ((float2){.x = a, .y = b}) --#define make_int4(a, b, c, d) ((int4){.x = a, .y = b, .z = c, .w = d}) - #define make_uchar4(a, b, c, d) ((uchar4){.x = a, .y = b, .z = c, .w = d}) - #define make_ushort4(a, b, c, d) ((ushort4){.x = a, .y = b, .z = c, .w = d}) --#define make_float4(a, b, c, d) ((float4){.x = a, .y = b, .z = c, .w = d}) - - // Conversions from the tex instruction's 4-register output to various types - #define TEX2D(type, ret) static inline __device__ void conv(type* out, unsigned a, unsigned b, unsigned c, unsigned d) {*out = (ret);} - - TEX2D(unsigned char, a & 0xFF) - TEX2D(unsigned short, a & 0xFFFF) --TEX2D(float, a) --TEX2D(uchar2, make_uchar2(a & 0xFF, b & 0xFF)) --TEX2D(ushort2, make_ushort2(a & 0xFFFF, b & 0xFFFF)) --TEX2D(float2, make_float2(a, b)) --TEX2D(uchar4, make_uchar4(a & 0xFF, b & 0xFF, c & 0xFF, d & 0xFF)) --TEX2D(ushort4, make_ushort4(a & 0xFFFF, b & 0xFFFF, c & 0xFFFF, d & 0xFFFF)) --TEX2D(float4, make_float4(a, b, c, d)) -+TEX2D(uchar2, make_uchar2((unsigned char)a, (unsigned char)b)) -+TEX2D(ushort2, make_ushort2((unsigned short)a, (unsigned short)b)) -+TEX2D(uchar4, make_uchar4((unsigned char)a, (unsigned char)b, (unsigned char)c, (unsigned char)d)) -+TEX2D(ushort4, make_ushort4((unsigned short)a, (unsigned short)b, (unsigned short)c, (unsigned short)d)) - - // Template calling tex instruction and converting the output to the selected type --template --inline __device__ T tex2D(cudaTextureObject_t texObject, float x, float y) -+template -+static inline __device__ T tex2D(cudaTextureObject_t texObject, float x, float y) - { - T ret; - unsigned ret1, ret2, ret3, ret4; -@@ -145,44 +128,4 @@ inline __device__ T tex2D(cudaTextureObj - return ret; - } - --template<> --inline __device__ float4 tex2D(cudaTextureObject_t texObject, float x, float y) --{ -- float4 ret; -- asm("tex.2d.v4.f32.f32 {%0, %1, %2, %3}, [%4, {%5, %6}];" : -- "=r"(ret.x), "=r"(ret.y), "=r"(ret.z), "=r"(ret.w) : -- "l"(texObject), "f"(x), "f"(y)); -- return ret; --} -- --template<> --inline __device__ float tex2D(cudaTextureObject_t texObject, float x, float y) --{ -- return tex2D(texObject, x, y).x; --} -- --template<> --inline __device__ float2 tex2D(cudaTextureObject_t texObject, float x, float y) --{ -- float4 ret = tex2D(texObject, x, y); -- return make_float2(ret.x, ret.y); --} -- --// Math helper functions --static inline __device__ float floorf(float a) { return __builtin_floorf(a); } --static inline __device__ float floor(float a) { return __builtin_floorf(a); } --static inline __device__ double floor(double a) { return __builtin_floor(a); } --static inline __device__ float ceilf(float a) { return __builtin_ceilf(a); } --static inline __device__ float ceil(float a) { return __builtin_ceilf(a); } --static inline __device__ double ceil(double a) { return __builtin_ceil(a); } --static inline __device__ float truncf(float a) { return __builtin_truncf(a); } --static inline __device__ float trunc(float a) { return __builtin_truncf(a); } --static inline __device__ double trunc(double a) { return __builtin_trunc(a); } --static inline __device__ float fabsf(float a) { return __builtin_fabsf(a); } --static inline __device__ float fabs(float a) { return __builtin_fabsf(a); } --static inline __device__ double fabs(double a) { return __builtin_fabs(a); } -- --static inline __device__ float __sinf(float a) { return __nvvm_sin_approx_f(a); } --static inline __device__ float __cosf(float a) { return __nvvm_cos_approx_f(a); } -- - #endif /* COMPAT_CUDA_CUDA_RUNTIME_H */ -Index: jellyfin-ffmpeg/configure -=================================================================== ---- jellyfin-ffmpeg.orig/configure -+++ jellyfin-ffmpeg/configure -@@ -6250,7 +6250,7 @@ fi - if enabled cuda_nvcc; then - nvccflags="$nvccflags -ptx" - else -- nvccflags="$nvccflags -S -nocudalib -nocudainc --cuda-device-only -Wno-c++11-narrowing -include ${source_link}/compat/cuda/cuda_runtime.h" -+ nvccflags="$nvccflags -S -nocudalib -nocudainc --cuda-device-only -Wno-c++11-narrowing -std=c++14 -include ${source_link}/compat/cuda/cuda_runtime.h" - check_nvcc cuda_llvm - fi - -Index: jellyfin-ffmpeg/libavfilter/Makefile -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/Makefile -+++ jellyfin-ffmpeg/libavfilter/Makefile -@@ -392,8 +392,7 @@ OBJS-$(CONFIG_ROBERTS_OPENCL_FILTER) - OBJS-$(CONFIG_ROTATE_FILTER) += vf_rotate.o - OBJS-$(CONFIG_SAB_FILTER) += vf_sab.o - OBJS-$(CONFIG_SCALE_FILTER) += vf_scale.o scale_eval.o --OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o scale_eval.o \ -- vf_scale_cuda.ptx.o vf_scale_cuda_bicubic.ptx.o -+OBJS-$(CONFIG_SCALE_CUDA_FILTER) += vf_scale_cuda.o vf_scale_cuda.ptx.o scale_eval.o - OBJS-$(CONFIG_SCALE_NPP_FILTER) += vf_scale_npp.o scale_eval.o - OBJS-$(CONFIG_SCALE_QSV_FILTER) += vf_scale_qsv.o - OBJS-$(CONFIG_SCALE_VAAPI_FILTER) += vf_scale_vaapi.o scale_eval.o vaapi_vpp.o -Index: jellyfin-ffmpeg/libavfilter/cuda/vector_helpers.cuh -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/cuda/vector_helpers.cuh -+++ /dev/null -@@ -1,112 +0,0 @@ --/* -- * This file is part of FFmpeg. -- * -- * Permission is hereby granted, free of charge, to any person obtaining a -- * copy of this software and associated documentation files (the "Software"), -- * to deal in the Software without restriction, including without limitation -- * the rights to use, copy, modify, merge, publish, distribute, sublicense, -- * and/or sell copies of the Software, and to permit persons to whom the -- * Software is furnished to do so, subject to the following conditions: -- * -- * The above copyright notice and this permission notice shall be included in -- * all copies or substantial portions of the Software. -- * -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -- * DEALINGS IN THE SOFTWARE. -- */ -- --#ifndef AVFILTER_CUDA_VECTORHELPERS_H --#define AVFILTER_CUDA_VECTORHELPERS_H -- --typedef unsigned char uchar; --typedef unsigned short ushort; -- --template struct vector_helper { }; --template<> struct vector_helper { typedef float ftype; typedef int itype; }; --template<> struct vector_helper { typedef float2 ftype; typedef int2 itype; }; --template<> struct vector_helper { typedef float4 ftype; typedef int4 itype; }; --template<> struct vector_helper { typedef float ftype; typedef int itype; }; --template<> struct vector_helper { typedef float2 ftype; typedef int2 itype; }; --template<> struct vector_helper { typedef float4 ftype; typedef int4 itype; }; --template<> struct vector_helper { typedef float ftype; typedef int itype; }; --template<> struct vector_helper { typedef float2 ftype; typedef int2 itype; }; --template<> struct vector_helper { typedef float4 ftype; typedef int4 itype; }; -- --#define floatT typename vector_helper::ftype --#define intT typename vector_helper::itype -- --template inline __device__ V to_floatN(const T &a) { return (V)a; } --template inline __device__ T from_floatN(const V &a) { return (T)a; } -- --#define OPERATORS2(T) \ -- template inline __device__ T operator+(const T &a, const V &b) { return make_ ## T (a.x + b.x, a.y + b.y); } \ -- template inline __device__ T operator-(const T &a, const V &b) { return make_ ## T (a.x - b.x, a.y - b.y); } \ -- template inline __device__ T operator*(const T &a, V b) { return make_ ## T (a.x * b, a.y * b); } \ -- template inline __device__ T operator/(const T &a, V b) { return make_ ## T (a.x / b, a.y / b); } \ -- template inline __device__ T operator>>(const T &a, V b) { return make_ ## T (a.x >> b, a.y >> b); } \ -- template inline __device__ T operator<<(const T &a, V b) { return make_ ## T (a.x << b, a.y << b); } \ -- template inline __device__ T &operator+=(T &a, const V &b) { a.x += b.x; a.y += b.y; return a; } \ -- template inline __device__ void vec_set(T &a, const V &b) { a.x = b.x; a.y = b.y; } \ -- template inline __device__ void vec_set_scalar(T &a, V b) { a.x = b; a.y = b; } \ -- template<> inline __device__ float2 to_floatN(const T &a) { return make_float2(a.x, a.y); } \ -- template<> inline __device__ T from_floatN(const float2 &a) { return make_ ## T(a.x, a.y); } --#define OPERATORS4(T) \ -- template inline __device__ T operator+(const T &a, const V &b) { return make_ ## T (a.x + b.x, a.y + b.y, a.z + b.z, a.w + b.w); } \ -- template inline __device__ T operator-(const T &a, const V &b) { return make_ ## T (a.x - b.x, a.y - b.y, a.z - b.z, a.w - b.w); } \ -- template inline __device__ T operator*(const T &a, V b) { return make_ ## T (a.x * b, a.y * b, a.z * b, a.w * b); } \ -- template inline __device__ T operator/(const T &a, V b) { return make_ ## T (a.x / b, a.y / b, a.z / b, a.w / b); } \ -- template inline __device__ T operator>>(const T &a, V b) { return make_ ## T (a.x >> b, a.y >> b, a.z >> b, a.w >> b); } \ -- template inline __device__ T operator<<(const T &a, V b) { return make_ ## T (a.x << b, a.y << b, a.z << b, a.w << b); } \ -- template inline __device__ T &operator+=(T &a, const V &b) { a.x += b.x; a.y += b.y; a.z += b.z; a.w += b.w; return a; } \ -- template inline __device__ void vec_set(T &a, const V &b) { a.x = b.x; a.y = b.y; a.z = b.z; a.w = b.w; } \ -- template inline __device__ void vec_set_scalar(T &a, V b) { a.x = b; a.y = b; a.z = b; a.w = b; } \ -- template<> inline __device__ float4 to_floatN(const T &a) { return make_float4(a.x, a.y, a.z, a.w); } \ -- template<> inline __device__ T from_floatN(const float4 &a) { return make_ ## T(a.x, a.y, a.z, a.w); } -- --OPERATORS2(int2) --OPERATORS2(uchar2) --OPERATORS2(ushort2) --OPERATORS2(float2) --OPERATORS4(int4) --OPERATORS4(uchar4) --OPERATORS4(ushort4) --OPERATORS4(float4) -- --template inline __device__ void vec_set(int &a, V b) { a = b; } --template inline __device__ void vec_set(float &a, V b) { a = b; } --template inline __device__ void vec_set(uchar &a, V b) { a = b; } --template inline __device__ void vec_set(ushort &a, V b) { a = b; } --template inline __device__ void vec_set_scalar(int &a, V b) { a = b; } --template inline __device__ void vec_set_scalar(float &a, V b) { a = b; } --template inline __device__ void vec_set_scalar(uchar &a, V b) { a = b; } --template inline __device__ void vec_set_scalar(ushort &a, V b) { a = b; } -- --template --inline __device__ T lerp_scalar(T v0, T v1, float t) { -- return t*v1 + (1.0f - t)*v0; --} -- --template<> --inline __device__ float2 lerp_scalar(float2 v0, float2 v1, float t) { -- return make_float2( -- lerp_scalar(v0.x, v1.x, t), -- lerp_scalar(v0.y, v1.y, t) -- ); --} -- --template<> --inline __device__ float4 lerp_scalar(float4 v0, float4 v1, float t) { -- return make_float4( -- lerp_scalar(v0.x, v1.x, t), -- lerp_scalar(v0.y, v1.y, t), -- lerp_scalar(v0.z, v1.z, t), -- lerp_scalar(v0.w, v1.w, t) -- ); --} -- --#endif -Index: jellyfin-ffmpeg/libavfilter/dither_matrix.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/dither_matrix.h -@@ -0,0 +1,74 @@ -+/* -+ * Dither matrix data -+ * -+ * This file is placed in the public domain. -+ */ -+ -+#include -+static const int ff_fruit_dither_size = 64; -+static const uint16_t ff_fruit_dither_matrix[] = { -+ 332, 2776, 1933, 42, 2598, 1796, 1000, 2978, 1677, 3452, 2164, 1564, 2644, 358, 2012, 3471, 1147, 3071, 596, 1943, 3146, 1191, 2469, 919, 3664, 2359, 441, 2691, 1179, 3027, 1408, 298, 3892, 1825, 182, 2178, 3028, 317, 2412, 858, 3097, 2205, 1145, 2880, 990, 2697, 728, 1969, 2312, 1393, 3232, 1204, 3752, 1529, 448, 3955, 2076, 833, 3856, 1, 3445, 2105, 955, 1761, -+ 4060, 1053, 3038, 1445, 3302, 430, 3702, 2119, 625, 2523, 12, 3003, 959, 3814, 2388, 829, 4059, 2236, 1417, 3447, 198, 4020, 1891, 3368, 76, 1460, 2963, 1680, 3721, 535, 2275, 2916, 1226, 2348, 3580, 823, 1897, 4032, 1245, 2728, 194, 3285, 1941, 399, 3639, 1593, 3775, 1038, 3012, 162, 2687, 2029, 559, 2983, 1809, 2378, 325, 2861, 1331, 2533, 1171, 2701, 3328, 153, -+ 2214, 3412, 501, 3934, 892, 1918, 2686, 1199, 3090, 1351, 3779, 1776, 3371, 1457, 217, 2844, 1726, 311, 2896, 1021, 2604, 1546, 569, 2758, 1818, 3967, 727, 3305, 963, 1866, 3591, 853, 3215, 496, 2651, 1453, 2808, 704, 2247, 3395, 1779, 937, 4014, 2288, 1286, 3110, 331, 3309, 1839, 3866, 932, 3566, 2499, 1005, 3346, 1192, 3712, 1743, 3399, 757, 3765, 391, 1871, 2928, -+ 1411, 820, 2531, 1622, 2192, 3478, 215, 4079, 384, 3298, 742, 2332, 436, 2685, 1963, 3273, 680, 3571, 2033, 3795, 806, 3550, 2319, 1225, 3191, 1027, 2506, 237, 2196, 3126, 28, 2148, 1772, 3959, 1009, 3507, 85, 3742, 1539, 453, 3647, 2154, 573, 2786, 156, 2020, 2569, 1425, 538, 2375, 1723, 300, 1854, 4065, 110, 2741, 678, 3138, 213, 1979, 2330, 1530, 3542, 720, -+ 3811, 1955, 3240, 126, 2909, 760, 2482, 1493, 2301, 1719, 2788, 1180, 3998, 923, 3649, 1094, 1862, 2579, 1272, 30, 3109, 1987, 255, 3816, 471, 1977, 3519, 1557, 3882, 1086, 2754, 3776, 1304, 241, 2262, 1863, 3163, 1111, 2982, 2026, 1056, 2948, 1439, 3323, 1737, 3595, 860, 3980, 2895, 1193, 3365, 2779, 852, 2175, 3069, 1641, 2309, 1237, 2630, 4036, 965, 3052, 1096, 2487, -+ 289, 2863, 1190, 3633, 1330, 3834, 1075, 3429, 602, 3850, 174, 3242, 1657, 3080, 98, 2357, 3899, 374, 3224, 1619, 2431, 1125, 3019, 1367, 2395, 3102, 794, 2850, 426, 2451, 1687, 548, 3070, 2596, 3335, 565, 1630, 2459, 288, 3937, 2504, 51, 3740, 725, 2475, 433, 2706, 2075, 19, 3694, 633, 1982, 3149, 1345, 729, 3843, 411, 3654, 1681, 564, 2721, 104, 3875, 2110, -+ 3504, 1730, 537, 2398, 2058, 443, 2636, 1802, 2925, 953, 2568, 2005, 583, 2108, 2802, 1441, 889, 2726, 1949, 3984, 486, 3407, 624, 2698, 1648, 97, 4055, 1340, 1994, 3667, 913, 3453, 1964, 815, 1400, 4072, 2767, 873, 3457, 684, 1576, 3119, 1884, 1222, 3898, 1535, 3482, 982, 1817, 2520, 1487, 3927, 181, 3493, 2396, 1438, 2871, 985, 2070, 3498, 1370, 3279, 1655, 586, -+ 1280, 2625, 3912, 939, 2999, 1649, 3162, 64, 2130, 3606, 1428, 3469, 1256, 3824, 409, 3562, 1780, 3433, 768, 1206, 2843, 2086, 3869, 926, 3663, 2099, 1047, 2623, 3217, 148, 1810, 2498, 314, 3790, 2126, 129, 2037, 3088, 1356, 2314, 3301, 946, 2716, 2163, 250, 3091, 575, 2227, 3204, 359, 2970, 1110, 2594, 1867, 532, 3338, 43, 2492, 3172, 282, 2394, 842, 2852, 2019, -+ 3111, 31, 1813, 3256, 243, 3687, 851, 4002, 1301, 480, 3004, 264, 2493, 1586, 2947, 714, 2538, 165, 2193, 3597, 1514, 130, 1792, 3132, 348, 2875, 3434, 491, 1251, 2120, 3979, 1093, 2905, 979, 2561, 3625, 1230, 373, 3836, 1953, 197, 4028, 498, 3383, 1713, 2400, 1402, 4083, 1150, 3589, 2106, 592, 3650, 1252, 4012, 1975, 3047, 1574, 690, 3909, 1745, 3616, 349, 3976, -+ 894, 3438, 2251, 1160, 2582, 1467, 2342, 1747, 2837, 2242, 1076, 3946, 866, 3385, 1108, 1985, 4076, 1303, 2915, 438, 2589, 3312, 1085, 2367, 1916, 1403, 759, 2340, 3582, 2835, 637, 3264, 1997, 3506, 515, 1544, 3258, 2612, 1017, 2903, 1322, 1791, 3014, 1154, 3826, 871, 2858, 192, 2739, 719, 1701, 3177, 2222, 345, 2737, 770, 1181, 3774, 2264, 1060, 2667, 1262, 2318, 1584, -+ 2654, 1420, 499, 4045, 688, 3379, 319, 3490, 735, 3699, 1642, 2050, 2683, 40, 2204, 3096, 343, 3261, 1672, 3747, 900, 1981, 4025, 644, 3505, 2575, 3903, 1724, 232, 1517, 2590, 1405, 58, 1663, 3051, 2381, 751, 1756, 3646, 647, 3464, 2363, 826, 2563, 92, 3137, 1928, 3524, 1590, 2159, 3851, 84, 1423, 3082, 1684, 2417, 3417, 369, 1808, 3022, 118, 3254, 661, 3555, -+ 229, 3756, 2917, 1627, 2773, 1235, 2949, 1002, 2470, 140, 3274, 594, 3533, 1678, 3799, 933, 1812, 2457, 673, 2306, 1474, 3055, 292, 2820, 1293, 2, 1106, 3237, 2013, 3823, 439, 3611, 2093, 4015, 1264, 258, 3914, 2294, 16, 2692, 1983, 295, 3723, 1893, 3442, 1306, 619, 2371, 392, 2989, 1071, 2484, 3512, 666, 3796, 195, 1522, 2775, 3586, 875, 4086, 1921, 2883, 1163, -+ 2456, 1935, 1032, 2305, 111, 3845, 2036, 1555, 3964, 2115, 1289, 2911, 977, 2372, 465, 2616, 3618, 1211, 3933, 72, 3404, 772, 2424, 1662, 3755, 2252, 3025, 518, 2524, 855, 2953, 1102, 2811, 795, 2602, 3414, 2060, 891, 3357, 1132, 3965, 1495, 2806, 551, 1633, 2629, 3659, 1172, 3958, 1446, 3319, 798, 1787, 2768, 1271, 3184, 2210, 587, 1338, 2478, 1550, 483, 2198, 3388, -+ 832, 3219, 386, 3674, 1733, 2479, 578, 3214, 416, 3044, 1861, 291, 4033, 1449, 3477, 1940, 205, 2976, 885, 2704, 1886, 3820, 1070, 3288, 700, 1369, 1855, 4087, 1194, 3463, 1764, 2329, 297, 3296, 1742, 539, 1398, 3107, 1696, 2387, 711, 3151, 1223, 2219, 4038, 328, 2095, 2919, 845, 2595, 263, 2235, 4043, 398, 2129, 903, 3924, 1885, 3317, 249, 2732, 3685, 1383, 55, -+ 3926, 1481, 2977, 1177, 3292, 893, 3600, 1418, 2670, 927, 3637, 2477, 1127, 2665, 765, 2879, 1283, 2162, 3333, 1359, 482, 2180, 2942, 219, 2548, 3594, 308, 2759, 2185, 106, 3174, 699, 3738, 1139, 2277, 3833, 2804, 223, 3707, 415, 3518, 1913, 150, 2995, 864, 3222, 1575, 35, 3428, 1694, 3581, 992, 2907, 1494, 3676, 2702, 11, 3103, 849, 3825, 1848, 947, 3125, 1901, -+ 2494, 600, 2017, 2658, 293, 2207, 2851, 9, 1799, 3186, 510, 2077, 3318, 102, 3196, 1571, 3982, 357, 1781, 3717, 2774, 1176, 1834, 4001, 908, 2044, 3195, 986, 1675, 3696, 1339, 2638, 1617, 3026, 96, 1984, 940, 2446, 1563, 2876, 930, 2532, 3426, 1516, 2407, 1134, 3801, 1931, 2307, 521, 2744, 1883, 138, 3356, 597, 1758, 2343, 1389, 2831, 2145, 693, 3485, 2286, 520, -+ 3031, 1601, 3710, 956, 4067, 1849, 1097, 3760, 2406, 1215, 3861, 1596, 846, 3804, 1890, 516, 2295, 3062, 747, 2337, 169, 3178, 603, 2269, 3104, 1537, 627, 3537, 2415, 786, 2988, 379, 4040, 839, 2554, 3561, 1363, 4005, 745, 2128, 3817, 1348, 617, 3910, 397, 3050, 598, 2787, 1037, 3932, 1277, 3741, 2091, 1073, 2503, 3530, 934, 4024, 352, 1610, 2969, 158, 1347, 3992, -+ 1155, 3348, 142, 2259, 3087, 500, 3380, 2096, 730, 2795, 210, 3005, 2335, 1173, 2627, 3703, 1049, 2038, 3514, 983, 3868, 1653, 3552, 1249, 74, 3891, 2586, 1452, 238, 3936, 1738, 2168, 1209, 3384, 1847, 593, 3233, 355, 3036, 1753, 63, 3250, 2150, 1732, 2613, 1259, 3629, 1483, 3120, 280, 2382, 663, 2641, 3176, 1637, 265, 3013, 1239, 2420, 3416, 1088, 3769, 1938, 2555, -+ 347, 2049, 2809, 1443, 761, 2628, 1693, 277, 3975, 1496, 3523, 1961, 547, 3106, 287, 1492, 3340, 24, 1547, 2887, 2147, 370, 2535, 1880, 2962, 2121, 479, 3077, 1922, 2618, 966, 3253, 2439, 327, 2847, 1515, 2226, 2713, 962, 3632, 2465, 1039, 2854, 245, 3179, 2080, 124, 2525, 792, 3486, 1744, 3289, 1404, 476, 3782, 2186, 715, 3579, 1971, 626, 2784, 2201, 741, 3248, -+ 1640, 3551, 1024, 3840, 1827, 3622, 1072, 3238, 2279, 835, 2562, 1295, 4085, 1816, 3535, 2495, 724, 2664, 4042, 570, 1281, 3422, 1013, 3787, 783, 1343, 3722, 1123, 3427, 599, 3634, 27, 1572, 3827, 1014, 3665, 139, 1868, 3197, 1390, 640, 4090, 1459, 3714, 902, 3421, 1676, 4004, 2246, 1128, 2720, 60, 4069, 2002, 1035, 2818, 1352, 2552, 88, 3847, 1801, 309, 3627, 1104, -+ 2894, 686, 2509, 403, 2926, 95, 1991, 2868, 469, 2052, 3370, 66, 2399, 679, 1248, 2081, 3181, 1100, 2224, 1870, 3001, 1506, 2760, 260, 3294, 2707, 2027, 146, 2355, 1323, 2783, 1956, 2946, 676, 2000, 3053, 1325, 3893, 424, 2084, 2998, 1797, 466, 2380, 1875, 507, 2939, 1054, 396, 3700, 1502, 3007, 904, 2418, 3443, 200, 3954, 1588, 3283, 1065, 3084, 1471, 2714, 2270, -+ 34, 4029, 1869, 3446, 1207, 2442, 3919, 879, 1788, 3726, 1115, 3129, 1466, 2742, 3897, 214, 1750, 3763, 405, 3459, 123, 3916, 812, 2317, 1685, 533, 3389, 1589, 3908, 1844, 376, 3990, 1158, 3437, 2377, 458, 2645, 896, 2336, 3396, 193, 2581, 3539, 1083, 2756, 3871, 1426, 2135, 3166, 1824, 566, 2104, 3559, 413, 1814, 2922, 2122, 797, 2750, 2258, 670, 3944, 869, 1729, -+ 3183, 1409, 916, 2220, 3100, 568, 1427, 3351, 2601, 336, 2803, 778, 3656, 432, 2170, 3330, 944, 2302, 2856, 970, 2416, 1766, 3249, 1218, 4066, 2438, 993, 2635, 697, 3021, 2152, 830, 2608, 234, 1421, 4051, 1705, 3577, 1507, 791, 3807, 958, 2051, 3148, 4, 2256, 712, 3529, 179, 2536, 3880, 989, 2655, 1302, 3267, 562, 1210, 3517, 303, 1950, 3393, 168, 2125, 3749, -+ 502, 2745, 3648, 256, 1620, 3684, 2240, 173, 1238, 3999, 2216, 1704, 2039, 2886, 1213, 1889, 2980, 665, 1585, 3715, 1333, 2662, 446, 3011, 41, 1906, 3772, 306, 3509, 1241, 3339, 1645, 3692, 2209, 3121, 607, 2833, 47, 3185, 2507, 1291, 2859, 400, 1580, 3675, 1328, 2676, 1658, 2857, 1183, 1965, 3190, 149, 3972, 1573, 2221, 3832, 1706, 3037, 1290, 2534, 1647, 2923, 1161, -+ 2452, 1942, 809, 3321, 2139, 1022, 2842, 1887, 3074, 1528, 536, 3475, 188, 3837, 752, 3573, 79, 4018, 2141, 285, 3354, 738, 3680, 2173, 1473, 2927, 1144, 2816, 877, 2368, 91, 2727, 635, 1253, 1888, 3513, 974, 2280, 1990, 488, 3326, 1948, 4007, 2153, 660, 3314, 302, 4039, 784, 3626, 445, 2327, 1674, 2513, 827, 3099, 26, 2464, 749, 4095, 912, 3704, 556, 3495, -+ 225, 3962, 1567, 2550, 713, 4053, 371, 3436, 796, 2541, 3169, 1174, 2428, 1414, 2609, 1628, 2753, 1263, 3206, 1951, 1129, 2885, 1740, 911, 3376, 672, 3603, 1616, 2015, 3873, 1477, 3543, 2087, 3846, 171, 2549, 1612, 3730, 1157, 3923, 1650, 151, 1136, 3033, 2466, 996, 2931, 1450, 2391, 1763, 3362, 883, 3678, 333, 3496, 1422, 2730, 1084, 3225, 375, 2780, 1480, 2354, 1882, -+ 2961, 1028, 2814, 80, 3154, 1720, 2463, 1444, 3733, 23, 1666, 3917, 611, 3398, 388, 3235, 696, 2344, 425, 2580, 3839, 154, 2266, 3957, 381, 2056, 2476, 196, 3180, 527, 3009, 1044, 383, 2347, 2973, 781, 3227, 342, 2766, 654, 2967, 2101, 3546, 457, 1534, 3732, 1917, 616, 3134, 52, 2174, 2981, 1169, 2813, 2116, 541, 3781, 2156, 1448, 3578, 2199, 87, 3359, 1313, -+ 618, 3424, 1397, 3818, 2098, 1095, 2943, 961, 2316, 1959, 2975, 1026, 2724, 1768, 2155, 1153, 3945, 1751, 3612, 814, 1551, 3304, 1178, 2764, 1643, 3136, 1081, 3981, 2213, 1310, 2587, 1826, 3369, 1533, 1092, 3953, 1296, 2433, 1833, 3598, 1023, 2543, 1309, 3187, 2043, 125, 2519, 3528, 1324, 3757, 1511, 492, 4057, 1910, 994, 3200, 1777, 212, 2960, 702, 1811, 3122, 943, 3925, -+ 2611, 2046, 477, 2397, 650, 3541, 235, 3864, 632, 3342, 423, 2234, 3592, 109, 3758, 2933, 239, 2790, 1051, 2985, 2113, 630, 2515, 257, 3778, 843, 2708, 1549, 653, 3521, 233, 4058, 748, 3086, 2231, 484, 2062, 3075, 115, 1501, 3287, 334, 3885, 856, 2763, 3971, 1195, 414, 2822, 681, 2700, 1830, 2422, 112, 3556, 2267, 901, 3983, 2373, 1217, 3770, 454, 2481, 1845, -+ 266, 3662, 1654, 3208, 1287, 1934, 3060, 1807, 2648, 1395, 4074, 828, 1531, 2640, 1350, 872, 2454, 1512, 3499, 8, 4092, 1762, 3540, 1434, 2146, 3286, 71, 3683, 1902, 2421, 1385, 2719, 1972, 13, 3660, 1688, 3450, 1001, 4077, 2328, 907, 2913, 1690, 2353, 545, 1485, 2991, 2134, 1728, 3948, 938, 3353, 1298, 2891, 1592, 387, 3029, 1896, 524, 3378, 2092, 1560, 2972, 1089, -+ 3150, 882, 2672, 183, 3693, 2572, 506, 1109, 3218, 164, 2467, 1930, 3175, 706, 3480, 2111, 3831, 584, 2211, 2679, 1292, 2819, 442, 2935, 601, 1790, 2496, 1041, 2906, 435, 3230, 880, 3780, 2512, 909, 2770, 301, 2657, 1914, 508, 3754, 2079, 39, 3698, 1879, 3455, 800, 3322, 159, 2225, 3046, 304, 3621, 615, 3870, 2567, 1077, 3651, 1484, 2749, 190, 4008, 606, 3564, -+ 2203, 1410, 4046, 1988, 837, 1468, 3978, 2260, 1638, 3764, 929, 3547, 322, 1819, 2855, 394, 1416, 3006, 1702, 785, 3262, 960, 2249, 3624, 1224, 4023, 790, 3432, 1254, 3939, 1621, 2283, 531, 1519, 3394, 1258, 3819, 756, 3244, 1609, 2583, 1294, 3141, 1052, 2674, 261, 2427, 1553, 3653, 1165, 1962, 2606, 1040, 2320, 1937, 1284, 3160, 56, 2237, 920, 3194, 1372, 2401, 1952, -+ 0, 2901, 689, 2338, 3352, 2840, 73, 3405, 739, 2054, 2959, 1377, 2202, 3941, 1067, 2021, 3306, 167, 3905, 2042, 307, 3792, 1860, 144, 2615, 1978, 3064, 278, 1945, 2383, 119, 3544, 1874, 3131, 203, 2187, 1767, 2462, 1229, 3585, 364, 2798, 683, 3503, 1412, 4049, 921, 2762, 447, 3144, 733, 3797, 1489, 2986, 231, 3474, 780, 2793, 3935, 1670, 2526, 367, 3315, 841, -+ 3855, 1734, 3489, 305, 1240, 1836, 2195, 1011, 3078, 390, 2556, 642, 3209, 44, 2743, 3679, 917, 2695, 1133, 3400, 2436, 1098, 3056, 1415, 3277, 487, 1568, 2643, 3670, 925, 3101, 1034, 2747, 1167, 4030, 2848, 580, 3094, 99, 2287, 1031, 3989, 1968, 2379, 514, 2053, 3092, 1234, 3894, 1623, 2472, 14, 3259, 822, 3968, 2248, 1401, 2040, 449, 3269, 766, 3706, 1603, 2944, -+ 1250, 2650, 1015, 2537, 3943, 579, 3630, 2593, 1274, 3467, 1583, 3829, 1162, 2471, 1543, 553, 2365, 1613, 3072, 677, 1748, 2752, 528, 3929, 906, 2321, 3810, 1288, 628, 2829, 2094, 3852, 401, 2392, 773, 1591, 3468, 1424, 3881, 1789, 3331, 1520, 172, 3220, 1636, 3596, 89, 1924, 2284, 1003, 3435, 1739, 2124, 2778, 1806, 517, 2621, 3403, 1205, 1829, 2869, 1062, 2293, 244, -+ 3608, 431, 3246, 1379, 2123, 2937, 1532, 296, 3922, 1865, 177, 2143, 2974, 427, 4011, 1912, 3576, 326, 2109, 4031, 75, 3655, 2206, 1541, 2048, 3401, 33, 2161, 3364, 1476, 254, 1691, 3337, 1375, 3605, 2055, 362, 2738, 716, 2634, 450, 2212, 3777, 1187, 2870, 863, 2485, 3363, 337, 3008, 634, 4063, 452, 1268, 3313, 1112, 3727, 253, 2228, 3798, 103, 1974, 4075, 1406, -+ 2430, 2061, 776, 3720, 152, 1114, 3293, 2325, 840, 2660, 3272, 988, 1725, 3366, 1305, 3020, 968, 3228, 799, 2544, 1840, 1016, 3170, 259, 2873, 777, 1838, 3142, 455, 3985, 2010, 2993, 646, 2689, 45, 2547, 3745, 1137, 3212, 1317, 3023, 825, 2566, 410, 2127, 3931, 1538, 775, 3812, 1785, 2757, 1368, 2542, 3584, 127, 3041, 2011, 1548, 2940, 723, 2490, 3307, 530, 2789, -+ 948, 3123, 1579, 2777, 2035, 3848, 542, 1946, 3057, 1433, 558, 3731, 2600, 755, 2326, 108, 2785, 1380, 3750, 1276, 3451, 2063, 737, 3567, 1247, 4062, 2671, 884, 2411, 1126, 2588, 952, 3794, 1858, 3161, 924, 1804, 2333, 218, 3974, 1679, 3456, 1394, 3572, 1757, 211, 3205, 2659, 1242, 2346, 176, 3140, 850, 2188, 1716, 2460, 560, 4019, 997, 3522, 1735, 1105, 3048, 1661, -+ 3773, 61, 3548, 609, 1273, 2553, 1682, 3609, 25, 4056, 1898, 2233, 224, 3604, 1107, 3802, 1673, 2410, 246, 2849, 459, 3066, 2578, 1625, 2425, 368, 1463, 3734, 1671, 3510, 107, 3257, 1341, 460, 2239, 3947, 550, 3441, 1993, 971, 2408, 20, 2765, 1061, 2952, 2292, 1371, 434, 3642, 972, 3460, 1659, 3736, 330, 3904, 888, 3276, 1362, 2735, 356, 2281, 3901, 227, 2171, -+ 805, 2528, 1774, 2183, 3165, 267, 2860, 1008, 2461, 1285, 2834, 935, 3081, 1509, 2694, 2073, 671, 3168, 1939, 1141, 3969, 1429, 133, 3815, 973, 3231, 2085, 201, 2918, 698, 2781, 1644, 2311, 3387, 1057, 1561, 2821, 1216, 2599, 3355, 701, 3791, 1892, 481, 4091, 651, 3310, 2191, 1700, 2899, 707, 2448, 1312, 2668, 1454, 2792, 2107, 36, 2030, 3234, 1465, 865, 2597, 3484, -+ 1518, 4000, 429, 3415, 870, 3949, 1503, 3492, 721, 3372, 361, 3789, 1831, 529, 3487, 320, 4081, 1012, 3607, 2250, 629, 2169, 3347, 1976, 2997, 722, 3620, 2351, 1200, 3889, 2144, 810, 4082, 236, 2023, 3515, 117, 3709, 444, 1835, 2845, 1299, 3198, 2140, 1510, 2546, 887, 3857, 49, 2009, 3994, 404, 3035, 1048, 3410, 461, 3668, 1618, 3828, 590, 2807, 3613, 1354, 620, -+ 3157, 1152, 2867, 1297, 2711, 2265, 490, 2131, 2955, 1712, 2350, 1214, 3203, 2179, 1069, 2577, 1857, 2924, 17, 2699, 1692, 2950, 1197, 485, 1582, 2740, 1407, 544, 3278, 1784, 382, 2941, 1208, 2510, 3063, 844, 2722, 2215, 1595, 4026, 226, 2370, 743, 3681, 145, 3465, 2068, 2782, 1392, 3153, 1006, 2255, 3638, 105, 1821, 2517, 813, 2920, 1189, 2409, 1967, 122, 3058, 2067, -+ 2403, 252, 1980, 3686, 116, 1652, 3746, 1337, 204, 3970, 669, 2715, 82, 3895, 1635, 3409, 763, 1526, 3502, 967, 3719, 268, 3900, 2393, 3558, 62, 3991, 1973, 2540, 987, 3716, 1909, 3327, 554, 1615, 3761, 1366, 595, 3300, 876, 3116, 1138, 2893, 1342, 2678, 1754, 378, 1079, 3563, 525, 2733, 1853, 1143, 2112, 4073, 1228, 3360, 1904, 377, 3391, 1042, 4050, 1721, 478, -+ 3860, 1624, 3270, 936, 2088, 2929, 610, 3145, 2444, 1486, 3534, 2007, 2996, 808, 2402, 199, 2828, 2100, 505, 3127, 1435, 2558, 2003, 613, 1852, 2633, 1117, 3164, 271, 3476, 2271, 3, 1469, 3853, 2362, 340, 2898, 1878, 2570, 1462, 2166, 3872, 335, 3367, 639, 3988, 2964, 1908, 2374, 1577, 3835, 281, 3481, 2839, 582, 3018, 187, 2276, 3928, 1597, 2652, 831, 2557, 3425, -+ 1119, 2836, 561, 2514, 4088, 1064, 3458, 1957, 886, 2841, 341, 1101, 1683, 3236, 1365, 3617, 1033, 3921, 2447, 1846, 750, 3402, 1087, 3065, 1308, 3439, 705, 1752, 2872, 1374, 848, 3207, 2637, 1030, 2065, 3462, 910, 3911, 57, 3623, 534, 1894, 2559, 1611, 2297, 1413, 746, 3783, 175, 3211, 905, 2527, 754, 1464, 2369, 1665, 3751, 1396, 652, 3040, 272, 3266, 1307, 2102, -+ 15, 2274, 3526, 1432, 350, 1795, 2565, 48, 3883, 1269, 3411, 2136, 4027, 310, 2626, 645, 3113, 1311, 290, 3784, 2680, 113, 2268, 4068, 339, 1947, 2468, 3830, 526, 2078, 3950, 1711, 636, 3049, 166, 1731, 3108, 1184, 1999, 2669, 1349, 3500, 890, 3711, 78, 3290, 2502, 1201, 2853, 2184, 1357, 3303, 1926, 3884, 313, 2675, 789, 3171, 2437, 1265, 3718, 1920, 608, 2951, -+ 3766, 1569, 857, 2897, 2118, 3645, 762, 3182, 1629, 2360, 703, 2900, 954, 1876, 3759, 1488, 2289, 1911, 2956, 981, 1664, 3644, 918, 1562, 2904, 3661, 147, 1475, 3311, 2649, 230, 2245, 3636, 1386, 4022, 2603, 509, 2376, 3345, 847, 3059, 208, 2866, 1186, 2646, 1703, 366, 3392, 1823, 540, 4017, 6, 2987, 991, 3375, 1159, 3601, 2066, 68, 2772, 767, 2322, 3587, 1399, -+ 519, 2181, 3879, 161, 3229, 1149, 2032, 2656, 417, 3767, 2018, 134, 3549, 2223, 552, 3284, 59, 3987, 589, 3444, 2339, 422, 2805, 2151, 563, 1196, 3199, 2345, 874, 1300, 3531, 1142, 2746, 372, 2182, 821, 3744, 1631, 269, 4070, 1587, 2405, 1782, 3887, 674, 3560, 2071, 942, 3669, 1513, 2571, 2089, 691, 2453, 1877, 2874, 468, 1717, 3525, 1430, 3960, 1626, 207, 2734, -+ 1832, 3000, 1203, 2585, 1749, 463, 3986, 1355, 3349, 975, 3054, 1604, 2607, 1182, 2938, 1698, 2574, 1227, 2794, 2069, 1146, 3260, 1316, 3876, 1794, 2681, 1996, 473, 3993, 1936, 3032, 567, 2001, 3397, 1478, 3252, 1148, 2954, 1929, 2272, 623, 3167, 420, 2158, 2930, 1121, 3085, 2441, 221, 2892, 1082, 3610, 1602, 3803, 157, 1523, 4044, 2285, 1043, 2912, 456, 2516, 3454, 978, -+ 4037, 315, 3361, 622, 3691, 2194, 2984, 189, 1815, 2530, 497, 3271, 740, 3859, 270, 3671, 834, 3511, 1771, 186, 3743, 718, 3015, 29, 3373, 819, 3762, 1578, 2755, 77, 2414, 1634, 3915, 881, 2826, 94, 2560, 467, 3520, 1260, 3724, 1360, 3473, 1498, 163, 4009, 555, 1851, 3800, 787, 3251, 299, 3039, 1232, 3268, 2229, 662, 3002, 242, 1899, 3295, 1198, 1989, 3159, -+ 709, 2443, 2041, 1525, 2666, 1275, 859, 2090, 3557, 1116, 4054, 1437, 2404, 1944, 2810, 1068, 2352, 385, 3156, 2450, 1472, 2639, 1710, 2366, 1140, 2884, 262, 3239, 964, 3690, 807, 3135, 251, 2384, 1699, 3865, 1318, 3098, 779, 2486, 18, 2631, 914, 2799, 1919, 2364, 1566, 3334, 1255, 2304, 1656, 2688, 2047, 574, 2653, 1091, 3408, 1332, 3844, 2445, 631, 3737, 93, 2290, -+ 1646, 3672, 1046, 3508, 70, 3886, 2419, 3213, 346, 2815, 2138, 5, 3430, 614, 1479, 3374, 1651, 4064, 1353, 771, 3888, 344, 3545, 667, 4035, 1859, 2497, 1320, 2300, 1765, 2632, 1436, 3658, 1118, 3350, 731, 2315, 1843, 3956, 1010, 3316, 2082, 3918, 472, 3640, 744, 2690, 65, 2823, 428, 4078, 854, 3570, 1458, 3952, 354, 2014, 2624, 836, 1497, 3042, 1709, 2771, 1103, -+ 2990, 228, 2862, 811, 3189, 1736, 512, 1482, 3809, 710, 1773, 3034, 1346, 3951, 2291, 141, 2890, 585, 2696, 2022, 2910, 1055, 2197, 3139, 1382, 489, 3635, 621, 3461, 220, 4080, 546, 1881, 2958, 412, 1998, 3588, 184, 1455, 2761, 1605, 717, 1778, 3188, 1170, 3030, 1391, 3862, 1905, 3423, 1063, 2505, 101, 1932, 2429, 1267, 3701, 37, 3488, 2083, 294, 4013, 803, 3470, -+ 1387, 3907, 1793, 2324, 1244, 2800, 2006, 3068, 980, 2385, 3628, 1050, 2729, 380, 1798, 3739, 928, 2232, 3413, 81, 1669, 3329, 1524, 216, 2703, 2097, 2936, 1639, 2045, 2712, 1344, 2167, 3494, 1019, 2458, 3158, 1168, 2592, 3448, 440, 3788, 2945, 202, 2474, 1995, 321, 3501, 1018, 577, 2176, 3083, 1373, 2865, 3344, 513, 3093, 1600, 2832, 1099, 3143, 2303, 1025, 2622, 363, -+ 2263, 668, 2717, 395, 4071, 659, 3673, 137, 2682, 1660, 275, 3210, 824, 2423, 3308, 1270, 3095, 1856, 1221, 3652, 2529, 576, 3961, 1895, 3735, 1124, 90, 3890, 941, 3255, 817, 2881, 32, 2731, 1715, 312, 4047, 649, 1986, 2358, 1246, 1927, 3574, 838, 4048, 2341, 1722, 2610, 3247, 1556, 276, 3677, 643, 1164, 3806, 2261, 774, 1903, 3913, 641, 1461, 3282, 1769, 3657, -+ 1614, 3325, 1175, 3133, 1565, 2483, 1113, 3297, 1319, 4003, 2241, 1236, 3838, 1606, 655, 2751, 248, 3920, 464, 2149, 950, 3045, 1261, 2825, 736, 2432, 3358, 1442, 2511, 323, 3725, 1527, 3940, 862, 3602, 2257, 1581, 2797, 998, 3147, 284, 2705, 1045, 2889, 1504, 648, 3073, 185, 1243, 3902, 2310, 1746, 2117, 2710, 1521, 180, 3516, 2647, 318, 2489, 3682, 143, 2908, 732, -+ 2508, 22, 3822, 1954, 222, 3483, 2137, 474, 2902, 588, 3114, 2034, 114, 2882, 3666, 1822, 1059, 2323, 3216, 1329, 3805, 155, 2298, 402, 3128, 1540, 2177, 656, 3061, 1800, 2313, 523, 1915, 3089, 1376, 694, 3281, 83, 3688, 1727, 3966, 1451, 3265, 50, 2064, 3697, 1335, 3449, 2028, 758, 2791, 949, 3996, 351, 3241, 2172, 1805, 995, 3079, 1131, 1872, 2389, 1220, 3973, -+ 1336, 2838, 931, 2361, 2992, 788, 1714, 3878, 2208, 1842, 976, 3532, 1358, 2103, 475, 2230, 3491, 1558, 734, 2817, 1741, 3431, 1384, 3705, 899, 3565, 274, 3997, 1166, 3538, 922, 3390, 2614, 209, 2390, 3877, 1188, 3010, 2157, 801, 2500, 522, 2218, 3849, 2539, 470, 2723, 897, 2473, 3614, 21, 3386, 1447, 3016, 895, 3874, 504, 3619, 1542, 4089, 692, 3440, 2057, 493, -+ 3245, 1759, 3615, 543, 1491, 3768, 2576, 1266, 46, 3643, 2545, 353, 2661, 4094, 1135, 2932, 38, 2564, 4010, 286, 2386, 802, 2684, 1770, 2522, 1321, 2914, 1689, 2673, 121, 2888, 1755, 1212, 3466, 1992, 462, 2605, 1864, 360, 3299, 1219, 3527, 1667, 685, 1185, 3223, 1966, 4006, 418, 1594, 3112, 2253, 591, 1900, 2449, 1364, 2864, 1970, 67, 2254, 2827, 329, 2971, 1058, -+ 2296, 283, 2617, 1873, 3152, 1120, 389, 3263, 2725, 1552, 726, 3226, 1686, 604, 3280, 1500, 3695, 999, 2025, 3192, 1078, 2979, 451, 4061, 10, 3221, 753, 2331, 984, 3842, 2160, 407, 4021, 878, 2966, 1545, 3536, 945, 3813, 1599, 2748, 178, 3118, 2008, 3631, 1608, 136, 1419, 2934, 2189, 682, 1326, 3729, 2736, 131, 3420, 818, 2521, 3320, 898, 1668, 3841, 1431, 3713, -+ 1536, 3406, 1007, 4034, 128, 2244, 3575, 2016, 951, 3930, 2299, 1020, 3748, 2435, 1925, 324, 2200, 3043, 571, 1775, 3785, 1456, 3275, 1151, 2165, 1803, 3793, 316, 3291, 1923, 1090, 3076, 2426, 1841, 612, 3201, 160, 2278, 2830, 549, 2132, 4093, 867, 2591, 365, 2769, 2114, 3553, 1004, 3821, 1828, 3336, 338, 1607, 4041, 1202, 3067, 419, 1327, 3583, 2190, 793, 2677, 100, -+ 2480, 764, 2921, 2133, 1282, 2801, 1388, 657, 3173, 279, 1820, 2965, 132, 1231, 2812, 3938, 861, 1440, 3590, 2663, 120, 2282, 675, 2620, 3554, 969, 2488, 1598, 2824, 495, 3641, 1505, 54, 3771, 2243, 1381, 3977, 1960, 1279, 3569, 1036, 1786, 2994, 1378, 3906, 1074, 3343, 572, 2518, 206, 2877, 868, 2413, 3155, 581, 2308, 1697, 3808, 2024, 2718, 240, 3202, 1233, 3497, -+ 1718, 3863, 406, 1632, 3381, 511, 3963, 2440, 1470, 2619, 3341, 1315, 2217, 3593, 557, 1760, 3324, 2501, 408, 1314, 3479, 1708, 3896, 1554, 247, 3017, 638, 3418, 1334, 2455, 816, 3377, 2142, 1029, 2878, 437, 2551, 687, 2957, 7, 2491, 3332, 273, 2334, 782, 2968, 1783, 1278, 3124, 2074, 1490, 3942, 2004, 1066, 1907, 3568, 191, 2796, 605, 1122, 3995, 1850, 2273, 695, -+ 3130, 1156, 2356, 3728, 915, 3105, 2059, 170, 3753, 1080, 503, 4016, 804, 3115, 1361, 2693, 86, 1837, 3854, 2349, 769, 2846, 393, 3117, 2072, 1257, 3867, 2031, 135, 4084, 1958, 2709, 708, 3243, 1570, 3708, 1130, 3419, 1695, 3858, 1508, 658, 3786, 1707, 3472, 69, 2434, 4052, 421, 3599, 664, 2573, 53, 3382, 2642, 957, 3193, 1499, 2238, 3024, 1559, 494, 3689, 2584, -+}; -Index: jellyfin-ffmpeg/libavfilter/vf_scale_cuda.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_scale_cuda.c -+++ jellyfin-ffmpeg/libavfilter/vf_scale_cuda.c -@@ -1,5 +1,8 @@ - /* - * Copyright (c) 2017, NVIDIA CORPORATION. All rights reserved. -+* Copyright (c) 2019 rcombs -+* -+* This file is part of FFmpeg. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the "Software"), -@@ -20,10 +23,10 @@ - * DEALINGS IN THE SOFTWARE. - */ - --#include - #include - #include - -+#include "libavutil/avassert.h" - #include "libavutil/avstring.h" - #include "libavutil/common.h" - #include "libavutil/hwcontext.h" -@@ -34,13 +37,12 @@ - #include "libavutil/pixdesc.h" - - #include "avfilter.h" -+#include "dither_matrix.h" - #include "formats.h" - #include "internal.h" - #include "scale_eval.h" - #include "video.h" - --#include "vf_scale_cuda.h" -- - static const enum AVPixelFormat supported_formats[] = { - AV_PIX_FMT_YUV420P, - AV_PIX_FMT_NV12, -@@ -48,8 +50,6 @@ static const enum AVPixelFormat supporte - AV_PIX_FMT_P010, - AV_PIX_FMT_P016, - AV_PIX_FMT_YUV444P16, -- AV_PIX_FMT_0RGB32, -- AV_PIX_FMT_0BGR32, - }; - - #define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) ) -@@ -58,17 +58,6 @@ static const enum AVPixelFormat supporte - - #define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x) - --enum { -- INTERP_ALGO_DEFAULT, -- -- INTERP_ALGO_NEAREST, -- INTERP_ALGO_BILINEAR, -- INTERP_ALGO_BICUBIC, -- INTERP_ALGO_LANCZOS, -- -- INTERP_ALGO_COUNT --}; -- - typedef struct CUDAScaleContext { - const AVClass *class; - -@@ -87,6 +76,7 @@ typedef struct CUDAScaleContext { - * Output sw format. AV_PIX_FMT_NONE for no conversion. - */ - enum AVPixelFormat format; -+ char *format_str; - - char *w_expr; ///< width expression string - char *h_expr; ///< height expression string -@@ -96,30 +86,56 @@ typedef struct CUDAScaleContext { - - CUcontext cu_ctx; - CUmodule cu_module; -- CUfunction cu_func_uchar; -- CUfunction cu_func_uchar2; -- CUfunction cu_func_uchar4; -- CUfunction cu_func_ushort; -- CUfunction cu_func_ushort2; -- CUfunction cu_func_ushort4; -+ -+#define VARIANT(NAME) \ -+ CUfunction cu_func_ ## NAME; -+#define VARIANTSET(NAME) \ -+ VARIANT(NAME) \ -+ VARIANT(NAME ## _c) \ -+ VARIANT(NAME ## _p2) \ -+ VARIANT(NAME ## _2) \ -+ VARIANT(NAME ## _2_u) \ -+ VARIANT(NAME ## _2_v) \ -+ VARIANT(NAME ## _4) -+ -+ VARIANTSET(8_8) -+ VARIANTSET(16_16) -+ VARIANTSET(8_16) -+ VARIANTSET(16_8) -+#undef VARIANTSET -+#undef VARIANT -+ -+ CUfunction cu_func_luma; -+ CUfunction cu_func_chroma_u; -+ CUfunction cu_func_chroma_v; -+ - CUstream cu_stream; - - CUdeviceptr srcBuffer; - CUdeviceptr dstBuffer; - int tex_alignment; - -- int interp_algo; -- int interp_use_linear; -- int interp_as_integer; -+ const AVPixFmtDescriptor *in_desc, *out_desc; -+ int in_planes, out_planes; - -- float param; -+ CUdeviceptr ditherBuffer; -+ CUtexObject ditherTex; - } CUDAScaleContext; - - static av_cold int cudascale_init(AVFilterContext *ctx) - { - CUDAScaleContext *s = ctx->priv; - -- s->format = AV_PIX_FMT_NONE; -+ if (!strcmp(s->format_str, "same")) { -+ s->format = AV_PIX_FMT_NONE; -+ } else { -+ s->format = av_get_pix_fmt(s->format_str); -+ if (s->format == AV_PIX_FMT_NONE) { -+ av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", s->format_str); -+ return AVERROR(EINVAL); -+ } -+ } -+ - s->frame = av_frame_alloc(); - if (!s->frame) - return AVERROR(ENOMEM); -@@ -135,13 +151,22 @@ static av_cold void cudascale_uninit(AVF - { - CUDAScaleContext *s = ctx->priv; - -- if (s->hwctx && s->cu_module) { -+ if (s->hwctx) { - CudaFunctions *cu = s->hwctx->internal->cuda_dl; -- CUcontext dummy; -+ CUcontext dummy, cuda_ctx = s->hwctx->cuda_ctx; -+ -+ CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); -+ -+ if (s->ditherTex) { -+ CHECK_CU(cu->cuTexObjectDestroy(s->ditherTex)); -+ s->ditherTex = 0; -+ } -+ -+ if (s->ditherBuffer) { -+ CHECK_CU(cu->cuMemFree(s->ditherBuffer)); -+ s->ditherBuffer = 0; -+ } - -- CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx)); -- CHECK_CU(cu->cuModuleUnload(s->cu_module)); -- s->cu_module = NULL; - CHECK_CU(cu->cuCtxPopCurrent(&dummy)); - } - -@@ -262,6 +287,63 @@ static av_cold int init_processing_chain - return 0; - } - -+static av_cold int cudascale_setup_dither(AVFilterContext *ctx) -+{ -+ CUDAScaleContext *s = ctx->priv; -+ AVFilterLink *inlink = ctx->inputs[0]; -+ AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; -+ AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; -+ CudaFunctions *cu = device_hwctx->internal->cuda_dl; -+ CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; -+ int ret = 0; -+ -+ CUDA_MEMCPY2D cpy = { -+ .srcMemoryType = CU_MEMORYTYPE_HOST, -+ .dstMemoryType = CU_MEMORYTYPE_DEVICE, -+ .srcHost = ff_fruit_dither_matrix, -+ .dstDevice = 0, -+ .srcPitch = ff_fruit_dither_size * sizeof(ff_fruit_dither_matrix[0]), -+ .dstPitch = ff_fruit_dither_size * sizeof(ff_fruit_dither_matrix[0]), -+ .WidthInBytes = ff_fruit_dither_size * sizeof(ff_fruit_dither_matrix[0]), -+ .Height = ff_fruit_dither_size, -+ }; -+ -+ CUDA_TEXTURE_DESC tex_desc = { -+ .filterMode = CU_TR_FILTER_MODE_POINT, -+ .flags = CU_TRSF_READ_AS_INTEGER, -+ }; -+ -+ CUDA_RESOURCE_DESC res_desc = { -+ .resType = CU_RESOURCE_TYPE_PITCH2D, -+ .res.pitch2D.format = CU_AD_FORMAT_UNSIGNED_INT16, -+ .res.pitch2D.numChannels = 1, -+ .res.pitch2D.width = ff_fruit_dither_size, -+ .res.pitch2D.height = ff_fruit_dither_size, -+ .res.pitch2D.pitchInBytes = ff_fruit_dither_size * sizeof(ff_fruit_dither_matrix[0]), -+ .res.pitch2D.devPtr = 0, -+ }; -+ -+ av_assert0(sizeof(ff_fruit_dither_matrix) == sizeof(ff_fruit_dither_matrix[0]) * ff_fruit_dither_size * ff_fruit_dither_size); -+ -+ if ((ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx))) < 0) -+ return ret; -+ -+ if ((ret = CHECK_CU(cu->cuMemAlloc(&s->ditherBuffer, sizeof(ff_fruit_dither_matrix)))) < 0) -+ goto fail; -+ -+ res_desc.res.pitch2D.devPtr = cpy.dstDevice = s->ditherBuffer; -+ -+ if ((ret = CHECK_CU(cu->cuMemcpy2D(&cpy))) < 0) -+ goto fail; -+ -+ if ((ret = CHECK_CU(cu->cuTexObjectCreate(&s->ditherTex, &res_desc, &tex_desc, NULL))) < 0) -+ goto fail; -+ -+fail: -+ CHECK_CU(cu->cuCtxPopCurrent(&dummy)); -+ return ret; -+} -+ - static av_cold int cudascale_config_props(AVFilterLink *outlink) - { - AVFilterContext *ctx = outlink->src; -@@ -271,46 +353,11 @@ static av_cold int cudascale_config_prop - AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; - CUcontext dummy, cuda_ctx = device_hwctx->cuda_ctx; - CudaFunctions *cu = device_hwctx->internal->cuda_dl; -- char buf[64]; - int w, h; -+ int i; - int ret; - -- char *scaler_ptx; -- const char *function_infix = ""; -- - extern char vf_scale_cuda_ptx[]; -- extern char vf_scale_cuda_bicubic_ptx[]; -- -- switch(s->interp_algo) { -- case INTERP_ALGO_NEAREST: -- scaler_ptx = vf_scale_cuda_ptx; -- function_infix = "_Nearest"; -- s->interp_use_linear = 0; -- s->interp_as_integer = 1; -- break; -- case INTERP_ALGO_BILINEAR: -- scaler_ptx = vf_scale_cuda_ptx; -- function_infix = "_Bilinear"; -- s->interp_use_linear = 1; -- s->interp_as_integer = 1; -- break; -- case INTERP_ALGO_DEFAULT: -- case INTERP_ALGO_BICUBIC: -- scaler_ptx = vf_scale_cuda_bicubic_ptx; -- function_infix = "_Bicubic"; -- s->interp_use_linear = 0; -- s->interp_as_integer = 0; -- break; -- case INTERP_ALGO_LANCZOS: -- scaler_ptx = vf_scale_cuda_bicubic_ptx; -- function_infix = "_Lanczos"; -- s->interp_use_linear = 0; -- s->interp_as_integer = 0; -- break; -- default: -- av_log(ctx, AV_LOG_ERROR, "Unknown interpolation algorithm\n"); -- return AVERROR_BUG; -- } - - s->hwctx = device_hwctx; - s->cu_stream = s->hwctx->stream; -@@ -319,40 +366,30 @@ static av_cold int cudascale_config_prop - if (ret < 0) - goto fail; - -- ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, scaler_ptx)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_uchar", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar, s->cu_module, buf)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_uchar2", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar2, s->cu_module, buf)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_uchar4", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_uchar4, s->cu_module, buf)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_ushort", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort, s->cu_module, buf)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_ushort2", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort2, s->cu_module, buf)); -- if (ret < 0) -- goto fail; -- -- snprintf(buf, sizeof(buf), "Subsample%s_ushort4", function_infix); -- CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ushort4, s->cu_module, buf)); -+ ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, vf_scale_cuda_ptx)); - if (ret < 0) - goto fail; - -+#define VARIANT(NAME) \ -+ CHECK_CU(cu->cuModuleGetFunction(&s->cu_func_ ## NAME, s->cu_module, "Subsample_Bilinear_" #NAME)); \ -+ if (ret < 0) \ -+ goto fail; -+ -+#define VARIANTSET(NAME) \ -+ VARIANT(NAME) \ -+ VARIANT(NAME ## _c) \ -+ VARIANT(NAME ## _2) \ -+ VARIANT(NAME ## _p2) \ -+ VARIANT(NAME ## _2_u) \ -+ VARIANT(NAME ## _2_v) \ -+ VARIANT(NAME ## _4) -+ -+ VARIANTSET(8_8) -+ VARIANTSET(16_16) -+ VARIANTSET(8_16) -+ VARIANTSET(16_8) -+#undef VARIANTSET -+#undef VARIANT - - CHECK_CU(cu->cuCtxPopCurrent(&dummy)); - -@@ -376,6 +413,53 @@ static av_cold int cudascale_config_prop - if (ret < 0) - return ret; - -+ s->in_desc = av_pix_fmt_desc_get(s->in_fmt); -+ s->out_desc = av_pix_fmt_desc_get(s->out_fmt); -+ -+ for (i = 0; i < s->in_desc->nb_components; i++) -+ s->in_planes = FFMAX(s->in_planes, s->in_desc ->comp[i].plane + 1); -+ -+ for (i = 0; i < s->in_desc->nb_components; i++) -+ s->out_planes = FFMAX(s->out_planes, s->out_desc->comp[i].plane + 1); -+ -+#define VARIANT(INDEPTH, OUTDEPTH, SUFFIX) s->cu_func_ ## INDEPTH ## _ ## OUTDEPTH ## SUFFIX -+#define BITS(n) ((n + 7) & ~7) -+#define VARIANTSET(INDEPTH, OUTDEPTH) \ -+ else if (BITS(s->in_desc->comp[0].depth) == INDEPTH && \ -+ BITS(s->out_desc->comp[0].depth) == OUTDEPTH) { \ -+ s->cu_func_luma = VARIANT(INDEPTH, OUTDEPTH,); \ -+ if (s->in_planes == 3 && s->out_planes == 3) { \ -+ s->cu_func_chroma_u = s->cu_func_chroma_v = VARIANT(INDEPTH, OUTDEPTH, _c); \ -+ } else if (s->in_planes == 3 && s->out_planes == 2) { \ -+ s->cu_func_chroma_u = s->cu_func_chroma_v = VARIANT(INDEPTH, OUTDEPTH, _p2); \ -+ } else if (s->in_planes == 2 && s->out_planes == 2) { \ -+ s->cu_func_chroma_u = VARIANT(INDEPTH, OUTDEPTH, _2); \ -+ } else if (s->in_planes == 2 && s->out_planes == 3) { \ -+ s->cu_func_chroma_u = VARIANT(INDEPTH, OUTDEPTH, _2_u); \ -+ s->cu_func_chroma_v = VARIANT(INDEPTH, OUTDEPTH, _2_v); \ -+ } else { \ -+ ret = AVERROR_BUG; \ -+ goto fail; \ -+ } \ -+ } -+ -+ if (0) {} -+ VARIANTSET(8, 8) -+ VARIANTSET(16, 16) -+ VARIANTSET(8, 16) -+ VARIANTSET(16, 8) -+ else { -+ ret = AVERROR_BUG; -+ goto fail; -+ } -+#undef VARIANTSET -+#undef VARIANT -+ -+ if (s->in_desc->comp[0].depth > s->out_desc->comp[0].depth) { -+ if ((ret = cudascale_setup_dither(ctx)) < 0) -+ goto fail; -+ } -+ - av_log(ctx, AV_LOG_VERBOSE, "w:%d h:%d -> w:%d h:%d%s\n", - inlink->w, inlink->h, outlink->w, outlink->h, s->passthrough ? " (passthrough)" : ""); - -@@ -396,21 +480,18 @@ fail: - static int call_resize_kernel(AVFilterContext *ctx, CUfunction func, int channels, - uint8_t *src_dptr, int src_width, int src_height, int src_pitch, - uint8_t *dst_dptr, int dst_width, int dst_height, int dst_pitch, -- int pixel_size, int bit_depth) -+ int pixel_size) - { - CUDAScaleContext *s = ctx->priv; - CudaFunctions *cu = s->hwctx->internal->cuda_dl; - CUdeviceptr dst_devptr = (CUdeviceptr)dst_dptr; - CUtexObject tex = 0; -- void *args_uchar[] = { &tex, &dst_devptr, &dst_width, &dst_height, &dst_pitch, -- &src_width, &src_height, &bit_depth, &s->param }; -+ void *args_uchar[] = { &tex, &dst_devptr, &dst_width, &dst_height, &dst_pitch, &src_width, &src_height, &s->ditherTex }; - int ret; - - CUDA_TEXTURE_DESC tex_desc = { -- .filterMode = s->interp_use_linear ? -- CU_TR_FILTER_MODE_LINEAR : -- CU_TR_FILTER_MODE_POINT, -- .flags = s->interp_as_integer ? CU_TRSF_READ_AS_INTEGER : 0, -+ .filterMode = CU_TR_FILTER_MODE_LINEAR, -+ .flags = CU_TRSF_READ_AS_INTEGER, - }; - - CUDA_RESOURCE_DESC res_desc = { -@@ -425,10 +506,6 @@ static int call_resize_kernel(AVFilterCo - .res.pitch2D.devPtr = (CUdeviceptr)src_dptr, - }; - -- // Handling of channels is done via vector-types in cuda, so their size is implicitly part of the pitch -- // Same for pixel_size, which is represented via datatypes on the cuda side of things. -- dst_pitch /= channels * pixel_size; -- - ret = CHECK_CU(cu->cuTexObjectCreate(&tex, &res_desc, &tex_desc, NULL)); - if (ret < 0) - goto exit; -@@ -447,91 +524,37 @@ exit: - static int scalecuda_resize(AVFilterContext *ctx, - AVFrame *out, AVFrame *in) - { -- AVHWFramesContext *in_frames_ctx = (AVHWFramesContext*)in->hw_frames_ctx->data; - CUDAScaleContext *s = ctx->priv; - -- switch (in_frames_ctx->sw_format) { -- case AV_PIX_FMT_YUV420P: -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 1, 8); -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[1], in->width / 2, in->height / 2, in->linesize[1], -- out->data[1], out->width / 2, out->height / 2, out->linesize[1], -- 1, 8); -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[2], in->width / 2, in->height / 2, in->linesize[2], -- out->data[2], out->width / 2, out->height / 2, out->linesize[2], -- 1, 8); -- break; -- case AV_PIX_FMT_YUV444P: -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 1, 8); -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[1], in->width, in->height, in->linesize[1], -- out->data[1], out->width, out->height, out->linesize[1], -- 1, 8); -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[2], in->width, in->height, in->linesize[2], -- out->data[2], out->width, out->height, out->linesize[2], -- 1, 8); -- break; -- case AV_PIX_FMT_YUV444P16: -- call_resize_kernel(ctx, s->cu_func_ushort, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 2, 16); -- call_resize_kernel(ctx, s->cu_func_ushort, 1, -- in->data[1], in->width, in->height, in->linesize[1], -- out->data[1], out->width, out->height, out->linesize[1], -- 2, 16); -- call_resize_kernel(ctx, s->cu_func_ushort, 1, -- in->data[2], in->width, in->height, in->linesize[2], -- out->data[2], out->width, out->height, out->linesize[2], -- 2, 16); -- break; -- case AV_PIX_FMT_NV12: -- call_resize_kernel(ctx, s->cu_func_uchar, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 1, 8); -- call_resize_kernel(ctx, s->cu_func_uchar2, 2, -- in->data[1], in->width / 2, in->height / 2, in->linesize[1], -- out->data[1], out->width / 2, out->height / 2, out->linesize[1], -- 1, 8); -- break; -- case AV_PIX_FMT_P010LE: -- call_resize_kernel(ctx, s->cu_func_ushort, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 2, 10); -- call_resize_kernel(ctx, s->cu_func_ushort2, 2, -- in->data[1], in->width / 2, in->height / 2, in->linesize[1], -- out->data[1], out->width / 2, out->height / 2, out->linesize[1], -- 2, 10); -- break; -- case AV_PIX_FMT_P016LE: -- call_resize_kernel(ctx, s->cu_func_ushort, 1, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 2, 16); -- call_resize_kernel(ctx, s->cu_func_ushort2, 2, -- in->data[1], in->width / 2, in->height / 2, in->linesize[1], -- out->data[1], out->width / 2, out->height / 2, out->linesize[1], -- 2, 16); -- break; -- case AV_PIX_FMT_0RGB32: -- case AV_PIX_FMT_0BGR32: -- call_resize_kernel(ctx, s->cu_func_uchar4, 4, -- in->data[0], in->width, in->height, in->linesize[0], -- out->data[0], out->width, out->height, out->linesize[0], -- 1, 8); -- break; -- default: -- return AVERROR_BUG; -+#define DEPTH_BYTES(depth) (((depth) + 7) / 8) -+ -+ call_resize_kernel(ctx, s->cu_func_luma, 1, -+ in->data[0], in->width, in->height, in->linesize[0], -+ out->data[0], out->width, out->height, out->linesize[0], -+ DEPTH_BYTES(s->in_desc->comp[0].depth)); -+ -+ call_resize_kernel(ctx, s->cu_func_chroma_u, s->in_planes == 2 ? 2 : 1, -+ in->data[1], -+ AV_CEIL_RSHIFT(in->width, s->in_desc->log2_chroma_w), -+ AV_CEIL_RSHIFT(in->height, s->in_desc->log2_chroma_h), -+ in->linesize[1], -+ out->data[1], -+ AV_CEIL_RSHIFT(out->width, s->out_desc->log2_chroma_w), -+ AV_CEIL_RSHIFT(out->height, s->out_desc->log2_chroma_h), -+ out->linesize[1], -+ DEPTH_BYTES(s->in_desc->comp[1].depth)); -+ -+ if (s->cu_func_chroma_v) { -+ call_resize_kernel(ctx, s->cu_func_chroma_v, s->in_planes == 2 ? 2 : 1, -+ in->data[s->in_desc->comp[2].plane], -+ AV_CEIL_RSHIFT(in->width, s->in_desc->log2_chroma_w), -+ AV_CEIL_RSHIFT(in->height, s->in_desc->log2_chroma_h), -+ in->linesize[s->in_desc->comp[2].plane], -+ out->data[s->out_desc->comp[2].plane] + s->out_desc->comp[2].offset, -+ AV_CEIL_RSHIFT(out->width, s->out_desc->log2_chroma_w), -+ AV_CEIL_RSHIFT(out->height, s->out_desc->log2_chroma_h), -+ out->linesize[s->out_desc->comp[2].plane], -+ DEPTH_BYTES(s->in_desc->comp[2].depth)); - } - - return 0; -@@ -621,20 +644,15 @@ static AVFrame *cudascale_get_video_buff - #define OFFSET(x) offsetof(CUDAScaleContext, x) - #define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) - static const AVOption options[] = { -- { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS }, -- { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS }, -- { "interp_algo", "Interpolation algorithm used for resizing", OFFSET(interp_algo), AV_OPT_TYPE_INT, { .i64 = INTERP_ALGO_DEFAULT }, 0, INTERP_ALGO_COUNT - 1, FLAGS, "interp_algo" }, -- { "nearest", "nearest neighbour", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_NEAREST }, 0, 0, FLAGS, "interp_algo" }, -- { "bilinear", "bilinear", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_BILINEAR }, 0, 0, FLAGS, "interp_algo" }, -- { "bicubic", "bicubic", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_BICUBIC }, 0, 0, FLAGS, "interp_algo" }, -- { "lanczos", "lanczos", 0, AV_OPT_TYPE_CONST, { .i64 = INTERP_ALGO_LANCZOS }, 0, 0, FLAGS, "interp_algo" }, -+ { "w", "Output video width", OFFSET(w_expr), AV_OPT_TYPE_STRING, { .str = "iw" }, .flags = FLAGS }, -+ { "h", "Output video height", OFFSET(h_expr), AV_OPT_TYPE_STRING, { .str = "ih" }, .flags = FLAGS }, -+ { "format", "Output format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS }, - { "passthrough", "Do not process frames at all if parameters match", OFFSET(passthrough), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, FLAGS }, -- { "param", "Algorithm-Specific parameter", OFFSET(param), AV_OPT_TYPE_FLOAT, { .dbl = SCALE_CUDA_PARAM_DEFAULT }, -FLT_MAX, FLT_MAX, FLAGS }, -- { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, 2, FLAGS, "force_oar" }, -- { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" }, -- { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, -- { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, -- { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1 }, 1, 256, FLAGS }, -+ { "force_original_aspect_ratio", "decrease or increase w/h if necessary to keep the original AR", OFFSET(force_original_aspect_ratio), AV_OPT_TYPE_INT, { .i64 = 0}, 0, 2, FLAGS, "force_oar" }, -+ { "disable", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 0 }, 0, 0, FLAGS, "force_oar" }, -+ { "decrease", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 1 }, 0, 0, FLAGS, "force_oar" }, -+ { "increase", NULL, 0, AV_OPT_TYPE_CONST, {.i64 = 2 }, 0, 0, FLAGS, "force_oar" }, -+ { "force_divisible_by", "enforce that the output resolution is divisible by a defined integer when force_original_aspect_ratio is used", OFFSET(force_divisible_by), AV_OPT_TYPE_INT, { .i64 = 1}, 1, 256, FLAGS }, - { NULL }, - }; - -Index: jellyfin-ffmpeg/libavfilter/vf_scale_cuda.cu -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_scale_cuda.cu -+++ jellyfin-ffmpeg/libavfilter/vf_scale_cuda.cu -@@ -20,35 +20,115 @@ - * DEALINGS IN THE SOFTWARE. - */ - --#include "cuda/vector_helpers.cuh" -+typedef unsigned char uchar; -+typedef unsigned short ushort; - --template --__device__ inline void Subsample_Nearest(cudaTextureObject_t tex, -- T *dst, -- int dst_width, int dst_height, int dst_pitch, -- int src_width, int src_height, -- int bit_depth) -+#define SHIFTDOWN(val) (dstbase)(val >> abs(2 + shift)) -+#define SHIFTUP(val) (dstbase)(val << abs(-shift - 2)) -+ -+template struct add_conv_shift1_d - { -- int xo = blockIdx.x * blockDim.x + threadIdx.x; -- int yo = blockIdx.y * blockDim.y + threadIdx.y; -+ typedef DST dstbase; - -- if (yo < dst_height && xo < dst_width) -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) - { -- float hscale = (float)src_width / (float)dst_width; -- float vscale = (float)src_height / (float)dst_height; -- float xi = (xo + 0.5f) * hscale; -- float yi = (yo + 0.5f) * vscale; -+ unsigned ret = (unsigned)i1 + (unsigned)i2 + (unsigned)i3 + (unsigned)i4 + ((1 + d) >> (sizeof(SRC) * 8 - dither + 3)); - -- dst[yo*dst_pitch+xo] = tex2D(tex, xi, yi); -+ if (shift > -2) -+ return SHIFTDOWN(ret); -+ else -+ return SHIFTUP(ret); - } --} -+}; -+ -+template struct add_conv_shift1 -+{ -+ typedef DST dstbase; - --template --__device__ inline void Subsample_Bilinear(cudaTextureObject_t tex, -- T *dst, -- int dst_width, int dst_height, int dst_pitch, -- int src_width, int src_height, -- int bit_depth) -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ unsigned ret = (unsigned)i1 + (unsigned)i2 + (unsigned)i3 + (unsigned)i4 + 2; -+ -+ if (shift > -2) -+ return SHIFTDOWN(ret); -+ else -+ return SHIFTUP(ret); -+ } -+}; -+ -+template struct add_conv_shift2 -+{ -+ typedef decltype(DST::x) dstbase; -+ -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ unsigned retx = (unsigned)i1.x + (unsigned)i2.x + (unsigned)i3.x + (unsigned)i4.x + 2; -+ unsigned rety = (unsigned)i1.y + (unsigned)i2.y + (unsigned)i3.y + (unsigned)i4.y + 2; -+ -+ if (shift > -2) -+ return { SHIFTDOWN(retx), SHIFTDOWN(rety) }; -+ else -+ return { SHIFTUP(retx), SHIFTUP(rety) }; -+ } -+}; -+ -+template struct add_conv_shift2_x -+{ -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ return add_conv_shift1()(i1.x, i2.x, i3.x, i4.x, d); -+ } -+}; -+ -+template struct add_conv_shift2_y -+{ -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ return add_conv_shift1()(i1.y, i2.y, i3.y, i4.y, d); -+ } -+}; -+ -+template struct add_conv_shift3 -+{ -+ typedef decltype(DST::x) dstbase; -+ -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ unsigned retx = (unsigned)i1.x + (unsigned)i2.x + (unsigned)i3.x + (unsigned)i4.x + 2; -+ unsigned rety = (unsigned)i1.y + (unsigned)i2.y + (unsigned)i3.y + (unsigned)i4.y + 2; -+ unsigned retz = (unsigned)i1.z + (unsigned)i2.z + (unsigned)i3.z + (unsigned)i4.z + 2; -+ -+ if (shift > -2) -+ return { SHIFTDOWN(retx), SHIFTDOWN(rety), SHIFTDOWN(retz) }; -+ else -+ return { SHIFTUP(retx), SHIFTUP(rety), SHIFTUP(retz) }; -+ } -+}; -+ -+template struct add_conv_shift4 -+{ -+ typedef decltype(DST::x) dstbase; -+ -+ __inline__ __device__ DST operator()(SRC i1, SRC i2, SRC i3, SRC i4, ushort d) -+ { -+ unsigned retx = (unsigned)i1.x + (unsigned)i2.x + (unsigned)i3.x + (unsigned)i4.x + 2; -+ unsigned rety = (unsigned)i1.y + (unsigned)i2.y + (unsigned)i3.y + (unsigned)i4.y + 2; -+ unsigned retz = (unsigned)i1.z + (unsigned)i2.z + (unsigned)i3.z + (unsigned)i4.z + 2; -+ unsigned retw = (unsigned)i1.w + (unsigned)i2.w + (unsigned)i3.w + (unsigned)i4.w + 2; -+ -+ if (shift > -2) -+ return { SHIFTDOWN(retx), SHIFTDOWN(rety), SHIFTDOWN(retz), SHIFTDOWN(retw) }; -+ else -+ return { SHIFTUP(retx), SHIFTUP(rety), SHIFTUP(retz), SHIFTUP(retw) }; -+ } -+}; -+ -+template class conv, int pitch, int shift, int dither> -+__inline__ __device__ void Subsample_Bilinear(cudaTextureObject_t tex, -+ DST *dst, -+ int dst_width, int dst_height, int dst_pitch, -+ int src_width, int src_height, -+ cudaTextureObject_t ditherTex) - { - int xo = blockIdx.x * blockDim.x + threadIdx.x; - int yo = blockIdx.y * blockDim.y + threadIdx.y; -@@ -66,58 +146,48 @@ __device__ inline void Subsample_Bilinea - float dx = wh / (0.5f + wh); - float dy = wv / (0.5f + wv); - -- intT r = { 0 }; -- vec_set_scalar(r, 2); -- r += tex2D(tex, xi - dx, yi - dy); -- r += tex2D(tex, xi + dx, yi - dy); -- r += tex2D(tex, xi - dx, yi + dy); -- r += tex2D(tex, xi + dx, yi + dy); -- vec_set(dst[yo*dst_pitch+xo], r >> 2); -+ SRC i0 = tex2D(tex, xi-dx, yi-dy); -+ SRC i1 = tex2D(tex, xi+dx, yi-dy); -+ SRC i2 = tex2D(tex, xi-dx, yi+dy); -+ SRC i3 = tex2D(tex, xi+dx, yi+dy); -+ -+ ushort ditherVal = dither ? tex2D(ditherTex, xo, yo) : 0; -+ -+ dst[yo*(dst_pitch / sizeof(DST))+xo*pitch] = conv()(i0, i1, i2, i3, ditherVal); - } - } - - extern "C" { - --#define NEAREST_KERNEL(T) \ -- __global__ void Subsample_Nearest_ ## T(cudaTextureObject_t src_tex, \ -- T *dst, \ -- int dst_width, int dst_height, int dst_pitch, \ -- int src_width, int src_height, \ -- int bit_depth) \ -- { \ -- Subsample_Nearest(src_tex, dst, \ -- dst_width, dst_height, dst_pitch, \ -- src_width, src_height, \ -- bit_depth); \ -- } -- --NEAREST_KERNEL(uchar) --NEAREST_KERNEL(uchar2) --NEAREST_KERNEL(uchar4) -- --NEAREST_KERNEL(ushort) --NEAREST_KERNEL(ushort2) --NEAREST_KERNEL(ushort4) -- --#define BILINEAR_KERNEL(T) \ -- __global__ void Subsample_Bilinear_ ## T(cudaTextureObject_t src_tex, \ -- T *dst, \ -- int dst_width, int dst_height, int dst_pitch, \ -- int src_width, int src_height, \ -- int bit_depth) \ -- { \ -- Subsample_Bilinear(src_tex, dst, \ -- dst_width, dst_height, dst_pitch, \ -- src_width, src_height, \ -- bit_depth); \ -- } -- --BILINEAR_KERNEL(uchar) --BILINEAR_KERNEL(uchar2) --BILINEAR_KERNEL(uchar4) -- --BILINEAR_KERNEL(ushort) --BILINEAR_KERNEL(ushort2) --BILINEAR_KERNEL(ushort4) -+#define VARIANT(SRC, DST, CONV, SHIFT, PITCH, DITHER, NAME) \ -+__global__ void Subsample_Bilinear_ ## NAME(cudaTextureObject_t tex, \ -+ DST *dst, \ -+ int dst_width, int dst_height, int dst_pitch, \ -+ int src_width, int src_height, \ -+ cudaTextureObject_t ditherTex) \ -+{ \ -+ Subsample_Bilinear(tex, dst, dst_width, dst_height, dst_pitch, \ -+ src_width, src_height, ditherTex); \ -+} -+ -+#define VARIANTSET2(SRC, DST, SHIFT, NAME) \ -+ VARIANT(SRC, DST, add_conv_shift1_d, SHIFT, 1, (sizeof(DST) < sizeof(SRC)) ? sizeof(DST) : 0, NAME) \ -+ VARIANT(SRC, DST, add_conv_shift1, SHIFT, 1, 0, NAME ## _c) \ -+ VARIANT(SRC, DST, add_conv_shift1, SHIFT, 2, 0, NAME ## _p2) \ -+ VARIANT(SRC ## 2, DST ## 2, add_conv_shift2, SHIFT, 1, 0, NAME ## _2) \ -+ VARIANT(SRC ## 2, DST, add_conv_shift2_x, SHIFT, 1, 0, NAME ## _2_u) \ -+ VARIANT(SRC ## 2, DST, add_conv_shift2_y, SHIFT, 1, 0, NAME ## _2_v) \ -+ VARIANT(SRC ## 4, DST ## 4, add_conv_shift4, SHIFT, 1, 0, NAME ## _4) -+ -+#define VARIANTSET(SRC, DST, SRCSIZE, DSTSIZE) \ -+ VARIANTSET2(SRC, DST, (SRCSIZE - DSTSIZE), SRCSIZE ## _ ## DSTSIZE) -+ -+// Straight no-conversion -+VARIANTSET(uchar, uchar, 8, 8) -+VARIANTSET(ushort, ushort, 16, 16) -+ -+// Conversion between 8- and 16-bit -+VARIANTSET(uchar, ushort, 8, 16) -+VARIANTSET(ushort, uchar, 16, 8) - - } -Index: jellyfin-ffmpeg/libavfilter/vf_scale_cuda.h -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_scale_cuda.h -+++ /dev/null -@@ -1,28 +0,0 @@ --/* -- * This file is part of FFmpeg. -- * -- * Permission is hereby granted, free of charge, to any person obtaining a -- * copy of this software and associated documentation files (the "Software"), -- * to deal in the Software without restriction, including without limitation -- * the rights to use, copy, modify, merge, publish, distribute, sublicense, -- * and/or sell copies of the Software, and to permit persons to whom the -- * Software is furnished to do so, subject to the following conditions: -- * -- * The above copyright notice and this permission notice shall be included in -- * all copies or substantial portions of the Software. -- * -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -- * DEALINGS IN THE SOFTWARE. -- */ -- --#ifndef AVFILTER_SCALE_CUDA_H --#define AVFILTER_SCALE_CUDA_H -- --#define SCALE_CUDA_PARAM_DEFAULT 999999.0f -- --#endif -Index: jellyfin-ffmpeg/libavfilter/vf_scale_cuda_bicubic.cu -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_scale_cuda_bicubic.cu -+++ /dev/null -@@ -1,224 +0,0 @@ --/* -- * This file is part of FFmpeg. -- * -- * Permission is hereby granted, free of charge, to any person obtaining a -- * copy of this software and associated documentation files (the "Software"), -- * to deal in the Software without restriction, including without limitation -- * the rights to use, copy, modify, merge, publish, distribute, sublicense, -- * and/or sell copies of the Software, and to permit persons to whom the -- * Software is furnished to do so, subject to the following conditions: -- * -- * The above copyright notice and this permission notice shall be included in -- * all copies or substantial portions of the Software. -- * -- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR -- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, -- * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL -- * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER -- * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING -- * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER -- * DEALINGS IN THE SOFTWARE. -- */ -- --#include "cuda/vector_helpers.cuh" --#include "vf_scale_cuda.h" -- --typedef float4 (*coeffs_function_t)(float, float); -- --__device__ inline float4 lanczos_coeffs(float x, float param) --{ -- const float pi = 3.141592654f; -- -- float4 res = make_float4( -- pi * (x + 1), -- pi * x, -- pi * (x - 1), -- pi * (x - 2)); -- -- res.x = res.x == 0.0f ? 1.0f : -- __sinf(res.x) * __sinf(res.x / 2.0f) / (res.x * res.x / 2.0f); -- res.y = res.y == 0.0f ? 1.0f : -- __sinf(res.y) * __sinf(res.y / 2.0f) / (res.y * res.y / 2.0f); -- res.z = res.z == 0.0f ? 1.0f : -- __sinf(res.z) * __sinf(res.z / 2.0f) / (res.z * res.z / 2.0f); -- res.w = res.w == 0.0f ? 1.0f : -- __sinf(res.w) * __sinf(res.w / 2.0f) / (res.w * res.w / 2.0f); -- -- return res / (res.x + res.y + res.z + res.w); --} -- --__device__ inline float4 bicubic_coeffs(float x, float param) --{ -- const float A = param == SCALE_CUDA_PARAM_DEFAULT ? 0.0f : -param; -- -- float4 res; -- res.x = ((A * (x + 1) - 5 * A) * (x + 1) + 8 * A) * (x + 1) - 4 * A; -- res.y = ((A + 2) * x - (A + 3)) * x * x + 1; -- res.z = ((A + 2) * (1 - x) - (A + 3)) * (1 - x) * (1 - x) + 1; -- res.w = 1.0f - res.x - res.y - res.z; -- -- return res; --} -- --__device__ inline void derived_fast_coeffs(float4 coeffs, float x, float *h0, float *h1, float *s) --{ -- float g0 = coeffs.x + coeffs.y; -- float g1 = coeffs.z + coeffs.w; -- -- *h0 = coeffs.y / g0 - 0.5f; -- *h1 = coeffs.w / g1 + 1.5f; -- *s = g0 / (g0 + g1); --} -- --template --__device__ inline V apply_coeffs(float4 coeffs, V c0, V c1, V c2, V c3) --{ -- V res = c0 * coeffs.x; -- res += c1 * coeffs.y; -- res += c2 * coeffs.z; -- res += c3 * coeffs.w; -- -- return res; --} -- --template --__device__ inline void Subsample_Bicubic(coeffs_function_t coeffs_function, -- cudaTextureObject_t src_tex, -- T *dst, -- int dst_width, int dst_height, int dst_pitch, -- int src_width, int src_height, -- int bit_depth, float param) --{ -- int xo = blockIdx.x * blockDim.x + threadIdx.x; -- int yo = blockIdx.y * blockDim.y + threadIdx.y; -- -- if (yo < dst_height && xo < dst_width) -- { -- float hscale = (float)src_width / (float)dst_width; -- float vscale = (float)src_height / (float)dst_height; -- float xi = (xo + 0.5f) * hscale - 0.5f; -- float yi = (yo + 0.5f) * vscale - 0.5f; -- float px = floor(xi); -- float py = floor(yi); -- float fx = xi - px; -- float fy = yi - py; -- -- float factor = bit_depth > 8 ? 0xFFFF : 0xFF; -- -- float4 coeffsX = coeffs_function(fx, param); -- float4 coeffsY = coeffs_function(fy, param); -- --#define PIX(x, y) tex2D(src_tex, (x), (y)) -- -- dst[yo * dst_pitch + xo] = from_floatN( -- apply_coeffs(coeffsY, -- apply_coeffs(coeffsX, PIX(px - 1, py - 1), PIX(px, py - 1), PIX(px + 1, py - 1), PIX(px + 2, py - 1)), -- apply_coeffs(coeffsX, PIX(px - 1, py ), PIX(px, py ), PIX(px + 1, py ), PIX(px + 2, py )), -- apply_coeffs(coeffsX, PIX(px - 1, py + 1), PIX(px, py + 1), PIX(px + 1, py + 1), PIX(px + 2, py + 1)), -- apply_coeffs(coeffsX, PIX(px - 1, py + 2), PIX(px, py + 2), PIX(px + 1, py + 2), PIX(px + 2, py + 2)) -- ) * factor -- ); -- --#undef PIX -- } --} -- --/* This does not yield correct results. Most likely because of low internal precision in tex2D linear interpolation */ --template --__device__ inline void Subsample_FastBicubic(coeffs_function_t coeffs_function, -- cudaTextureObject_t src_tex, -- T *dst, -- int dst_width, int dst_height, int dst_pitch, -- int src_width, int src_height, -- int bit_depth, float param) --{ -- int xo = blockIdx.x * blockDim.x + threadIdx.x; -- int yo = blockIdx.y * blockDim.y + threadIdx.y; -- -- if (yo < dst_height && xo < dst_width) -- { -- float hscale = (float)src_width / (float)dst_width; -- float vscale = (float)src_height / (float)dst_height; -- float xi = (xo + 0.5f) * hscale - 0.5f; -- float yi = (yo + 0.5f) * vscale - 0.5f; -- float px = floor(xi); -- float py = floor(yi); -- float fx = xi - px; -- float fy = yi - py; -- -- float factor = bit_depth > 8 ? 0xFFFF : 0xFF; -- -- float4 coeffsX = coeffs_function(fx, param); -- float4 coeffsY = coeffs_function(fy, param); -- -- float h0x, h1x, sx; -- float h0y, h1y, sy; -- derived_fast_coeffs(coeffsX, fx, &h0x, &h1x, &sx); -- derived_fast_coeffs(coeffsY, fy, &h0y, &h1y, &sy); -- --#define PIX(x, y) tex2D(src_tex, (x), (y)) -- -- floatT pix[4] = { -- PIX(px + h0x, py + h0y), -- PIX(px + h1x, py + h0y), -- PIX(px + h0x, py + h1y), -- PIX(px + h1x, py + h1y) -- }; -- --#undef PIX -- -- dst[yo * dst_pitch + xo] = from_floatN( -- lerp_scalar( -- lerp_scalar(pix[3], pix[2], sx), -- lerp_scalar(pix[1], pix[0], sx), -- sy) * factor -- ); -- } --} -- --extern "C" { -- --#define BICUBIC_KERNEL(T) \ -- __global__ void Subsample_Bicubic_ ## T(cudaTextureObject_t src_tex, \ -- T *dst, \ -- int dst_width, int dst_height, int dst_pitch, \ -- int src_width, int src_height, \ -- int bit_depth, float param) \ -- { \ -- Subsample_Bicubic(&bicubic_coeffs, src_tex, dst, \ -- dst_width, dst_height, dst_pitch, \ -- src_width, src_height, \ -- bit_depth, param); \ -- } -- --BICUBIC_KERNEL(uchar) --BICUBIC_KERNEL(uchar2) --BICUBIC_KERNEL(uchar4) -- --BICUBIC_KERNEL(ushort) --BICUBIC_KERNEL(ushort2) --BICUBIC_KERNEL(ushort4) -- -- --#define LANCZOS_KERNEL(T) \ -- __global__ void Subsample_Lanczos_ ## T(cudaTextureObject_t src_tex, \ -- T *dst, \ -- int dst_width, int dst_height, int dst_pitch, \ -- int src_width, int src_height, \ -- int bit_depth, float param) \ -- { \ -- Subsample_Bicubic(&lanczos_coeffs, src_tex, dst, \ -- dst_width, dst_height, dst_pitch, \ -- src_width, src_height, \ -- bit_depth, param); \ -- } -- --LANCZOS_KERNEL(uchar) --LANCZOS_KERNEL(uchar2) --LANCZOS_KERNEL(uchar4) -- --LANCZOS_KERNEL(ushort) --LANCZOS_KERNEL(ushort2) --LANCZOS_KERNEL(ushort4) -- --} diff --git a/debian/patches/0005-cuda-tonemap-impl.patch b/debian/patches/0005-cuda-tonemap-impl.patch deleted file mode 100644 index 4a4c48320..000000000 --- a/debian/patches/0005-cuda-tonemap-impl.patch +++ /dev/null @@ -1,1824 +0,0 @@ -Index: jellyfin-ffmpeg/compat/cuda/cuda_runtime.h -=================================================================== ---- jellyfin-ffmpeg.orig/compat/cuda/cuda_runtime.h -+++ jellyfin-ffmpeg/compat/cuda/cuda_runtime.h -@@ -33,55 +33,69 @@ - #define max(a, b) ((a) > (b) ? (a) : (b)) - #define min(a, b) ((a) < (b) ? (a) : (b)) - #define abs(x) ((x) < 0 ? -(x) : (x)) -+#define clamp(a, b, c) min(max((a), (b)), (c)) - - #define atomicAdd(a, b) (__atomic_fetch_add(a, b, __ATOMIC_SEQ_CST)) - - // Basic typedefs - typedef __device_builtin__ unsigned long long cudaTextureObject_t; - --typedef struct __device_builtin__ __align__(2) uchar2 --{ -- unsigned char x, y; --} uchar2; -- --typedef struct __device_builtin__ __align__(4) ushort2 --{ -- unsigned short x, y; --} ushort2; -- --typedef struct __device_builtin__ uint3 --{ -- unsigned int x, y, z; --} uint3; -- --typedef struct uint3 dim3; -- --typedef struct __device_builtin__ __align__(8) int2 --{ -- int x, y; --} int2; -+#define MAKE_VECTORS(type, base) \ -+typedef struct __device_builtin__ type##1 { \ -+ base x; \ -+} type##1; \ -+static __inline__ __device__ type##1 make_##type##1(base x) { \ -+ type##1 ret; \ -+ ret.x = x; \ -+ return ret; \ -+} \ -+typedef struct __device_builtin__ __align__(sizeof(base) * 2) type##2 { \ -+ base x, y; \ -+} type##2; \ -+static __inline__ __device__ type##2 make_##type##2(base x, base y) { \ -+ type##2 ret; \ -+ ret.x = x; \ -+ ret.y = y; \ -+ return ret; \ -+} \ -+typedef struct __device_builtin__ type##3 { \ -+ base x, y, z; \ -+} type##3; \ -+static __inline__ __device__ type##3 make_##type##3(base x, base y, base z) { \ -+ type##3 ret; \ -+ ret.x = x; \ -+ ret.y = y; \ -+ ret.z = z; \ -+ return ret; \ -+} \ -+typedef struct __device_builtin__ __align__(sizeof(base) * 4) type##4 { \ -+ base x, y, z, w; \ -+} type##4; \ -+static __inline__ __device__ type##4 make_##type##4(base x, base y, base z, base w) { \ -+ type##4 ret; \ -+ ret.x = x; \ -+ ret.y = y; \ -+ ret.z = z; \ -+ ret.w = w; \ -+ return ret; \ -+} - --typedef struct __device_builtin__ __align__(4) uchar4 --{ -- unsigned char x, y, z, w; --} uchar4; -+#define MAKE_TYPE - --typedef struct __device_builtin__ __align__(8) ushort4 --{ -- unsigned short x, y, z, w; --} ushort4; -+MAKE_VECTORS(uchar, unsigned char) -+MAKE_VECTORS(ushort, unsigned short) -+MAKE_VECTORS(int, int) -+MAKE_VECTORS(uint, unsigned int) -+MAKE_VECTORS(float, float) - --typedef struct __device_builtin__ __align__(16) int4 --{ -- int x, y, z, w; --} int4; -+typedef struct __device_builtin__ uint3 dim3; - - // Accessors for special registers - #define GETCOMP(reg, comp) \ - asm("mov.u32 %0, %%" #reg "." #comp ";" : "=r"(tmp)); \ - ret.comp = tmp; - --#define GET(name, reg) static inline __device__ uint3 name() {\ -+#define GET(name, reg) static __inline__ __device__ uint3 name() {\ - uint3 ret; \ - unsigned tmp; \ - GETCOMP(reg, x) \ -@@ -99,14 +113,8 @@ GET(getThreadIdx, tid) - #define blockDim (getBlockDim()) - #define threadIdx (getThreadIdx()) - --// Basic initializers (simple macros rather than inline functions) --#define make_uchar2(a, b) ((uchar2){.x = a, .y = b}) --#define make_ushort2(a, b) ((ushort2){.x = a, .y = b}) --#define make_uchar4(a, b, c, d) ((uchar4){.x = a, .y = b, .z = c, .w = d}) --#define make_ushort4(a, b, c, d) ((ushort4){.x = a, .y = b, .z = c, .w = d}) -- - // Conversions from the tex instruction's 4-register output to various types --#define TEX2D(type, ret) static inline __device__ void conv(type* out, unsigned a, unsigned b, unsigned c, unsigned d) {*out = (ret);} -+#define TEX2D(type, ret) static __inline__ __device__ void conv(type* out, unsigned a, unsigned b, unsigned c, unsigned d) {*out = (ret);} - - TEX2D(unsigned char, a & 0xFF) - TEX2D(unsigned short, a & 0xFFFF) -@@ -117,15 +125,47 @@ TEX2D(ushort4, make_ushort4((unsigned sh - - // Template calling tex instruction and converting the output to the selected type - template --static inline __device__ T tex2D(cudaTextureObject_t texObject, float x, float y) -+static __inline__ __device__ T tex2D(cudaTextureObject_t texObject, float x, float y) -+{ -+ T ret; -+ unsigned ret1, ret2, ret3, ret4; -+ asm("tex.2d.v4.u32.f32 {%0, %1, %2, %3}, [%4, {%5, %6}];" : -+ "=r"(ret1), "=r"(ret2), "=r"(ret3), "=r"(ret4) : -+ "l"(texObject), "f"(x), "f"(y)); -+ conv(&ret, ret1, ret2, ret3, ret4); -+ return ret; -+} -+ -+static __inline__ __device__ float __exp2f(float x) -+{ -+ float ret; -+ asm("ex2.approx.f32 %0, %1;" : "=f"(ret) : "f"(x)); -+ return ret; -+} -+ -+#define __expf(x) (__exp2f((x) * 1.4427f)) -+ -+static __inline__ __device__ float __log2f(float x) - { -- T ret; -- unsigned ret1, ret2, ret3, ret4; -- asm("tex.2d.v4.u32.f32 {%0, %1, %2, %3}, [%4, {%5, %6}];" : -- "=r"(ret1), "=r"(ret2), "=r"(ret3), "=r"(ret4) : -- "l"(texObject), "f"(x), "f"(y)); -- conv(&ret, ret1, ret2, ret3, ret4); -- return ret; -+ float ret; -+ asm("lg2.approx.f32 %0, %1;" : "=f"(ret) : "f"(x)); -+ return ret; - } - --#endif /* COMPAT_CUDA_CUDA_RUNTIME_H */ -+#define __logf(x) (__log2f((x)) * 0.693147f) -+#define __log10f(x) (__log2f((x)) * 0.30103f) -+ -+static __inline__ __device__ float __powf(float x, float y) -+{ -+ return __exp2f(y * __log2f(x)); -+} -+ -+static __inline__ __device__ float __sqrtf(float x) -+{ -+ float ret; -+ asm("sqrtf.approx.f32 %0, %1;" : "=f"(ret) : "f"(x)); -+ return ret; -+} -+ -+#endif -+ -Index: jellyfin-ffmpeg/configure -=================================================================== ---- jellyfin-ffmpeg.orig/configure -+++ jellyfin-ffmpeg/configure -@@ -3057,6 +3057,8 @@ scale_cuda_filter_deps="ffnvcodec" - scale_cuda_filter_deps_any="cuda_nvcc cuda_llvm" - thumbnail_cuda_filter_deps="ffnvcodec" - thumbnail_cuda_filter_deps_any="cuda_nvcc cuda_llvm" -+tonemap_cuda_filter_deps="ffnvcodec const_nan" -+tonemap_cuda_filter_deps_any="cuda_nvcc cuda_llvm" - transpose_npp_filter_deps="ffnvcodec libnpp" - overlay_cuda_filter_deps="ffnvcodec" - overlay_cuda_filter_deps_any="cuda_nvcc cuda_llvm" -Index: jellyfin-ffmpeg/ffbuild/common.mak -=================================================================== ---- jellyfin-ffmpeg.orig/ffbuild/common.mak -+++ jellyfin-ffmpeg/ffbuild/common.mak -@@ -38,6 +38,7 @@ OBJCCFLAGS = $(CPPFLAGS) $(CFLAGS) $(OB - ASFLAGS := $(CPPFLAGS) $(ASFLAGS) - CXXFLAGS := $(CPPFLAGS) $(CFLAGS) $(CXXFLAGS) - X86ASMFLAGS += $(IFLAGS:%=%/) -I$( 0.0f) { -+ float xpow = __powf(x, 1.0f / ST2084_M2); -+ float num = max(xpow - ST2084_C1, 0.0f); -+ float den = max(ST2084_C2 - ST2084_C3 * xpow, FLOAT_EPS); -+ x = __powf(num / den, 1.0f / ST2084_M1); -+ return x * ST2084_MAX_LUMINANCE / REFERENCE_WHITE; -+ } else { -+ return 0.0f; -+ } -+} -+ -+// delinearizer for PQ/ST2084 -+static __inline__ __device__ float inverse_eotf_st2084(float x) { -+ if (x > 0.0f) { -+ x *= REFERENCE_WHITE / ST2084_MAX_LUMINANCE; -+ float xpow = __powf(x, ST2084_M1); -+#if 0 -+ // Original formulation from SMPTE ST 2084:2014 publication. -+ float num = ST2084_C1 + ST2084_C2 * xpow; -+ float den = 1.0f + ST2084_C3 * xpow; -+ return __powf(num / den, ST2084_M2); -+#else -+ // More stable arrangement that avoids some cancellation error. -+ float num = (ST2084_C1 - 1.0f) + (ST2084_C2 - ST2084_C3) * xpow; -+ float den = 1.0f + ST2084_C3 * xpow; -+ return __powf(1.0f + num / den, ST2084_M2); -+#endif -+ } else { -+ return 0.0f; -+ } -+} -+ -+static __inline__ __device__ float ootf_1_2(float x) { -+ return x < 0.0f ? x : __powf(x, 1.2f); -+} -+ -+static __inline__ __device__ float inverse_ootf_1_2(float x) { -+ return x < 0.0f ? x : __powf(x, 1.0f / 1.2f); -+} -+ -+static __inline__ __device__ float oetf_arib_b67(float x) { -+ x = max(x, 0.0f); -+ return x <= (1.0f / 12.0f) -+ ? __sqrtf(3.0f * x) -+ : (ARIB_B67_A * __logf(12.0f * x - ARIB_B67_B) + ARIB_B67_C); -+} -+ -+static __inline__ __device__ float inverse_oetf_arib_b67(float x) { -+ x = max(x, 0.0f); -+ return x <= 0.5f -+ ? (x * x) * (1.0f / 3.0f) -+ : (__expf((x - ARIB_B67_C) / ARIB_B67_A) + ARIB_B67_B) * (1.0f / 12.0f); -+} -+ -+// linearizer for HLG/ARIB-B67 -+static __inline__ __device__ float eotf_arib_b67(float x) { -+ return ootf_1_2(inverse_oetf_arib_b67(x)); -+} -+ -+// delinearizer for HLG/ARIB-B67 -+static __inline__ __device__ float inverse_eotf_arib_b67(float x) { -+ return oetf_arib_b67(inverse_ootf_1_2(x)); -+} -+ -+static __inline__ __device__ float inverse_eotf_bt1886(float x) { -+ return x < 0.0f ? 0.0f : __powf(x, 1.0f / 2.4f); -+} -+ -+static __inline__ __device__ float oetf_bt709(float x) { -+ x = max(0.0f, x); -+ return x < BT709_BETA -+ ? (x * 4.5f) -+ : (BT709_ALPHA * __powf(x, 0.45f) - (BT709_ALPHA - 1.0f)); -+} -+ -+static __inline__ __device__ float inverse_oetf_bt709(float x) { -+ return x < (4.5f * BT709_BETA) -+ ? (x / 4.5f) -+ : (__powf((x + (BT709_ALPHA - 1.0f)) / BT709_ALPHA, 1.0f / 0.45f)); -+} -+ -+static __inline__ __device__ float linearize(float x) -+{ -+ if (trc_src == AVCOL_TRC_SMPTE2084) -+ return eotf_st2084(x); -+ else if (trc_src == AVCOL_TRC_ARIB_STD_B67) -+ return eotf_arib_b67(x); -+ else -+ return x; -+} -+ -+static __inline__ __device__ float delinearize(float x) -+{ -+ if (trc_dst == AVCOL_TRC_BT709 || trc_dst == AVCOL_TRC_BT2020_10) -+ return inverse_eotf_bt1886(x); -+ else -+ return x; -+} -+ -+static __inline__ __device__ float3 yuv2rgb(float y, float u, float v) { -+ if (range_src == AVCOL_RANGE_JPEG) { -+ u -= 0.5f; v -= 0.5f; -+ } else { -+ y = (y * 255.0f - 16.0f) / 219.0f; -+ u = (u * 255.0f - 128.0f) / 224.0f; -+ v = (v * 255.0f - 128.0f) / 224.0f; -+ } -+ float r = y * rgb_matrix[0] + u * rgb_matrix[1] + v * rgb_matrix[2]; -+ float g = y * rgb_matrix[3] + u * rgb_matrix[4] + v * rgb_matrix[5]; -+ float b = y * rgb_matrix[6] + u * rgb_matrix[7] + v * rgb_matrix[8]; -+ return make_float3(r, g, b); -+} -+ -+static __inline__ __device__ float3 yuv2lrgb(float3 yuv) { -+ float3 rgb = yuv2rgb(yuv.x, yuv.y, yuv.z); -+ return make_float3(linearize(rgb.x), -+ linearize(rgb.y), -+ linearize(rgb.z)); -+} -+ -+static __inline__ __device__ float3 rgb2yuv(float r, float g, float b) { -+ float y = r*yuv_matrix[0] + g*yuv_matrix[1] + b*yuv_matrix[2]; -+ float u = r*yuv_matrix[3] + g*yuv_matrix[4] + b*yuv_matrix[5]; -+ float v = r*yuv_matrix[6] + g*yuv_matrix[7] + b*yuv_matrix[8]; -+ if (range_dst == AVCOL_RANGE_JPEG) { -+ u += 0.5f; v += 0.5f; -+ } else { -+ y = (219.0f * y + 16.0f) / 255.0f; -+ u = (224.0f * u + 128.0f) / 255.0f; -+ v = (224.0f * v + 128.0f) / 255.0f; -+ } -+ return make_float3(y, u, v); -+} -+ -+static __inline__ __device__ float rgb2y(float r, float g, float b) { -+ float y = r*yuv_matrix[0] + g*yuv_matrix[1] + b*yuv_matrix[2]; -+ if (range_dst != AVCOL_RANGE_JPEG) -+ y = (219.0f * y + 16.0f) / 255.0f; -+ return y; -+} -+ -+static __inline__ __device__ float3 lrgb2yuv(float3 c) { -+ float r = delinearize(c.x); -+ float g = delinearize(c.y); -+ float b = delinearize(c.z); -+ return rgb2yuv(r, g, b); -+} -+ -+static __inline__ __device__ float3 lrgb2lrgb(float3 c) { -+ if (rgb2rgb_passthrough) { -+ return c; -+ } else { -+ float r = c.x, g = c.y, b = c.z; -+ float rr = rgb2rgb_matrix[0] * r + rgb2rgb_matrix[1] * g + rgb2rgb_matrix[2] * b; -+ float gg = rgb2rgb_matrix[3] * r + rgb2rgb_matrix[4] * g + rgb2rgb_matrix[5] * b; -+ float bb = rgb2rgb_matrix[6] * r + rgb2rgb_matrix[7] * g + rgb2rgb_matrix[8] * b; -+ return make_float3(rr, gg, bb); -+ } -+} -+ -+#endif /* AVFILTER_CUDA_COLORSPACE_COMMON_H */ -Index: jellyfin-ffmpeg/libavfilter/cuda/host_util.c -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/host_util.c -@@ -0,0 +1,35 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "libavfilter/colorspace.h" -+#include "host_util.h" -+ -+int ff_make_cuda_frame(FFCUDAFrame *dst, const AVFrame *src) -+{ -+ int i = 0; -+ for (i = 0; i < 4; i++) { -+ dst->data[i] = src->data[i]; -+ dst->linesize[i] = src->linesize[i]; -+ } -+ -+ dst->width = src->width; -+ dst->height = src->height; -+ -+ return 0; -+} -+ -Index: jellyfin-ffmpeg/libavfilter/cuda/host_util.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/host_util.h -@@ -0,0 +1,29 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVFILTER_CUDA_HOST_UTIL_H -+#define AVFILTER_CUDA_HOST_UTIL_H -+ -+#include "libavutil/frame.h" -+ -+#include "shared.h" -+ -+int ff_make_cuda_frame(FFCUDAFrame *dst, const AVFrame *src); -+ -+#endif /* AVFILTER_CUDA_HOST_UTIL_H */ -+ -Index: jellyfin-ffmpeg/libavfilter/cuda/pixfmt.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/pixfmt.h -@@ -0,0 +1,209 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVFILTER_CUDA_PIXFMT_H -+#define AVFILTER_CUDA_PIXFMT_H -+ -+#include "shared.h" -+ -+extern const enum AVPixelFormat fmt_src, fmt_dst; -+extern const int depth_src, depth_dst; -+ -+// Single-sample read function -+template -+static __inline__ __device__ T read_sample(const FFCUDAFrame& frame, int x, int y) -+{ -+ T* ptr = (T*)(frame.data[p] + (y * frame.linesize[p])); -+ return ptr[x]; -+} -+ -+// Per-format read functions -+static __inline__ __device__ ushort3 read_p016(const FFCUDAFrame& frame, int x, int y) -+{ -+ return make_ushort3(read_sample(frame, x, y), -+ read_sample(frame, (x & ~1), y / 2), -+ read_sample(frame, (x & ~1) + 1, y / 2)); -+} -+ -+static __inline__ __device__ ushort3 read_p010(const FFCUDAFrame& frame, int x, int y) -+{ -+ ushort3 val = read_p016(frame, x, y); -+ return make_ushort3(val.x >> 6, -+ val.y >> 6, -+ val.z >> 6); -+} -+ -+static __inline__ __device__ ushort3 read_yuv420p16(const FFCUDAFrame& frame, int x, int y) -+{ -+ return make_ushort3(read_sample(frame, x, y), -+ read_sample(frame, x / 2, y / 2), -+ read_sample(frame, x / 2, y / 2)); -+} -+ -+static __inline__ __device__ ushort3 read_yuv420p10(const FFCUDAFrame& frame, int x, int y) -+{ -+ ushort3 val = read_yuv420p16(frame, x, y); -+ return make_ushort3(val.x >> 6, -+ val.y >> 6, -+ val.z >> 6); -+} -+ -+// Generic read functions -+static __inline__ __device__ ushort3 read_px(const FFCUDAFrame& frame, int x, int y) -+{ -+ if (fmt_src == AV_PIX_FMT_P016) -+ return read_p016(frame, x, y); -+ else if (fmt_src == AV_PIX_FMT_P010) -+ return read_p010(frame, x, y); -+ else -+ return make_ushort3(0, 0, 0); -+} -+ -+static __inline__ __device__ float sample_to_float(unsigned short i) -+{ -+ return (float)i / ((1 << depth_src) - 1); -+} -+ -+static __inline__ __device__ float3 pixel_to_float3(ushort3 flt) -+{ -+ return make_float3(sample_to_float(flt.x), -+ sample_to_float(flt.y), -+ sample_to_float(flt.z)); -+} -+ -+static __inline__ __device__ float3 read_px_flt(const FFCUDAFrame& frame, int x, int y) -+{ -+ return pixel_to_float3(read_px(frame, x, y)); -+} -+ -+// Single-sample write function -+template -+static __inline__ __device__ void write_sample(const FFCUDAFrame& frame, int x, int y, T sample) -+{ -+ T* ptr = (T*)(frame.data[p] + (y * frame.linesize[p])); -+ ptr[x] = sample; -+} -+ -+// Per-format write functions -+static __inline__ __device__ void write_nv12_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned char)a.x); -+ write_sample<0>(frame, x + 1, y, (unsigned char)b.x); -+ write_sample<0>(frame, x, y + 1, (unsigned char)c.x); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned char)d.x); -+ -+ write_sample<1>(frame, (x & ~1), y / 2, (unsigned char)chroma.y); -+ write_sample<1>(frame, (x & ~1) + 1, y / 2, (unsigned char)chroma.z); -+} -+ -+static __inline__ __device__ void write_yuv420p_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned char)a.x); -+ write_sample<0>(frame, x + 1, y, (unsigned char)b.x); -+ write_sample<0>(frame, x, y + 1, (unsigned char)c.x); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned char)d.x); -+ -+ write_sample<1>(frame, x / 2, y / 2, (unsigned char)chroma.y); -+ write_sample<2>(frame, x / 2, y / 2, (unsigned char)chroma.z); -+} -+ -+static __inline__ __device__ void write_p016_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned short)a.x); -+ write_sample<0>(frame, x + 1, y, (unsigned short)b.x); -+ write_sample<0>(frame, x, y + 1, (unsigned short)c.x); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned short)d.x); -+ -+ write_sample<1>(frame, (x & ~1), y / 2, (unsigned short)chroma.y); -+ write_sample<1>(frame, (x & ~1) + 1, y / 2, (unsigned short)chroma.z); -+} -+ -+static __inline__ __device__ void write_p010_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned short)(a.x << 6)); -+ write_sample<0>(frame, x + 1, y, (unsigned short)(b.x << 6)); -+ write_sample<0>(frame, x, y + 1, (unsigned short)(c.x << 6)); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned short)(d.x << 6)); -+ -+ write_sample<1>(frame, (x & ~1), y / 2, (unsigned short)(chroma.y << 6)); -+ write_sample<1>(frame, (x & ~1) + 1, y / 2, (unsigned short)(chroma.z << 6)); -+} -+ -+static __inline__ __device__ void write_yuv420p16_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned short)a.x); -+ write_sample<0>(frame, x + 1, y, (unsigned short)b.x); -+ write_sample<0>(frame, x, y + 1, (unsigned short)c.x); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned short)d.x); -+ -+ write_sample<1>(frame, x / 2, y / 2, (unsigned short)chroma.y); -+ write_sample<2>(frame, x / 2, y / 2, (unsigned short)chroma.z); -+} -+ -+static __inline__ __device__ void write_yuv420p10_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ write_sample<0>(frame, x, y, (unsigned short)(a.x << 6)); -+ write_sample<0>(frame, x + 1, y, (unsigned short)(b.x << 6)); -+ write_sample<0>(frame, x, y + 1, (unsigned short)(c.x << 6)); -+ write_sample<0>(frame, x + 1, y + 1, (unsigned short)(d.x << 6)); -+ -+ write_sample<1>(frame, x / 2, y / 2, (unsigned short)(chroma.y << 6)); -+ write_sample<2>(frame, x / 2, y / 2, (unsigned short)(chroma.z << 6)); -+} -+ -+// Generic write functions -+static __inline__ __device__ void write_2x2(const FFCUDAFrame& frame, int x, int y, ushort3 a, ushort3 b, ushort3 c, ushort3 d, ushort3 chroma) -+{ -+ if (fmt_dst == AV_PIX_FMT_YUV420P) -+ write_yuv420p_2x2(frame, x, y, a, b, c, d, chroma); -+ else if (fmt_dst == AV_PIX_FMT_NV12) -+ write_nv12_2x2(frame, x, y, a, b, c, d, chroma); -+ else if (fmt_dst == AV_PIX_FMT_P016) -+ write_p016_2x2(frame, x, y, a, b, c, d, chroma); -+ else if (fmt_dst == AV_PIX_FMT_P010) -+ write_p010_2x2(frame, x, y, a, b, c, d, chroma); -+} -+ -+static __inline__ __device__ unsigned short sample_to_ushort(float flt) -+{ -+ return (unsigned short)(flt * ((1 << depth_dst) - 1)); -+} -+ -+static __inline__ __device__ ushort3 pixel_to_ushort3(float3 flt) -+{ -+ return make_ushort3(sample_to_ushort(flt.x), -+ sample_to_ushort(flt.y), -+ sample_to_ushort(flt.z)); -+} -+ -+static __inline__ __device__ void write_2x2_flt(const FFCUDAFrame& frame, int x, int y, float3 a, float3 b, float3 c, float3 d) -+{ -+ float3 chroma = get_chroma_sample(a, b, c, d); -+ -+ ushort3 ia = pixel_to_ushort3(a); -+ ushort3 ib = pixel_to_ushort3(b); -+ ushort3 ic = pixel_to_ushort3(c); -+ ushort3 id = pixel_to_ushort3(d); -+ -+ ushort3 ichroma = pixel_to_ushort3(chroma); -+ -+ write_2x2(frame, x, y, ia, ib, ic, id, ichroma); -+} -+ -+#endif /* AVFILTER_CUDA_PIXFMT_H */ -+ -Index: jellyfin-ffmpeg/libavfilter/cuda/shared.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/shared.h -@@ -0,0 +1,32 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVFILTER_CUDA_SHARED_H -+#define AVFILTER_CUDA_SHARED_H -+ -+typedef struct FFCUDAFrame { -+ unsigned char *data[4]; -+ int linesize[4]; -+ -+ int width, height; -+ -+ float peak; -+} FFCUDAFrame; -+ -+#endif /* AVFILTER_CUDA_SHARED_H */ -+ -Index: jellyfin-ffmpeg/libavfilter/cuda/tonemap.cu -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/tonemap.cu -@@ -0,0 +1,201 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include "colorspace_common.h" -+#include "pixfmt.h" -+#include "tonemap.h" -+#include "util.h" -+ -+extern const enum TonemapAlgorithm tonemap_func; -+extern const float tone_param; -+extern const float desat_param; -+ -+#define mix(x, y, a) ((x) + ((y) - (x)) * (a)) -+ -+static __inline__ __device__ -+float hable_f(float in) { -+ float a = 0.15f, b = 0.50f, c = 0.10f, d = 0.20f, e = 0.02f, f = 0.30f; -+ return (in * (in * a + b * c) + d * e) / (in * (in * a + b) + d * f) - e / f; -+} -+ -+static __inline__ __device__ -+float direct(float s, float peak) { -+ return s; -+} -+ -+static __inline__ __device__ -+float linear(float s, float peak) { -+ return s * tone_param / peak; -+} -+ -+static __inline__ __device__ -+float gamma(float s, float peak) { -+ float p = s > 0.05f ? s / peak : 0.05f / peak; -+ float v = __powf(p, 1.0f / tone_param); -+ return s > 0.05f ? v : (s * v / 0.05f); -+} -+ -+static __inline__ __device__ -+float clip(float s, float peak) { -+ return clamp(s * tone_param, 0.0f, 1.0f); -+} -+ -+static __inline__ __device__ -+float reinhard(float s, float peak) { -+ return s / (s + tone_param) * (peak + tone_param) / peak; -+} -+ -+static __inline__ __device__ -+float hable(float s, float peak) { -+ return hable_f(s) / hable_f(peak); -+} -+ -+static __inline__ __device__ -+float mobius(float s, float peak) { -+ float j = tone_param; -+ float a, b; -+ -+ if (s <= j) -+ return s; -+ -+ a = -j * j * (peak - 1.0f) / (j * j - 2.0f * j + peak); -+ b = (j * j - 2.0f * j * peak + peak) / max(peak - 1.0f, FLOAT_EPS); -+ -+ return (b * b + 2.0f * b * j + j * j) / (b - a) * (s + a) / (s + b); -+} -+ -+static __inline__ __device__ -+float bt2390(float s, float peak, float dst_peak) { -+ float peak_pq = inverse_eotf_st2084(peak); -+ float scale = 1.0f / peak_pq; -+ -+ float s_pq = inverse_eotf_st2084(s) * scale; -+ float maxLum = inverse_eotf_st2084(dst_peak) * scale; -+ -+ float ks = 1.5f * maxLum - 0.5f; -+ float tb = (s_pq - ks) / (1.0f - ks); -+ float tb2 = tb * tb; -+ float tb3 = tb2 * tb; -+ float pb = (2.0f * tb3 - 3.0f * tb2 + 1.0f) * ks + -+ (tb3 - 2.0f * tb2 + tb) * (1.0f - ks) + -+ (-2.0f * tb3 + 3.0f * tb2) * maxLum; -+ float sig = (s_pq < ks) ? s_pq : pb; -+ -+ return eotf_st2084(sig * peak_pq); -+} -+ -+static __inline__ __device__ -+float map(float s, float peak, float dst_peak) -+{ -+ switch (tonemap_func) { -+ case TONEMAP_NONE: -+ default: -+ return direct(s, peak); -+ case TONEMAP_LINEAR: -+ return linear(s, peak); -+ case TONEMAP_GAMMA: -+ return gamma(s, peak); -+ case TONEMAP_CLIP: -+ return clip(s, peak); -+ case TONEMAP_REINHARD: -+ return reinhard(s, peak); -+ case TONEMAP_HABLE: -+ return hable(s, peak); -+ case TONEMAP_MOBIUS: -+ return mobius(s, peak); -+ case TONEMAP_BT2390: -+ return bt2390(s, peak, dst_peak); -+ } -+} -+ -+static __inline__ __device__ -+float3 map_one_pixel_rgb(float3 rgb, const FFCUDAFrame& src, const FFCUDAFrame& dst) { -+ float sig = max(max(rgb.x, max(rgb.y, rgb.z)), FLOAT_EPS); -+ float peak = src.peak; -+ float dst_peak = dst.peak; -+ -+ // Rescale the variables in order to bring it into a representation where -+ // 1.0 represents the dst_peak. This is because all of the tone mapping -+ // algorithms are defined in such a way that they map to the range [0.0, 1.0]. -+ if (dst.peak > 1.0f) { -+ sig *= 1.0f / dst.peak; -+ peak *= 1.0f / dst.peak; -+ } -+ -+ float sig_old = sig; -+ -+ // Desaturate the color using a coefficient dependent on the signal level -+ if (desat_param > 0.0f) { -+ float luma = get_luma_dst(rgb, luma_dst); -+ float coeff = max(sig - 0.18f, FLOAT_EPS) / max(sig, FLOAT_EPS); -+ coeff = __powf(coeff, 10.0f / desat_param); -+ rgb = mix(rgb, make_float3(luma, luma, luma), make_float3(coeff, coeff, coeff)); -+ } -+ -+ sig = map(sig, peak, dst_peak); -+ -+ sig = min(sig, 1.0f); -+ rgb = rgb * (sig / sig_old); -+ return rgb; -+} -+ -+// Map from source space YUV to destination space RGB -+static __inline__ __device__ -+float3 map_to_dst_space_from_yuv(float3 yuv, float peak) { -+ float3 c = yuv2lrgb(yuv); -+ c = lrgb2lrgb(c); -+ return c; -+} -+ -+extern "C" { -+ -+__global__ void tonemap(FFCUDAFrame src, FFCUDAFrame dst) -+{ -+ int xi = blockIdx.x * blockDim.x + threadIdx.x; -+ int yi = blockIdx.y * blockDim.y + threadIdx.y; -+ // each work item process four pixels -+ int x = 2 * xi; -+ int y = 2 * yi; -+ -+ if (y + 1 < src.height && x + 1 < src.width) -+ { -+ float3 yuv0 = read_px_flt(src, x, y); -+ float3 yuv1 = read_px_flt(src, x + 1, y); -+ float3 yuv2 = read_px_flt(src, x, y + 1); -+ float3 yuv3 = read_px_flt(src, x + 1, y + 1); -+ -+ float3 c0 = map_to_dst_space_from_yuv(yuv0, src.peak); -+ float3 c1 = map_to_dst_space_from_yuv(yuv1, src.peak); -+ float3 c2 = map_to_dst_space_from_yuv(yuv2, src.peak); -+ float3 c3 = map_to_dst_space_from_yuv(yuv3, src.peak); -+ -+ c0 = map_one_pixel_rgb(c0, src, dst); -+ c1 = map_one_pixel_rgb(c1, src, dst); -+ c2 = map_one_pixel_rgb(c2, src, dst); -+ c3 = map_one_pixel_rgb(c3, src, dst); -+ -+ yuv0 = lrgb2yuv(c0); -+ yuv1 = lrgb2yuv(c1); -+ yuv2 = lrgb2yuv(c2); -+ yuv3 = lrgb2yuv(c3); -+ -+ write_2x2_flt(dst, x, y, yuv0, yuv1, yuv2, yuv3); -+ } -+} -+ -+} -Index: jellyfin-ffmpeg/libavfilter/cuda/tonemap.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/tonemap.h -@@ -0,0 +1,35 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVFILTER_CUDA_TONEMAP_H -+#define AVFILTER_CUDA_TONEMAP_H -+ -+enum TonemapAlgorithm { -+ TONEMAP_NONE, -+ TONEMAP_LINEAR, -+ TONEMAP_GAMMA, -+ TONEMAP_CLIP, -+ TONEMAP_REINHARD, -+ TONEMAP_HABLE, -+ TONEMAP_MOBIUS, -+ TONEMAP_BT2390, -+ TONEMAP_MAX, -+}; -+ -+#endif /* AVFILTER_CUDA_TONEMAP_H */ -+ -Index: jellyfin-ffmpeg/libavfilter/cuda/util.h -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/cuda/util.h -@@ -0,0 +1,55 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#ifndef AVFILTER_CUDA_UTIL_H -+#define AVFILTER_CUDA_UTIL_H -+ -+static inline __device__ float3 operator+(const float3 &a, const float3 &b) { -+ return make_float3(a.x + b.x, a.y + b.y, a.z + b.z); -+} -+ -+static inline __device__ float3 operator+(const float3 &a, float b) { -+ return make_float3(a.x + b, a.y + b, a.z + b); -+} -+ -+static inline __device__ float3 operator-(const float3 &a, const float3 &b) { -+ return make_float3(a.x - b.x, a.y - b.y, a.z - b.z); -+} -+ -+static inline __device__ float3 operator-(const float3 &a, float b) { -+ return make_float3(a.x - b, a.y - b, a.z - b); -+} -+ -+static inline __device__ float3 operator*(const float3 &a, const float3 &b) { -+ return make_float3(a.x * b.x, a.y * b.y, a.z * b.z); -+} -+ -+static inline __device__ float3 operator*(const float3 &a, float b) { -+ return make_float3(a.x * b, a.y * b, a.z * b); -+} -+ -+static inline __device__ float3 operator/(const float3 &a, const float3 &b) { -+ return make_float3(a.x / b.x, a.y / b.y, a.z / b.z); -+} -+ -+static inline __device__ float3 operator/(const float3 &a, float b) { -+ return make_float3(a.x / b, a.y / b, a.z / b); -+} -+ -+#endif /* AVFILTER_CUDA_UTIL_H */ -+ -Index: jellyfin-ffmpeg/libavfilter/vf_tonemap_cuda.c -=================================================================== ---- /dev/null -+++ jellyfin-ffmpeg/libavfilter/vf_tonemap_cuda.c -@@ -0,0 +1,712 @@ -+/* -+ * This file is part of FFmpeg. -+ * -+ * FFmpeg is free software; you can redistribute it and/or -+ * modify it under the terms of the GNU Lesser General Public -+ * License as published by the Free Software Foundation; either -+ * version 2.1 of the License, or (at your option) any later version. -+ * -+ * FFmpeg is distributed in the hope that it will be useful, -+ * but WITHOUT ANY WARRANTY; without even the implied warranty of -+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU -+ * Lesser General Public License for more details. -+ * -+ * You should have received a copy of the GNU Lesser General Public -+ * License along with FFmpeg; if not, write to the Free Software -+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA -+ */ -+ -+#include -+#include -+#include -+ -+#include "libavutil/avassert.h" -+#include "libavutil/avstring.h" -+#include "libavutil/bprint.h" -+#include "libavutil/common.h" -+#include "libavutil/hwcontext.h" -+#include "libavutil/hwcontext_cuda_internal.h" -+#include "libavutil/cuda_check.h" -+#include "libavutil/internal.h" -+#include "libavutil/opt.h" -+#include "libavutil/pixdesc.h" -+ -+#include "avfilter.h" -+#include "colorspace.h" -+#include "cuda/host_util.h" -+#include "cuda/shared.h" -+#include "cuda/tonemap.h" -+#include "formats.h" -+#include "internal.h" -+#include "scale_eval.h" -+#include "video.h" -+ -+static const enum AVPixelFormat supported_formats[] = { -+ AV_PIX_FMT_YUV420P, -+ AV_PIX_FMT_NV12, -+ AV_PIX_FMT_P010, -+ AV_PIX_FMT_P016 -+}; -+ -+#define DIV_UP(a, b) ( ((a) + (b) - 1) / (b) ) -+#define ALIGN_UP(a, b) (((a) + (b) - 1) & ~((b) - 1)) -+#define NUM_BUFFERS 2 -+#define BLOCKX 32 -+#define BLOCKY 16 -+ -+#define CHECK_CU(x) FF_CUDA_CHECK_DL(ctx, s->hwctx->internal->cuda_dl, x) -+ -+typedef struct TonemapCUDAContext { -+ const AVClass *class; -+ -+ AVCUDADeviceContext *hwctx; -+ -+ enum AVPixelFormat in_fmt, out_fmt; -+ -+ enum AVColorTransferCharacteristic trc, in_trc, out_trc; -+ enum AVColorSpace spc, in_spc, out_spc; -+ enum AVColorPrimaries pri, in_pri, out_pri; -+ enum AVColorRange range, in_range, out_range; -+ enum AVChromaLocation in_chroma_loc, out_chroma_loc; -+ -+ AVBufferRef *frames_ctx; -+ AVFrame *frame; -+ -+ AVFrame *tmp_frame; -+ -+ /** -+ * Output sw format. AV_PIX_FMT_NONE for no conversion. -+ */ -+ enum AVPixelFormat format; -+ char *format_str; -+ -+ CUcontext cu_ctx; -+ CUmodule cu_module; -+ -+ CUfunction cu_func; -+ -+ CUdeviceptr srcBuffer; -+ CUdeviceptr dstBuffer; -+ -+ enum TonemapAlgorithm tonemap; -+ double param; -+ double desat_param; -+ double peak; -+ double dst_peak; -+ double scene_threshold; -+ -+ const AVPixFmtDescriptor *in_desc, *out_desc; -+} TonemapCUDAContext; -+ -+static av_cold int init(AVFilterContext *ctx) -+{ -+ TonemapCUDAContext *s = ctx->priv; -+ -+ if (!strcmp(s->format_str, "same")) { -+ s->format = AV_PIX_FMT_NONE; -+ } else { -+ s->format = av_get_pix_fmt(s->format_str); -+ if (s->format == AV_PIX_FMT_NONE) { -+ av_log(ctx, AV_LOG_ERROR, "Unrecognized pixel format: %s\n", s->format_str); -+ return AVERROR(EINVAL); -+ } -+ } -+ -+ s->frame = av_frame_alloc(); -+ if (!s->frame) -+ return AVERROR(ENOMEM); -+ -+ s->tmp_frame = av_frame_alloc(); -+ if (!s->tmp_frame) -+ return AVERROR(ENOMEM); -+ -+ return 0; -+} -+ -+static av_cold void uninit(AVFilterContext *ctx) -+{ -+ TonemapCUDAContext *s = ctx->priv; -+ -+ if (s->hwctx) { -+ CudaFunctions *cu = s->hwctx->internal->cuda_dl; -+ CUcontext dummy, cuda_ctx = s->hwctx->cuda_ctx; -+ -+ CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); -+ -+ if (s->cu_module) { -+ CHECK_CU(cu->cuModuleUnload(s->cu_module)); -+ s->cu_func = NULL; -+ s->cu_module = NULL; -+ } -+ -+ CHECK_CU(cu->cuCtxPopCurrent(&dummy)); -+ } -+ -+ av_frame_free(&s->frame); -+ av_buffer_unref(&s->frames_ctx); -+ av_frame_free(&s->tmp_frame); -+} -+ -+static int query_formats(AVFilterContext *ctx) -+{ -+ static const enum AVPixelFormat pixel_formats[] = { -+ AV_PIX_FMT_CUDA, AV_PIX_FMT_NONE, -+ }; -+ AVFilterFormats *pix_fmts = ff_make_format_list(pixel_formats); -+ -+ return ff_set_common_formats(ctx, pix_fmts); -+} -+ -+static av_cold int init_stage(TonemapCUDAContext *s, AVBufferRef *device_ctx, -+ AVFilterLink *outlink) -+{ -+ AVBufferRef *out_ref = NULL; -+ AVHWFramesContext *out_ctx; -+ int ret; -+ -+ out_ref = av_hwframe_ctx_alloc(device_ctx); -+ if (!out_ref) -+ return AVERROR(ENOMEM); -+ out_ctx = (AVHWFramesContext*)out_ref->data; -+ -+ out_ctx->format = AV_PIX_FMT_CUDA; -+ out_ctx->sw_format = s->out_fmt; -+ out_ctx->width = FFALIGN(outlink->w, 32); -+ out_ctx->height = FFALIGN(outlink->h, 32); -+ -+ ret = av_hwframe_ctx_init(out_ref); -+ if (ret < 0) -+ goto fail; -+ -+ av_frame_unref(s->frame); -+ ret = av_hwframe_get_buffer(out_ref, s->frame, 0); -+ if (ret < 0) -+ goto fail; -+ -+ s->frame->width = outlink->w; -+ s->frame->height = outlink->h; -+ -+ av_buffer_unref(&s->frames_ctx); -+ s->frames_ctx = out_ref; -+ -+ return 0; -+fail: -+ av_buffer_unref(&out_ref); -+ return ret; -+} -+ -+static int format_is_supported(enum AVPixelFormat fmt) -+{ -+ int i; -+ -+ for (i = 0; i < FF_ARRAY_ELEMS(supported_formats); i++) -+ if (supported_formats[i] == fmt) -+ return 1; -+ return 0; -+} -+ -+static av_cold int init_processing_chain(AVFilterContext *ctx, AVFilterLink *outlink) -+{ -+ TonemapCUDAContext *s = ctx->priv; -+ -+ AVHWFramesContext *in_frames_ctx; -+ -+ enum AVPixelFormat in_format; -+ enum AVPixelFormat out_format; -+ const AVPixFmtDescriptor *in_desc; -+ const AVPixFmtDescriptor *out_desc; -+ int ret; -+ -+ /* check that we have a hw context */ -+ if (!ctx->inputs[0]->hw_frames_ctx) { -+ av_log(ctx, AV_LOG_ERROR, "No hw context provided on input\n"); -+ return AVERROR(EINVAL); -+ } -+ in_frames_ctx = (AVHWFramesContext*)ctx->inputs[0]->hw_frames_ctx->data; -+ in_format = in_frames_ctx->sw_format; -+ out_format = (s->format == AV_PIX_FMT_NONE) ? in_format : s->format; -+ in_desc = av_pix_fmt_desc_get(in_format); -+ out_desc = av_pix_fmt_desc_get(out_format); -+ -+ if (!format_is_supported(in_format)) { -+ av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n", -+ av_get_pix_fmt_name(in_format)); -+ return AVERROR(ENOSYS); -+ } -+ if (!format_is_supported(out_format)) { -+ av_log(ctx, AV_LOG_ERROR, "Unsupported output format: %s\n", -+ av_get_pix_fmt_name(out_format)); -+ return AVERROR(ENOSYS); -+ } -+ if (!(in_desc->comp[0].depth == 10 || -+ in_desc->comp[0].depth == 16)) { -+ av_log(ctx, AV_LOG_ERROR, "Unsupported input format depth: %d\n", -+ in_desc->comp[0].depth); -+ return AVERROR(ENOSYS); -+ } -+ -+ s->in_fmt = in_format; -+ s->out_fmt = out_format; -+ s->in_desc = in_desc; -+ s->out_desc = out_desc; -+ -+ ret = init_stage(s, in_frames_ctx->device_ref, outlink); -+ if (ret < 0) -+ return ret; -+ -+ ctx->outputs[0]->hw_frames_ctx = av_buffer_ref(s->frames_ctx); -+ if (!ctx->outputs[0]->hw_frames_ctx) -+ return AVERROR(ENOMEM); -+ -+ return 0; -+} -+ -+static const struct PrimaryCoefficients primaries_table[AVCOL_PRI_NB] = { -+ [AVCOL_PRI_BT709] = { 0.640, 0.330, 0.300, 0.600, 0.150, 0.060 }, -+ [AVCOL_PRI_BT2020] = { 0.708, 0.292, 0.170, 0.797, 0.131, 0.046 }, -+}; -+ -+static const struct WhitepointCoefficients whitepoint_table[AVCOL_PRI_NB] = { -+ [AVCOL_PRI_BT709] = { 0.3127, 0.3290 }, -+ [AVCOL_PRI_BT2020] = { 0.3127, 0.3290 }, -+}; -+ -+static int get_rgb2rgb_matrix(enum AVColorPrimaries in, enum AVColorPrimaries out, -+ double rgb2rgb[3][3]) { -+ double rgb2xyz[3][3], xyz2rgb[3][3]; -+ -+ ff_fill_rgb2xyz_table(&primaries_table[out], &whitepoint_table[out], rgb2xyz); -+ ff_matrix_invert_3x3(rgb2xyz, xyz2rgb); -+ ff_fill_rgb2xyz_table(&primaries_table[in], &whitepoint_table[in], rgb2xyz); -+ ff_matrix_mul_3x3(rgb2rgb, rgb2xyz, xyz2rgb); -+ -+ return 0; -+} -+ -+static av_cold int compile(AVFilterLink *inlink) -+{ -+ int ret = 0; -+ AVFilterContext *ctx = inlink->dst; -+ TonemapCUDAContext *s = ctx->priv; -+ CudaFunctions *cu = s->hwctx->internal->cuda_dl; -+ CUcontext dummy, cuda_ctx = s->hwctx->cuda_ctx; -+ AVBPrint constants; -+ CUlinkState link_state; -+ void *cubin; -+ size_t cubin_size; -+ double rgb_matrix[3][3], yuv_matrix[3][3], rgb2rgb_matrix[3][3]; -+ const struct LumaCoefficients *in_coeffs, *out_coeffs; -+ enum AVColorTransferCharacteristic in_trc = s->in_trc, out_trc = s->out_trc; -+ enum AVColorSpace in_spc = s->in_spc, out_spc = s->out_spc; -+ enum AVColorPrimaries in_pri = s->in_pri, out_pri = s->out_pri; -+ enum AVColorRange in_range = s->in_range, out_range = s->out_range; -+ char info_log[4096], error_log[4096]; -+ CUjit_option options[] = {CU_JIT_INFO_LOG_BUFFER, CU_JIT_ERROR_LOG_BUFFER, CU_JIT_INFO_LOG_BUFFER_SIZE_BYTES, CU_JIT_ERROR_LOG_BUFFER_SIZE_BYTES}; -+ void *option_values[] = {&info_log, &error_log, (void*)(intptr_t)sizeof(info_log), (void*)(intptr_t)sizeof(error_log)}; -+ -+ extern char tonemap_ptx[]; -+ -+ switch(s->tonemap) { -+ case TONEMAP_GAMMA: -+ if (isnan(s->param)) -+ s->param = 1.8f; -+ break; -+ case TONEMAP_REINHARD: -+ if (!isnan(s->param)) -+ s->param = (1.0f - s->param) / s->param; -+ break; -+ case TONEMAP_MOBIUS: -+ if (isnan(s->param)) -+ s->param = 0.3f; -+ break; -+ } -+ -+ if (isnan(s->param)) -+ s->param = 1.0f; -+ -+ s->dst_peak = 1.0f; -+ -+ if (in_trc == AVCOL_TRC_UNSPECIFIED) -+ in_trc = AVCOL_TRC_SMPTE2084; -+ if (out_trc == AVCOL_TRC_UNSPECIFIED) -+ out_trc = AVCOL_TRC_BT709; -+ -+ if (in_spc == AVCOL_SPC_UNSPECIFIED) -+ in_spc = AVCOL_SPC_BT2020_NCL; -+ if (out_spc == AVCOL_SPC_UNSPECIFIED) -+ out_spc = AVCOL_SPC_BT709; -+ -+ if (in_pri == AVCOL_PRI_UNSPECIFIED) -+ in_pri = AVCOL_PRI_BT2020; -+ if (out_pri == AVCOL_PRI_UNSPECIFIED) -+ out_pri = AVCOL_PRI_BT709; -+ -+ if (in_range == AVCOL_RANGE_UNSPECIFIED) -+ in_range = AVCOL_RANGE_MPEG; -+ if (out_range == AVCOL_RANGE_UNSPECIFIED) -+ out_range = AVCOL_RANGE_MPEG; -+ -+ av_log(ctx, AV_LOG_DEBUG, "Tonemapping transfer from %s to %s\n", -+ av_color_transfer_name(in_trc), -+ av_color_transfer_name(out_trc)); -+ av_log(ctx, AV_LOG_DEBUG, "Mapping colorspace from %s to %s\n", -+ av_color_space_name(in_spc), -+ av_color_space_name(out_spc)); -+ av_log(ctx, AV_LOG_DEBUG, "Mapping primaries from %s to %s\n", -+ av_color_primaries_name(in_pri), -+ av_color_primaries_name(out_pri)); -+ av_log(ctx, AV_LOG_DEBUG, "Mapping range from %s to %s\n", -+ av_color_range_name(in_range), -+ av_color_range_name(out_range)); -+ -+ if (!(in_coeffs = ff_get_luma_coefficients(in_spc))) -+ return AVERROR(EINVAL); -+ -+ ff_fill_rgb2yuv_table(in_coeffs, yuv_matrix); -+ ff_matrix_invert_3x3(yuv_matrix, rgb_matrix); -+ -+ if (!(out_coeffs = ff_get_luma_coefficients(out_spc))) -+ return AVERROR(EINVAL); -+ -+ ff_fill_rgb2yuv_table(out_coeffs, yuv_matrix); -+ -+ if ((ret = get_rgb2rgb_matrix(in_pri, out_pri, rgb2rgb_matrix)) < 0) -+ return ret; -+ -+ av_bprint_init(&constants, 2048, AV_BPRINT_SIZE_UNLIMITED); -+ -+ av_bprintf(&constants, ".version 3.2\n"); -+ av_bprintf(&constants, ".target sm_30\n"); -+ av_bprintf(&constants, ".address_size %zu\n", sizeof(void*) * 8); -+ -+#define CONSTANT_A(decl, align, ...) \ -+ av_bprintf(&constants, ".visible .const .align " #align " " decl ";\n", __VA_ARGS__) -+#define CONSTANT(decl, ...) CONSTANT_A(decl, 4, __VA_ARGS__) -+#define CONSTANT_M(a, b) \ -+ CONSTANT(".f32 " a "[] = {%f, %f, %f, %f, %f, %f, %f, %f, %f}", \ -+ b[0][0], b[0][1], b[0][2], \ -+ b[1][0], b[1][1], b[1][2], \ -+ b[2][0], b[2][1], b[2][2]) -+#define CONSTANT_C(a, b) \ -+ CONSTANT(".f32 " a "[] = {%f, %f, %f}", \ -+ b->cr, b->cg, b->cb) -+ -+ CONSTANT(".u32 depth_src = %i", (int)s->in_desc->comp[0].depth); -+ CONSTANT(".u32 depth_dst = %i", (int)s->out_desc->comp[0].depth); -+ CONSTANT(".u32 fmt_src = %i", (int)s->in_fmt); -+ CONSTANT(".u32 fmt_dst = %i", (int)s->out_fmt); -+ CONSTANT(".u32 range_src = %i", (int)in_range); -+ CONSTANT(".u32 range_dst = %i", (int)out_range); -+ CONSTANT(".u32 trc_src = %i", (int)in_trc); -+ CONSTANT(".u32 trc_dst = %i", (int)out_trc); -+ CONSTANT(".u32 chroma_loc_src = %i", (int)s->in_chroma_loc); -+ CONSTANT(".u32 chroma_loc_dst = %i", (int)s->out_chroma_loc); -+ CONSTANT(".u32 tonemap_func = %i", (int)s->tonemap); -+ CONSTANT(".f32 tone_param = %f", s->param); -+ CONSTANT(".f32 desat_param = %f", s->desat_param); -+ CONSTANT_M("rgb_matrix", rgb_matrix); -+ CONSTANT_M("yuv_matrix", yuv_matrix); -+ CONSTANT_A(".u8 rgb2rgb_passthrough = %i", 1, in_pri == out_pri); -+ CONSTANT_M("rgb2rgb_matrix", rgb2rgb_matrix); -+ CONSTANT_C("luma_src", in_coeffs); -+ CONSTANT_C("luma_dst", out_coeffs); -+ -+ ret = CHECK_CU(cu->cuCtxPushCurrent(cuda_ctx)); -+ if (ret < 0) -+ return ret; -+ -+ if (s->cu_module) { -+ ret = CHECK_CU(cu->cuModuleUnload(s->cu_module)); -+ if (ret < 0) -+ goto fail; -+ -+ s->cu_func = NULL; -+ s->cu_module = NULL; -+ } -+ -+ ret = CHECK_CU(cu->cuLinkCreate(sizeof(options) / sizeof(options[0]), options, option_values, &link_state)); -+ if (ret < 0) -+ goto fail; -+ -+ ret = CHECK_CU(cu->cuLinkAddData(link_state, CU_JIT_INPUT_PTX, constants.str, -+ constants.len, "constants", 0, NULL, NULL)); -+ if (ret < 0) -+ goto fail2; -+ -+ ret = CHECK_CU(cu->cuLinkAddData(link_state, CU_JIT_INPUT_PTX, tonemap_ptx, -+ strlen(tonemap_ptx), "tonemap.ptx", 0, NULL, NULL)); -+ if (ret < 0) -+ goto fail2; -+ -+ ret = CHECK_CU(cu->cuLinkComplete(link_state, &cubin, &cubin_size)); -+ if (ret < 0) -+ goto fail2; -+ -+ ret = CHECK_CU(cu->cuModuleLoadData(&s->cu_module, cubin)); -+ if (ret < 0) -+ goto fail2; -+ -+ CHECK_CU(cu->cuModuleGetFunction(&s->cu_func, s->cu_module, "tonemap")); -+ if (ret < 0) -+ goto fail2; -+ -+fail2: -+ CHECK_CU(cu->cuLinkDestroy(link_state)); -+ -+fail: -+ CHECK_CU(cu->cuCtxPopCurrent(&dummy)); -+ -+ av_bprint_finalize(&constants, NULL); -+ -+ if ((intptr_t)option_values[2] > 0) -+ av_log(ctx, AV_LOG_INFO, "CUDA linker output: %.*s\n", (int)(intptr_t)option_values[2], info_log); -+ -+ if ((intptr_t)option_values[3] > 0) -+ av_log(ctx, AV_LOG_ERROR, "CUDA linker output: %.*s\n", (int)(intptr_t)option_values[3], error_log); -+ -+ return ret; -+} -+ -+static av_cold int config_props(AVFilterLink *outlink) -+{ -+ AVFilterContext *ctx = outlink->src; -+ AVFilterLink *inlink = outlink->src->inputs[0]; -+ AVHWFramesContext *frames_ctx = (AVHWFramesContext*)inlink->hw_frames_ctx->data; -+ AVCUDADeviceContext *device_hwctx = frames_ctx->device_ctx->hwctx; -+ TonemapCUDAContext *s = ctx->priv; -+ int ret; -+ -+ s->hwctx = device_hwctx; -+ -+ outlink->w = inlink->w; -+ outlink->h = inlink->h; -+ -+ ret = init_processing_chain(ctx, outlink); -+ if (ret < 0) -+ return ret; -+ -+ outlink->sample_aspect_ratio = inlink->sample_aspect_ratio; -+ -+ return 0; -+} -+ -+static int run_kernel(AVFilterContext *ctx, -+ AVFrame *out, AVFrame *in) -+{ -+ TonemapCUDAContext *s = ctx->priv; -+ CudaFunctions *cu = s->hwctx->internal->cuda_dl; -+ FFCUDAFrame src, dst; -+ void *args_uchar[] = { &src, &dst }; -+ int ret; -+ -+ ret = ff_make_cuda_frame(&src, in); -+ if (ret < 0) -+ goto fail; -+ -+ ret = ff_make_cuda_frame(&dst, out); -+ if (ret < 0) -+ goto fail; -+ -+ src.peak = s->peak; -+ if (!src.peak) { -+ src.peak = ff_determine_signal_peak(in); -+ av_log(s, AV_LOG_DEBUG, "Computed signal peak: %f\n", src.peak); -+ } -+ -+ dst.peak = s->dst_peak; -+ -+ ret = CHECK_CU(cu->cuLaunchKernel(s->cu_func, -+ DIV_UP(src.width / 2, BLOCKX), DIV_UP(src.height / 2, BLOCKY), 1, -+ BLOCKX, BLOCKY, 1, 0, s->hwctx->stream, args_uchar, NULL)); -+ -+fail: -+ return ret; -+} -+ -+static int do_tonemap(AVFilterContext *ctx, AVFrame *out, AVFrame *in) -+{ -+ TonemapCUDAContext *s = ctx->priv; -+ AVFrame *src = in; -+ int ret; -+ -+ ret = run_kernel(ctx, s->frame, src); -+ if (ret < 0) -+ return ret; -+ -+ src = s->frame; -+ ret = av_hwframe_get_buffer(src->hw_frames_ctx, s->tmp_frame, 0); -+ if (ret < 0) -+ return ret; -+ -+ av_frame_move_ref(out, s->frame); -+ av_frame_move_ref(s->frame, s->tmp_frame); -+ -+ s->frame->width = in->width; -+ s->frame->height = in->height; -+ -+ ret = av_frame_copy_props(out, in); -+ if (ret < 0) -+ return ret; -+ -+ if (s->out_trc != out->color_trc || -+ s->out_spc != out->colorspace || -+ s->out_pri != out->color_primaries || -+ s->out_range != out->color_range || -+ s->out_chroma_loc != out->chroma_location) { -+ out->color_trc = s->out_trc; -+ out->colorspace = s->out_spc; -+ out->color_primaries = s->out_pri; -+ out->color_range = s->out_range; -+ out->chroma_location = s->out_chroma_loc; -+ } -+ -+ return 0; -+} -+ -+static int filter_frame(AVFilterLink *link, AVFrame *in) -+{ -+ AVFilterContext *ctx = link->dst; -+ TonemapCUDAContext *s = ctx->priv; -+ AVFilterLink *outlink = ctx->outputs[0]; -+ CudaFunctions *cu = s->hwctx->internal->cuda_dl; -+ -+ AVFrame *out = NULL; -+ CUcontext dummy; -+ int ret = 0; -+ -+ out = av_frame_alloc(); -+ if (!out) { -+ ret = AVERROR(ENOMEM); -+ goto fail; -+ } -+ -+ if (!(in->color_trc == AVCOL_TRC_SMPTE2084 || -+ in->color_trc == AVCOL_TRC_ARIB_STD_B67)) { -+ av_log(ctx, AV_LOG_ERROR, "Unsupported input transfer characteristic: %s\n", -+ av_color_transfer_name(in->color_trc)); -+ ret = AVERROR(EINVAL); -+ goto fail; -+ } -+ -+ if (!s->cu_func || -+ s->in_trc != in->color_trc || -+ s->in_spc != in->colorspace || -+ s->in_pri != in->color_primaries || -+ s->in_range != in->color_range || -+ s->in_chroma_loc != in->chroma_location) { -+ s->in_trc = in->color_trc; -+ s->in_spc = in->colorspace; -+ s->in_pri = in->color_primaries; -+ s->in_range = in->color_range; -+ s->in_chroma_loc = in->chroma_location; -+ -+ s->out_trc = s->trc; -+ s->out_spc = s->spc; -+ s->out_pri = s->pri; -+ s->out_range = s->range; -+ s->out_chroma_loc = s->in_chroma_loc; -+ -+ if ((ret = compile(link)) < 0) -+ goto fail; -+ } -+ -+ ret = CHECK_CU(cu->cuCtxPushCurrent(s->hwctx->cuda_ctx)); -+ if (ret < 0) -+ goto fail; -+ -+ ret = do_tonemap(ctx, out, in); -+ -+ CHECK_CU(cu->cuCtxPopCurrent(&dummy)); -+ if (ret < 0) -+ goto fail; -+ -+ av_frame_free(&in); -+ -+ ff_update_hdr_metadata(out, s->dst_peak); -+ -+ return ff_filter_frame(outlink, out); -+fail: -+ av_frame_free(&in); -+ av_frame_free(&out); -+ return ret; -+} -+ -+#define OFFSET(x) offsetof(TonemapCUDAContext, x) -+#define FLAGS (AV_OPT_FLAG_FILTERING_PARAM|AV_OPT_FLAG_VIDEO_PARAM) -+static const AVOption options[] = { -+ { "tonemap", "tonemap algorithm selection", OFFSET(tonemap), AV_OPT_TYPE_INT, {.i64 = TONEMAP_NONE}, TONEMAP_NONE, TONEMAP_MAX - 1, FLAGS, "tonemap" }, -+ { "none", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_NONE}, 0, 0, FLAGS, "tonemap" }, -+ { "linear", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_LINEAR}, 0, 0, FLAGS, "tonemap" }, -+ { "gamma", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_GAMMA}, 0, 0, FLAGS, "tonemap" }, -+ { "clip", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_CLIP}, 0, 0, FLAGS, "tonemap" }, -+ { "reinhard", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_REINHARD}, 0, 0, FLAGS, "tonemap" }, -+ { "hable", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_HABLE}, 0, 0, FLAGS, "tonemap" }, -+ { "mobius", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_MOBIUS}, 0, 0, FLAGS, "tonemap" }, -+ { "bt2390", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_BT2390}, 0, 0, FLAGS, "tonemap" }, -+ { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, -+ { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, -+ { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709}, 0, 0, FLAGS, "transfer" }, -+ { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT2020_10}, 0, 0, FLAGS, "transfer" }, -+ { "matrix", "set colorspace matrix", OFFSET(spc), AV_OPT_TYPE_INT, {.i64 = AVCOL_SPC_BT709}, -1, INT_MAX, FLAGS, "matrix" }, -+ { "m", "set colorspace matrix", OFFSET(spc), AV_OPT_TYPE_INT, {.i64 = AVCOL_SPC_BT709}, -1, INT_MAX, FLAGS, "matrix" }, -+ { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT709}, 0, 0, FLAGS, "matrix" }, -+ { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_SPC_BT2020_NCL}, 0, 0, FLAGS, "matrix" }, -+ { "primaries", "set color primaries", OFFSET(pri), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_BT709}, -1, INT_MAX, FLAGS, "primaries" }, -+ { "p", "set color primaries", OFFSET(pri), AV_OPT_TYPE_INT, {.i64 = AVCOL_PRI_BT709}, -1, INT_MAX, FLAGS, "primaries" }, -+ { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT709}, 0, 0, FLAGS, "primaries" }, -+ { "bt2020", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_PRI_BT2020}, 0, 0, FLAGS, "primaries" }, -+ { "range", "set color range", OFFSET(range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_MPEG}, -1, INT_MAX, FLAGS, "range" }, -+ { "r", "set color range", OFFSET(range), AV_OPT_TYPE_INT, {.i64 = AVCOL_RANGE_MPEG}, -1, INT_MAX, FLAGS, "range" }, -+ { "tv", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, -+ { "pc", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, -+ { "limited", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_MPEG}, 0, 0, FLAGS, "range" }, -+ { "full", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_RANGE_JPEG}, 0, 0, FLAGS, "range" }, -+ { "format", "Output format", OFFSET(format_str), AV_OPT_TYPE_STRING, { .str = "same" }, .flags = FLAGS }, -+ { "peak", "signal peak override", OFFSET(peak), AV_OPT_TYPE_DOUBLE, {.dbl = 0}, 0, DBL_MAX, FLAGS }, -+ { "param", "tonemap parameter", OFFSET(param), AV_OPT_TYPE_DOUBLE, {.dbl = NAN}, DBL_MIN, DBL_MAX, FLAGS }, -+ { "desat", "desaturation parameter", OFFSET(desat_param), AV_OPT_TYPE_DOUBLE, {.dbl = 0.5}, 0, DBL_MAX, FLAGS }, -+ { "threshold", "scene detection threshold", OFFSET(scene_threshold), AV_OPT_TYPE_DOUBLE, {.dbl = 0.2}, 0, DBL_MAX, FLAGS }, -+ { NULL }, -+}; -+ -+static const AVClass tonemap_cuda_class = { -+ .class_name = "tonemap_cuda", -+ .item_name = av_default_item_name, -+ .option = options, -+ .version = LIBAVUTIL_VERSION_INT, -+}; -+ -+static const AVFilterPad inputs[] = { -+ { -+ .name = "default", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .filter_frame = filter_frame, -+ }, -+ { NULL } -+}; -+ -+static const AVFilterPad outputs[] = { -+ { -+ .name = "default", -+ .type = AVMEDIA_TYPE_VIDEO, -+ .config_props = config_props, -+ }, -+ { NULL } -+}; -+ -+AVFilter ff_vf_tonemap_cuda = { -+ .name = "tonemap_cuda", -+ .description = NULL_IF_CONFIG_SMALL("GPU accelerated HDR to SDR tonemapping"), -+ -+ .init = init, -+ .uninit = uninit, -+ .query_formats = query_formats, -+ -+ .priv_size = sizeof(TonemapCUDAContext), -+ .priv_class = &tonemap_cuda_class, -+ -+ .inputs = inputs, -+ .outputs = outputs, -+ -+ .flags_internal = FF_FILTER_FLAG_HWFRAME_AWARE, -+}; diff --git a/debian/patches/0006-bt2390-and-fix-for-peak-detection-in-opencl-tonemap.patch b/debian/patches/0006-bt2390-and-fix-for-peak-detection-in-opencl-tonemap.patch deleted file mode 100644 index d88e553a9..000000000 --- a/debian/patches/0006-bt2390-and-fix-for-peak-detection-in-opencl-tonemap.patch +++ /dev/null @@ -1,755 +0,0 @@ -Index: jellyfin-ffmpeg/libavfilter/opencl/colorspace_common.cl -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/opencl/colorspace_common.cl -+++ jellyfin-ffmpeg/libavfilter/opencl/colorspace_common.cl -@@ -16,8 +16,23 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - -+#define BT709_ALPHA 1.09929682680944f -+#define BT709_BETA 0.018053968510807f -+ - #define ST2084_MAX_LUMINANCE 10000.0f --#define REFERENCE_WHITE 100.0f -+#define REFERENCE_WHITE 203.0f -+ -+#define ST2084_M1 0.1593017578125f -+#define ST2084_M2 78.84375f -+#define ST2084_C1 0.8359375f -+#define ST2084_C2 18.8515625f -+#define ST2084_C3 18.6875f -+ -+#define ARIB_B67_A 0.17883277f -+#define ARIB_B67_B 0.28466892f -+#define ARIB_B67_C 0.55991073f -+ -+#define FLOAT_EPS 1.175494351e-38f - - #if chroma_loc == 1 - #define chroma_sample(a,b,c,d) (((a) + (c)) * 0.5f) -@@ -33,12 +48,6 @@ - #define chroma_sample(a,b,c,d) (((a) + (b) + (c) + (d)) * 0.25f) - #endif - --constant const float ST2084_M1 = 0.1593017578125f; --constant const float ST2084_M2 = 78.84375f; --constant const float ST2084_C1 = 0.8359375f; --constant const float ST2084_C2 = 18.8515625f; --constant const float ST2084_C3 = 18.6875f; -- - float get_luma_dst(float3 c) { - return luma_dst.x * c.x + luma_dst.y * c.y + luma_dst.z * c.z; - } -@@ -51,61 +60,87 @@ float3 get_chroma_sample(float3 a, float - return chroma_sample(a, b, c, d); - } - -+// linearizer for PQ/ST2084 - float eotf_st2084(float x) { -- float p = powr(x, 1.0f / ST2084_M2); -- float a = max(p -ST2084_C1, 0.0f); -- float b = max(ST2084_C2 - ST2084_C3 * p, 1e-6f); -- float c = powr(a / b, 1.0f / ST2084_M1); -- return x > 0.0f ? c * ST2084_MAX_LUMINANCE / REFERENCE_WHITE : 0.0f; --} -- --__constant const float HLG_A = 0.17883277f; --__constant const float HLG_B = 0.28466892f; --__constant const float HLG_C = 0.55991073f; -- --// linearizer for HLG --float inverse_oetf_hlg(float x) { -- float a = 4.0f * x * x; -- float b = exp((x - HLG_C) / HLG_A) + HLG_B; -- return x < 0.5f ? a : b; --} -- --// delinearizer for HLG --float oetf_hlg(float x) { -- float a = 0.5f * sqrt(x); -- float b = HLG_A * log(x - HLG_B) + HLG_C; -- return x <= 1.0f ? a : b; --} -- --float3 ootf_hlg(float3 c, float peak) { -- float luma = get_luma_src(c); -- float gamma = 1.2f + 0.42f * log10(peak * REFERENCE_WHITE / 1000.0f); -- gamma = max(1.0f, gamma); -- float factor = peak * powr(luma, gamma - 1.0f) / powr(12.0f, gamma); -- return c * factor; --} -- --float3 inverse_ootf_hlg(float3 c, float peak) { -- float gamma = 1.2f + 0.42f * log10(peak * REFERENCE_WHITE / 1000.0f); -- c *= powr(12.0f, gamma) / peak; -- c /= powr(get_luma_dst(c), (gamma - 1.0f) / gamma); -- return c; -+ if (x > 0.0f) { -+ float xpow = powr(x, 1.0f / ST2084_M2); -+ float num = max(xpow - ST2084_C1, 0.0f); -+ float den = max(ST2084_C2 - ST2084_C3 * xpow, FLOAT_EPS); -+ x = powr(num / den, 1.0f / ST2084_M1); -+ return x * ST2084_MAX_LUMINANCE / REFERENCE_WHITE; -+ } else { -+ return 0.0f; -+ } -+} -+ -+// delinearizer for PQ/ST2084 -+float inverse_eotf_st2084(float x) { -+ if (x > 0.0f) { -+ x *= REFERENCE_WHITE / ST2084_MAX_LUMINANCE; -+ float xpow = powr(x, ST2084_M1); -+#if 0 -+ // Original formulation from SMPTE ST 2084:2014 publication. -+ float num = ST2084_C1 + ST2084_C2 * xpow; -+ float den = 1.0f + ST2084_C3 * xpow; -+ return powr(num / den, ST2084_M2); -+#else -+ // More stable arrangement that avoids some cancellation error. -+ float num = (ST2084_C1 - 1.0f) + (ST2084_C2 - ST2084_C3) * xpow; -+ float den = 1.0f + ST2084_C3 * xpow; -+ return powr(1.0f + num / den, ST2084_M2); -+#endif -+ } else { -+ return 0.0f; -+ } -+} -+ -+float ootf_1_2(float x) { -+ return x < 0.0f ? x : powr(x, 1.2f); -+} -+ -+float inverse_ootf_1_2(float x) { -+ return x < 0.0f ? x : powr(x, 1.0f / 1.2f); -+} -+ -+float oetf_arib_b67(float x) { -+ x = max(x, 0.0f); -+ return x <= (1.0f / 12.0f) -+ ? sqrt(3.0f * x) -+ : (ARIB_B67_A * log(12.0f * x - ARIB_B67_B) + ARIB_B67_C); -+} -+ -+float inverse_oetf_arib_b67(float x) { -+ x = max(x, 0.0f); -+ return x <= 0.5f -+ ? (x * x) * (1.0f / 3.0f) -+ : (exp((x - ARIB_B67_C) / ARIB_B67_A) + ARIB_B67_B) * (1.0f / 12.0f); - } - --float inverse_eotf_bt1886(float c) { -- return c < 0.0f ? 0.0f : powr(c, 1.0f / 2.4f); -+// linearizer for HLG/ARIB-B67 -+float eotf_arib_b67(float x) { -+ return ootf_1_2(inverse_oetf_arib_b67(x)); - } - --float oetf_bt709(float c) { -- c = c < 0.0f ? 0.0f : c; -- float r1 = 4.5f * c; -- float r2 = 1.099f * powr(c, 0.45f) - 0.099f; -- return c < 0.018f ? r1 : r2; --} --float inverse_oetf_bt709(float c) { -- float r1 = c / 4.5f; -- float r2 = powr((c + 0.099f) / 1.099f, 1.0f / 0.45f); -- return c < 0.081f ? r1 : r2; -+// delinearizer for HLG/ARIB-B67 -+float inverse_eotf_arib_b67(float x) { -+ return oetf_arib_b67(inverse_ootf_1_2(x)); -+} -+ -+float inverse_eotf_bt1886(float x) { -+ return x < 0.0f ? 0.0f : powr(x, 1.0f / 2.4f); -+} -+ -+float oetf_bt709(float x) { -+ x = max(0.0f, x); -+ return x < BT709_BETA -+ ? (x * 4.5f) -+ : (BT709_ALPHA * powr(x, 0.45f) - (BT709_ALPHA - 1.0f)); -+} -+ -+float inverse_oetf_bt709(float x) { -+ return x < (4.5f * BT709_BETA) -+ ? (x / 4.5f) -+ : (powr((x + (BT709_ALPHA - 1.0f)) / BT709_ALPHA, 1.0f / 0.45f)); - } - - float3 yuv2rgb(float y, float u, float v) { -@@ -187,19 +222,3 @@ float3 lrgb2lrgb(float3 c) { - return (float3)(rr, gg, bb); - #endif - } -- --float3 ootf(float3 c, float peak) { --#ifdef ootf_impl -- return ootf_impl(c, peak); --#else -- return c; --#endif --} -- --float3 inverse_ootf(float3 c, float peak) { --#ifdef inverse_ootf_impl -- return inverse_ootf_impl(c, peak); --#else -- return c; --#endif --} -Index: jellyfin-ffmpeg/libavfilter/opencl/tonemap.cl -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/opencl/tonemap.cl -+++ jellyfin-ffmpeg/libavfilter/opencl/tonemap.cl -@@ -16,54 +16,50 @@ - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ - --#define REFERENCE_WHITE 100.0f -+#define FLOAT_EPS 1.175494351e-38f -+ - extern float3 lrgb2yuv(float3); - extern float lrgb2y(float3); - extern float3 yuv2lrgb(float3); - extern float3 lrgb2lrgb(float3); - extern float get_luma_src(float3); - extern float get_luma_dst(float3); --extern float3 ootf(float3 c, float peak); --extern float3 inverse_ootf(float3 c, float peak); -+extern float eotf_st2084(float); -+extern float inverse_eotf_st2084(float); - extern float3 get_chroma_sample(float3, float3, float3, float3); - --struct detection_result { -- float peak; -- float average; --}; -- - float hable_f(float in) { - float a = 0.15f, b = 0.50f, c = 0.10f, d = 0.20f, e = 0.02f, f = 0.30f; - return (in * (in * a + b * c) + d * e) / (in * (in * a + b) + d * f) - e / f; - } - --float direct(float s, float peak) { -+float direct(float s, float peak, float target_peak) { - return s; - } - --float linear(float s, float peak) { -+float linear(float s, float peak, float target_peak) { - return s * tone_param / peak; - } - --float gamma(float s, float peak) { -- float p = s > 0.05f ? s /peak : 0.05f / peak; -+float gamma(float s, float peak, float target_peak) { -+ float p = s > 0.05f ? s / peak : 0.05f / peak; - float v = powr(p, 1.0f / tone_param); -- return s > 0.05f ? v : (s * v /0.05f); -+ return s > 0.05f ? v : (s * v / 0.05f); - } - --float clip(float s, float peak) { -+float clip(float s, float peak, float target_peak) { - return clamp(s * tone_param, 0.0f, 1.0f); - } - --float reinhard(float s, float peak) { -+float reinhard(float s, float peak, float target_peak) { - return s / (s + tone_param) * (peak + tone_param) / peak; - } - --float hable(float s, float peak) { -- return hable_f(s)/hable_f(peak); -+float hable(float s, float peak, float target_peak) { -+ return hable_f(s) / hable_f(peak); - } - --float mobius(float s, float peak) { -+float mobius(float s, float peak, float target_peak) { - float j = tone_param; - float a, b; - -@@ -71,102 +67,32 @@ float mobius(float s, float peak) { - return s; - - a = -j * j * (peak - 1.0f) / (j * j - 2.0f * j + peak); -- b = (j * j - 2.0f * j * peak + peak) / max(peak - 1.0f, 1e-6f); -+ b = (j * j - 2.0f * j * peak + peak) / max(peak - 1.0f, FLOAT_EPS); - - return (b * b + 2.0f * b * j + j * j) / (b - a) * (s + a) / (s + b); - } - --// detect peak/average signal of a frame, the algorithm was ported from: --// libplacebo (https://github.com/haasn/libplacebo) --struct detection_result --detect_peak_avg(global uint *util_buf, __local uint *sum_wg, -- float signal, float peak) { --// layout of the util buffer --// --// Name: : Size (units of 4-bytes) --// average buffer : detection_frames + 1 --// peak buffer : detection_frames + 1 --// workgroup counter : 1 --// total of peak : 1 --// total of average : 1 --// frame index : 1 --// frame number : 1 -- global uint *avg_buf = util_buf; -- global uint *peak_buf = avg_buf + DETECTION_FRAMES + 1; -- global uint *counter_wg_p = peak_buf + DETECTION_FRAMES + 1; -- global uint *max_total_p = counter_wg_p + 1; -- global uint *avg_total_p = max_total_p + 1; -- global uint *frame_idx_p = avg_total_p + 1; -- global uint *scene_frame_num_p = frame_idx_p + 1; -- -- uint frame_idx = *frame_idx_p; -- uint scene_frame_num = *scene_frame_num_p; -- -- size_t lidx = get_local_id(0); -- size_t lidy = get_local_id(1); -- size_t lsizex = get_local_size(0); -- size_t lsizey = get_local_size(1); -- uint num_wg = get_num_groups(0) * get_num_groups(1); -- size_t group_idx = get_group_id(0); -- size_t group_idy = get_group_id(1); -- struct detection_result r = {peak, sdr_avg}; -- if (lidx == 0 && lidy == 0) -- *sum_wg = 0; -- barrier(CLK_LOCAL_MEM_FENCE); -- -- // update workgroup sum -- atomic_add(sum_wg, (uint)(signal * REFERENCE_WHITE)); -- barrier(CLK_LOCAL_MEM_FENCE); -- -- // update frame peak/avg using work-group-average. -- if (lidx == 0 && lidy == 0) { -- uint avg_wg = *sum_wg / (lsizex * lsizey); -- atomic_max(&peak_buf[frame_idx], avg_wg); -- atomic_add(&avg_buf[frame_idx], avg_wg); -- } -- -- if (scene_frame_num > 0) { -- float peak = (float)*max_total_p / (REFERENCE_WHITE * scene_frame_num); -- float avg = (float)*avg_total_p / (REFERENCE_WHITE * scene_frame_num); -- r.peak = max(1.0f, peak); -- r.average = max(0.25f, avg); -- } -+float bt2390(float s, float peak, float target_peak) { -+ float peak_pq = inverse_eotf_st2084(peak); -+ float scale = 1.0f / peak_pq; -+ -+ float s_pq = inverse_eotf_st2084(s) * scale; -+ float maxLum = inverse_eotf_st2084(target_peak) * scale; -+ -+ float ks = 1.5f * maxLum - 0.5f; -+ float tb = (s_pq - ks) / (1.0f - ks); -+ float tb2 = tb * tb; -+ float tb3 = tb2 * tb; -+ float pb = (2.0f * tb3 - 3.0f * tb2 + 1.0f) * ks + -+ (tb3 - 2.0f * tb2 + tb) * (1.0f - ks) + -+ (-2.0f * tb3 + 3.0f * tb2) * maxLum; -+ float sig = (s_pq < ks) ? s_pq : pb; - -- if (lidx == 0 && lidy == 0 && atomic_add(counter_wg_p, 1) == num_wg - 1) { -- *counter_wg_p = 0; -- avg_buf[frame_idx] /= num_wg; -- -- if (scene_threshold > 0.0f) { -- uint cur_max = peak_buf[frame_idx]; -- uint cur_avg = avg_buf[frame_idx]; -- int diff = (int)(scene_frame_num * cur_avg) - (int)*avg_total_p; -- -- if (abs(diff) > scene_frame_num * scene_threshold * REFERENCE_WHITE) { -- for (uint i = 0; i < DETECTION_FRAMES + 1; i++) -- avg_buf[i] = 0; -- for (uint i = 0; i < DETECTION_FRAMES + 1; i++) -- peak_buf[i] = 0; -- *avg_total_p = *max_total_p = 0; -- *scene_frame_num_p = 0; -- avg_buf[frame_idx] = cur_avg; -- peak_buf[frame_idx] = cur_max; -- } -- } -- uint next = (frame_idx + 1) % (DETECTION_FRAMES + 1); -- // add current frame, subtract next frame -- *max_total_p += peak_buf[frame_idx] - peak_buf[next]; -- *avg_total_p += avg_buf[frame_idx] - avg_buf[next]; -- // reset next frame -- peak_buf[next] = avg_buf[next] = 0; -- *frame_idx_p = next; -- *scene_frame_num_p = min(*scene_frame_num_p + 1, -- (uint)DETECTION_FRAMES); -- } -- return r; -+ return eotf_st2084(sig * peak_pq); - } - --float3 map_one_pixel_rgb(float3 rgb, float peak, float average) { -- float sig = max(max(rgb.x, max(rgb.y, rgb.z)), 1e-6f); -+float3 map_one_pixel_rgb(float3 rgb, float peak) { -+ float sig = max(max(rgb.x, max(rgb.y, rgb.z)), FLOAT_EPS); - - // Rescale the variables in order to bring it into a representation where - // 1.0 represents the dst_peak. This is because all of the tone mapping -@@ -178,30 +104,24 @@ float3 map_one_pixel_rgb(float3 rgb, flo - - float sig_old = sig; - -- // Scale the signal to compensate for differences in the average brightness -- float slope = min(1.0f, sdr_avg / average); -- sig *= slope; -- peak *= slope; -- - // Desaturate the color using a coefficient dependent on the signal level - if (desat_param > 0.0f) { - float luma = get_luma_dst(rgb); -- float coeff = max(sig - 0.18f, 1e-6f) / max(sig, 1e-6f); -- coeff = native_powr(coeff, 10.0f / desat_param); -+ float coeff = max(sig - 0.18f, FLOAT_EPS) / max(sig, FLOAT_EPS); -+ coeff = powr(coeff, 10.0f / desat_param); - rgb = mix(rgb, (float3)luma, (float3)coeff); -- sig = mix(sig, luma * slope, coeff); - } - -- sig = TONE_FUNC(sig, peak); -+ sig = TONE_FUNC(sig, peak, target_peak); - - sig = min(sig, 1.0f); -- rgb *= (sig/sig_old); -+ rgb *= (sig / sig_old); - return rgb; - } --// map from source space YUV to destination space RGB -+ -+// Map from source space YUV to destination space RGB - float3 map_to_dst_space_from_yuv(float3 yuv, float peak) { - float3 c = yuv2lrgb(yuv); -- c = ootf(c, peak); - c = lrgb2lrgb(c); - return c; - } -@@ -210,7 +130,6 @@ __kernel void tonemap(__write_only image - __read_only image2d_t src1, - __write_only image2d_t dst2, - __read_only image2d_t src2, -- global uint *util_buf, - float peak - ) - { -@@ -241,23 +160,17 @@ __kernel void tonemap(__write_only image - float sig3 = max(c3.x, max(c3.y, c3.z)); - float sig = max(sig0, max(sig1, max(sig2, sig3))); - -- struct detection_result r = detect_peak_avg(util_buf, &sum_wg, sig, peak); -- - float3 c0_old = c0, c1_old = c1, c2_old = c2; -- c0 = map_one_pixel_rgb(c0, r.peak, r.average); -- c1 = map_one_pixel_rgb(c1, r.peak, r.average); -- c2 = map_one_pixel_rgb(c2, r.peak, r.average); -- c3 = map_one_pixel_rgb(c3, r.peak, r.average); -- -- c0 = inverse_ootf(c0, target_peak); -- c1 = inverse_ootf(c1, target_peak); -- c2 = inverse_ootf(c2, target_peak); -- c3 = inverse_ootf(c3, target_peak); -+ c0 = map_one_pixel_rgb(c0, peak); -+ c1 = map_one_pixel_rgb(c1, peak); -+ c2 = map_one_pixel_rgb(c2, peak); -+ c3 = map_one_pixel_rgb(c3, peak); - - y0 = lrgb2y(c0); - y1 = lrgb2y(c1); - y2 = lrgb2y(c2); - y3 = lrgb2y(c3); -+ - float3 chroma_c = get_chroma_sample(c0, c1, c2, c3); - float3 chroma = lrgb2yuv(chroma_c); - -Index: jellyfin-ffmpeg/libavfilter/vf_tonemap_opencl.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_tonemap_opencl.c -+++ jellyfin-ffmpeg/libavfilter/vf_tonemap_opencl.c -@@ -15,6 +15,7 @@ - * License along with FFmpeg; if not, write to the Free Software - * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA - */ -+ - #include - - #include "libavutil/avassert.h" -@@ -31,13 +32,6 @@ - #include "video.h" - #include "colorspace.h" - --// TODO: --// - separate peak-detection from tone-mapping kernel to solve --// one-frame-delay issue. --// - more format support -- --#define DETECTION_FRAMES 63 -- - enum TonemapAlgorithm { - TONEMAP_NONE, - TONEMAP_LINEAR, -@@ -46,6 +40,7 @@ enum TonemapAlgorithm { - TONEMAP_REINHARD, - TONEMAP_HABLE, - TONEMAP_MOBIUS, -+ TONEMAP_BT2390, - TONEMAP_MAX, - }; - -@@ -68,12 +63,11 @@ typedef struct TonemapOpenCLContext { - int initialised; - cl_kernel kernel; - cl_command_queue command_queue; -- cl_mem util_mem; - } TonemapOpenCLContext; - - static const char *const linearize_funcs[AVCOL_TRC_NB] = { -- [AVCOL_TRC_SMPTE2084] = "eotf_st2084", -- [AVCOL_TRC_ARIB_STD_B67] = "inverse_oetf_hlg", -+ [AVCOL_TRC_SMPTE2084] = "eotf_st2084", -+ [AVCOL_TRC_ARIB_STD_B67] = "eotf_arib_b67", - }; - - static const char *const delinearize_funcs[AVCOL_TRC_NB] = { -@@ -99,6 +93,7 @@ static const char *const tonemap_func[TO - [TONEMAP_REINHARD] = "reinhard", - [TONEMAP_HABLE] = "hable", - [TONEMAP_MOBIUS] = "mobius", -+ [TONEMAP_BT2390] = "bt2390", - }; - - static void get_rgb2rgb_matrix(enum AVColorPrimaries in, enum AVColorPrimaries out, -@@ -112,9 +107,6 @@ static void get_rgb2rgb_matrix(enum AVCo - } - - #define OPENCL_SOURCE_NB 3 --// Average light level for SDR signals. This is equal to a signal level of 0.5 --// under a typical presentation gamma of about 2.0. --static const float sdr_avg = 0.25f; - - static int tonemap_opencl_init(AVFilterContext *avctx) - { -@@ -127,7 +119,7 @@ static int tonemap_opencl_init(AVFilterC - AVBPrint header; - const char *opencl_sources[OPENCL_SOURCE_NB]; - -- av_bprint_init(&header, 1024, AV_BPRINT_SIZE_AUTOMATIC); -+ av_bprint_init(&header, 2048, AV_BPRINT_SIZE_UNLIMITED); - - switch(ctx->tonemap) { - case TONEMAP_GAMMA: -@@ -149,18 +141,20 @@ static int tonemap_opencl_init(AVFilterC - - // SDR peak is 1.0f - ctx->target_peak = 1.0f; -- av_log(ctx, AV_LOG_DEBUG, "tone mapping transfer from %s to %s\n", -+ -+ av_log(ctx, AV_LOG_DEBUG, "Tonemapping transfer from %s to %s\n", - av_color_transfer_name(ctx->trc_in), - av_color_transfer_name(ctx->trc_out)); -- av_log(ctx, AV_LOG_DEBUG, "mapping colorspace from %s to %s\n", -+ av_log(ctx, AV_LOG_DEBUG, "Mapping colorspace from %s to %s\n", - av_color_space_name(ctx->colorspace_in), - av_color_space_name(ctx->colorspace_out)); -- av_log(ctx, AV_LOG_DEBUG, "mapping primaries from %s to %s\n", -+ av_log(ctx, AV_LOG_DEBUG, "Mapping primaries from %s to %s\n", - av_color_primaries_name(ctx->primaries_in), - av_color_primaries_name(ctx->primaries_out)); -- av_log(ctx, AV_LOG_DEBUG, "mapping range from %s to %s\n", -+ av_log(ctx, AV_LOG_DEBUG, "Mapping range from %s to %s\n", - av_color_range_name(ctx->range_in), - av_color_range_name(ctx->range_out)); -+ - // checking valid value just because of limited implementaion - // please remove when more functionalities are implemented - av_assert0(ctx->trc_out == AVCOL_TRC_BT709 || -@@ -178,11 +172,9 @@ static int tonemap_opencl_init(AVFilterC - ctx->desat_param); - av_bprintf(&header, "__constant const float target_peak = %.4ff;\n", - ctx->target_peak); -- av_bprintf(&header, "__constant const float sdr_avg = %.4ff;\n", sdr_avg); - av_bprintf(&header, "__constant const float scene_threshold = %.4ff;\n", - ctx->scene_threshold); - av_bprintf(&header, "#define TONE_FUNC %s\n", tonemap_func[ctx->tonemap]); -- av_bprintf(&header, "#define DETECTION_FRAMES %d\n", DETECTION_FRAMES); - - if (ctx->primaries_out != ctx->primaries_in) { - get_rgb2rgb_matrix(ctx->primaries_in, ctx->primaries_out, rgb2rgb); -@@ -196,6 +188,16 @@ static int tonemap_opencl_init(AVFilterC - - av_bprintf(&header, "#define chroma_loc %d\n", (int)ctx->chroma_loc); - -+ av_bprintf(&header, "#define powr native_powr\n"); -+ -+ av_bprintf(&header, "#define exp native_exp\n"); -+ -+ av_bprintf(&header, "#define log native_log\n"); -+ -+ av_bprintf(&header, "#define log10 native_log10\n"); -+ -+ av_bprintf(&header, "#define sqrt native_sqrt\n"); -+ - if (rgb2rgb_passthrough) - av_bprintf(&header, "#define RGB2RGB_PASSTHROUGH\n"); - else -@@ -205,7 +207,7 @@ static int tonemap_opencl_init(AVFilterC - luma_src = ff_get_luma_coefficients(ctx->colorspace_in); - if (!luma_src) { - err = AVERROR(EINVAL); -- av_log(avctx, AV_LOG_ERROR, "unsupported input colorspace %d (%s)\n", -+ av_log(avctx, AV_LOG_ERROR, "Unsupported input colorspace %d (%s)\n", - ctx->colorspace_in, av_color_space_name(ctx->colorspace_in)); - goto fail; - } -@@ -213,7 +215,7 @@ static int tonemap_opencl_init(AVFilterC - luma_dst = ff_get_luma_coefficients(ctx->colorspace_out); - if (!luma_dst) { - err = AVERROR(EINVAL); -- av_log(avctx, AV_LOG_ERROR, "unsupported output colorspace %d (%s)\n", -+ av_log(avctx, AV_LOG_ERROR, "Unsupported output colorspace %d (%s)\n", - ctx->colorspace_out, av_color_space_name(ctx->colorspace_out)); - goto fail; - } -@@ -225,21 +227,16 @@ static int tonemap_opencl_init(AVFilterC - ff_matrix_invert_3x3(rgb2yuv, yuv2rgb); - ff_opencl_print_const_matrix_3x3(&header, "rgb_matrix", yuv2rgb); - -- av_bprintf(&header, "constant float3 luma_src = {%.4ff, %.4ff, %.4ff};\n", -+ av_bprintf(&header, "__constant float3 luma_src = {%.4ff, %.4ff, %.4ff};\n", - luma_src->cr, luma_src->cg, luma_src->cb); -- av_bprintf(&header, "constant float3 luma_dst = {%.4ff, %.4ff, %.4ff};\n", -+ av_bprintf(&header, "__constant float3 luma_dst = {%.4ff, %.4ff, %.4ff};\n", - luma_dst->cr, luma_dst->cg, luma_dst->cb); - -- av_bprintf(&header, "#define linearize %s\n", linearize_funcs[ctx->trc_in]); -+ av_bprintf(&header, "#define linearize %s\n", -+ linearize_funcs[ctx->trc_in]); - av_bprintf(&header, "#define delinearize %s\n", - delinearize_funcs[ctx->trc_out]); - -- if (ctx->trc_in == AVCOL_TRC_ARIB_STD_B67) -- av_bprintf(&header, "#define ootf_impl ootf_hlg\n"); -- -- if (ctx->trc_out == AVCOL_TRC_ARIB_STD_B67) -- av_bprintf(&header, "#define inverse_ootf_impl inverse_ootf_hlg\n"); -- - av_log(avctx, AV_LOG_DEBUG, "Generated OpenCL header:\n%s\n", header.str); - opencl_sources[0] = header.str; - opencl_sources[1] = ff_opencl_source_tonemap; -@@ -259,19 +256,11 @@ static int tonemap_opencl_init(AVFilterC - ctx->kernel = clCreateKernel(ctx->ocf.program, "tonemap", &cle); - CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create kernel %d.\n", cle); - -- ctx->util_mem = -- clCreateBuffer(ctx->ocf.hwctx->context, 0, -- (2 * DETECTION_FRAMES + 7) * sizeof(unsigned), -- NULL, &cle); -- CL_FAIL_ON_ERROR(AVERROR(EIO), "Failed to create util buffer: %d.\n", cle); -- - ctx->initialised = 1; - return 0; - - fail: - av_bprint_finalize(&header, NULL); -- if (ctx->util_mem) -- clReleaseMemObject(ctx->util_mem); - if (ctx->command_queue) - clReleaseCommandQueue(ctx->command_queue); - if (ctx->kernel) -@@ -285,11 +274,11 @@ static int tonemap_opencl_config_output( - TonemapOpenCLContext *s = avctx->priv; - int ret; - if (s->format == AV_PIX_FMT_NONE) -- av_log(avctx, AV_LOG_WARNING, "format not set, use default format NV12\n"); -+ av_log(avctx, AV_LOG_WARNING, "Format not set, use default format NV12\n"); - else { - if (s->format != AV_PIX_FMT_P010 && - s->format != AV_PIX_FMT_NV12) { -- av_log(avctx, AV_LOG_ERROR, "unsupported output format," -+ av_log(avctx, AV_LOG_ERROR, "Unsupported output format," - "only p010/nv12 supported now\n"); - return AVERROR(EINVAL); - } -@@ -315,8 +304,7 @@ static int launch_kernel(AVFilterContext - CL_SET_KERNEL_ARG(kernel, 1, cl_mem, &input->data[0]); - CL_SET_KERNEL_ARG(kernel, 2, cl_mem, &output->data[1]); - CL_SET_KERNEL_ARG(kernel, 3, cl_mem, &input->data[1]); -- CL_SET_KERNEL_ARG(kernel, 4, cl_mem, &ctx->util_mem); -- CL_SET_KERNEL_ARG(kernel, 5, cl_float, &peak); -+ CL_SET_KERNEL_ARG(kernel, 4, cl_float, &peak); - - local_work[0] = 16; - local_work[1] = 16; -@@ -390,13 +378,15 @@ static int tonemap_opencl_filter_frame(A - if (!ctx->initialised) { - if (!(input->color_trc == AVCOL_TRC_SMPTE2084 || - input->color_trc == AVCOL_TRC_ARIB_STD_B67)) { -- av_log(ctx, AV_LOG_ERROR, "unsupported transfer function characteristic.\n"); -+ av_log(ctx, AV_LOG_ERROR, "Unsupported transfer function characteristic: %s\n", -+ av_color_transfer_name(input->color_trc)); - err = AVERROR(ENOSYS); - goto fail; - } - - if (input_frames_ctx->sw_format != AV_PIX_FMT_P010) { -- av_log(ctx, AV_LOG_ERROR, "unsupported format in tonemap_opencl.\n"); -+ av_log(ctx, AV_LOG_ERROR, "Unsupported input format: %s\n", -+ av_get_pix_fmt_name(input_frames_ctx->sw_format)); - err = AVERROR(ENOSYS); - goto fail; - } -@@ -423,31 +413,9 @@ static int tonemap_opencl_filter_frame(A - - ff_update_hdr_metadata(output, ctx->target_peak); - -- av_log(ctx, AV_LOG_DEBUG, "Tone-mapping output: %s, %ux%u (%"PRId64").\n", -+ av_log(ctx, AV_LOG_DEBUG, "Tonemapping output: %s, %ux%u (%"PRId64").\n", - av_get_pix_fmt_name(output->format), - output->width, output->height, output->pts); --#ifndef NDEBUG -- { -- uint32_t *ptr, *max_total_p, *avg_total_p, *frame_number_p; -- float peak_detected, avg_detected; -- unsigned map_size = (2 * DETECTION_FRAMES + 7) * sizeof(unsigned); -- ptr = (void *)clEnqueueMapBuffer(ctx->command_queue, ctx->util_mem, -- CL_TRUE, CL_MAP_READ, 0, map_size, -- 0, NULL, NULL, &cle); -- // For the layout of the util buffer, refer tonemap.cl -- if (ptr) { -- max_total_p = ptr + 2 * (DETECTION_FRAMES + 1) + 1; -- avg_total_p = max_total_p + 1; -- frame_number_p = avg_total_p + 2; -- peak_detected = (float)*max_total_p / (REFERENCE_WHITE * (*frame_number_p)); -- avg_detected = (float)*avg_total_p / (REFERENCE_WHITE * (*frame_number_p)); -- av_log(ctx, AV_LOG_DEBUG, "peak %f, avg %f will be used for next frame\n", -- peak_detected, avg_detected); -- clEnqueueUnmapMemObject(ctx->command_queue, ctx->util_mem, ptr, 0, -- NULL, NULL); -- } -- } --#endif - - return ff_filter_frame(outlink, output); - -@@ -463,8 +431,6 @@ static av_cold void tonemap_opencl_unini - TonemapOpenCLContext *ctx = avctx->priv; - cl_int cle; - -- if (ctx->util_mem) -- clReleaseMemObject(ctx->util_mem); - if (ctx->kernel) { - cle = clReleaseKernel(ctx->kernel); - if (cle != CL_SUCCESS) -@@ -493,6 +459,7 @@ static const AVOption tonemap_opencl_opt - { "reinhard", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_REINHARD}, 0, 0, FLAGS, "tonemap" }, - { "hable", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_HABLE}, 0, 0, FLAGS, "tonemap" }, - { "mobius", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_MOBIUS}, 0, 0, FLAGS, "tonemap" }, -+ { "bt2390", 0, 0, AV_OPT_TYPE_CONST, {.i64 = TONEMAP_BT2390}, 0, 0, FLAGS, "tonemap" }, - { "transfer", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, - { "t", "set transfer characteristic", OFFSET(trc), AV_OPT_TYPE_INT, {.i64 = AVCOL_TRC_BT709}, -1, INT_MAX, FLAGS, "transfer" }, - { "bt709", 0, 0, AV_OPT_TYPE_CONST, {.i64 = AVCOL_TRC_BT709}, 0, 0, FLAGS, "transfer" }, diff --git a/debian/patches/0007-fix-for-fmp4-in-hlsenc.patch b/debian/patches/0007-fix-for-fmp4-in-hlsenc.patch deleted file mode 100644 index 5610f02b4..000000000 --- a/debian/patches/0007-fix-for-fmp4-in-hlsenc.patch +++ /dev/null @@ -1,24 +0,0 @@ -Index: jellyfin-ffmpeg/libavformat/hlsenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/hlsenc.c -+++ jellyfin-ffmpeg/libavformat/hlsenc.c -@@ -2672,14 +2672,13 @@ static int hls_write_packet(AVFormatCont - - vs->packets_written++; - if (oc->pb) { -- int64_t keyframe_pre_pos = avio_tell(oc->pb); - ret = ff_write_chained(oc, stream_index, pkt, s, 0); -- if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && -- (pkt->flags & AV_PKT_FLAG_KEY) && !keyframe_pre_pos) { -- av_write_frame(oc, NULL); /* Flush any buffered data */ -- vs->video_keyframe_size = avio_tell(oc->pb) - keyframe_pre_pos; -+ vs->video_keyframe_size += pkt->size; -+ if ((st->codecpar->codec_type == AVMEDIA_TYPE_VIDEO) && (pkt->flags & AV_PKT_FLAG_KEY)) { -+ vs->video_keyframe_size = avio_tell(oc->pb); -+ } else { -+ vs->video_keyframe_pos = avio_tell(vs->out); - } -- vs->video_keyframe_pos = vs->start_pos; - if (hls->ignore_io_errors) - ret = 0; - } diff --git a/debian/patches/0008-fix-nvdec-exceeded-32-surfaces-error.patch b/debian/patches/0008-fix-nvdec-exceeded-32-surfaces-error.patch deleted file mode 100644 index ed02508ae..000000000 --- a/debian/patches/0008-fix-nvdec-exceeded-32-surfaces-error.patch +++ /dev/null @@ -1,17 +0,0 @@ -Index: jellyfin-ffmpeg/libavcodec/nvdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/nvdec.c -+++ jellyfin-ffmpeg/libavcodec/nvdec.c -@@ -303,8 +303,10 @@ static int nvdec_init_hwframes(AVCodecCo - frames_ctx = (AVHWFramesContext*)(*out_frames_ref)->data; - - if (dummy) { -- // Copied from ff_decode_get_hw_frames_ctx for compatibility -- frames_ctx->initial_pool_size += 3; -+ // The function above guarantees 1 work surface, We must guarantee 4 work surfaces. -+ // (the absolute minimum), so add the missing count without exceeding the maximum -+ // recommended for nvdec. -+ frames_ctx->initial_pool_size = FFMIN(frames_ctx->initial_pool_size + 3, 32); - - frames_ctx->free = nvdec_free_dummy; - frames_ctx->pool = av_buffer_pool_init(0, nvdec_alloc_dummy); diff --git a/debian/patches/0009-fix-for-nvenc-from-upstream.patch b/debian/patches/0009-fix-for-nvenc-from-upstream.patch deleted file mode 100644 index 0eca70f36..000000000 --- a/debian/patches/0009-fix-for-nvenc-from-upstream.patch +++ /dev/null @@ -1,1716 +0,0 @@ -Index: jellyfin-ffmpeg/Changelog -=================================================================== ---- jellyfin-ffmpeg.orig/Changelog -+++ jellyfin-ffmpeg/Changelog -@@ -1,7 +1,7 @@ - Entries are sorted chronologically from oldest to youngest within each release, - releases are sorted from youngest to oldest. - --version : -+version 4.4: - - AudioToolbox output device - - MacCaption demuxer - - PGX decoder -Index: jellyfin-ffmpeg/RELEASE_NOTES -=================================================================== ---- jellyfin-ffmpeg.orig/RELEASE_NOTES -+++ jellyfin-ffmpeg/RELEASE_NOTES -@@ -11,5 +11,5 @@ - - We hope you will like this release as much as we enjoyed working on it, and - as usual, if you have any questions about it, or any FFmpeg related topic, -- feel free to join us on the #ffmpeg IRC channel (on irc.freenode.net) or ask -+ feel free to join us on the #ffmpeg IRC channel (on irc.libera.chat) or ask - on the mailing-lists. -Index: jellyfin-ffmpeg/configure -=================================================================== ---- jellyfin-ffmpeg.orig/configure -+++ jellyfin-ffmpeg/configure -@@ -536,7 +536,7 @@ die(){ - - If you think configure made a mistake, make sure you are using the latest - version from Git. If the latest version fails, report the problem to the --ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.freenode.net. -+ffmpeg-user@ffmpeg.org mailing list or IRC #ffmpeg on irc.libera.chat. - EOF - if disabled logging; then - cat <st->index, ost->st->id, ost->initialized, ost->inputs_done, ost->finished); - - if (!ost->initialized && !ost->inputs_done) -- return ost; -+ return ost->unavailable ? NULL : ost; - - if (!ost->finished && opts < opts_min) { - opts_min = opts; -Index: jellyfin-ffmpeg/libavcodec/aacenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/aacenc.c -+++ jellyfin-ffmpeg/libavcodec/aacenc.c -@@ -28,6 +28,7 @@ - * TODOs: - * add sane pulse detection - ***********************************/ -+#include - - #include "libavutil/libm.h" - #include "libavutil/float_dsp.h" -@@ -852,7 +853,7 @@ static int aac_encode_frame(AVCodecConte - /* Not so fast though */ - ratio = sqrtf(ratio); - } -- s->lambda = FFMIN(s->lambda * ratio, 65536.f); -+ s->lambda = av_clipf(s->lambda * ratio, FLT_EPSILON, 65536.f); - - /* Keep iterating if we must reduce and lambda is in the sky */ - if (ratio > 0.9f && ratio < 1.1f) { -@@ -897,7 +898,7 @@ static av_cold int aac_encode_end(AVCode - { - AACEncContext *s = avctx->priv_data; - -- av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_sum / s->lambda_count); -+ av_log(avctx, AV_LOG_INFO, "Qavg: %.3f\n", s->lambda_count ? s->lambda_sum / s->lambda_count : NAN); - - ff_mdct_end(&s->mdct1024); - ff_mdct_end(&s->mdct128); -Index: jellyfin-ffmpeg/libavcodec/aacpsy.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/aacpsy.c -+++ jellyfin-ffmpeg/libavcodec/aacpsy.c -@@ -308,6 +308,9 @@ static av_cold int psy_3gpp_init(FFPsyCo - const int bandwidth = ctx->cutoff ? ctx->cutoff : AAC_CUTOFF(ctx->avctx); - const float num_bark = calc_bark((float)bandwidth); - -+ if (bandwidth <= 0) -+ return AVERROR(EINVAL); -+ - ctx->model_priv_data = av_mallocz(sizeof(AacPsyContext)); - if (!ctx->model_priv_data) - return AVERROR(ENOMEM); -@@ -794,7 +797,7 @@ static void psy_3gpp_analyze_channel(FFP - - if (pe < 1.15f * desired_pe) { - /* 6.6.1.3.6 "Final threshold modification by linearization" */ -- norm_fac = 1.0f / norm_fac; -+ norm_fac = norm_fac ? 1.0f / norm_fac : 0; - for (w = 0; w < wi->num_windows*16; w += 16) { - for (g = 0; g < num_bands; g++) { - AacPsyBand *band = &pch->band[w+g]; -Index: jellyfin-ffmpeg/libavcodec/aarch64/hevcdsp_idct_neon.S -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/aarch64/hevcdsp_idct_neon.S -+++ jellyfin-ffmpeg/libavcodec/aarch64/hevcdsp_idct_neon.S -@@ -573,14 +573,13 @@ idct_16x16 10 - // void ff_hevc_idct_NxN_dc_DEPTH_neon(int16_t *coeffs) - .macro idct_dc size, bitdepth - function ff_hevc_idct_\size\()x\size\()_dc_\bitdepth\()_neon, export=1 -- movi v1.8h, #((1 << (14 - \bitdepth))+1) - ld1r {v4.8h}, [x0] -- add v4.8h, v4.8h, v1.8h -- sshr v0.8h, v4.8h, #(15 - \bitdepth) -- sshr v1.8h, v4.8h, #(15 - \bitdepth) -+ srshr v4.8h, v4.8h, #1 -+ srshr v0.8h, v4.8h, #(14 - \bitdepth) -+ srshr v1.8h, v4.8h, #(14 - \bitdepth) - .if \size > 4 -- sshr v2.8h, v4.8h, #(15 - \bitdepth) -- sshr v3.8h, v4.8h, #(15 - \bitdepth) -+ srshr v2.8h, v4.8h, #(14 - \bitdepth) -+ srshr v3.8h, v4.8h, #(14 - \bitdepth) - .if \size > 16 /* dc 32x32 */ - mov x2, #4 - 1: -Index: jellyfin-ffmpeg/libavcodec/alsdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/alsdec.c -+++ jellyfin-ffmpeg/libavcodec/alsdec.c -@@ -1632,7 +1632,7 @@ static int read_frame_data(ALSDecContext - AVCodecContext *avctx = ctx->avctx; - GetBitContext *gb = &ctx->gb; - unsigned int div_blocks[32]; ///< block sizes. -- unsigned int c; -+ int c; - unsigned int js_blocks[2]; - uint32_t bs_info = 0; - int ret; -@@ -1810,14 +1810,17 @@ static int decode_frame(AVCodecContext * - else - ctx->cur_frame_length = sconf->frame_length; - -- ctx->highest_decoded_channel = 0; -+ ctx->highest_decoded_channel = -1; - // decode the frame data - if ((invalid_frame = read_frame_data(ctx, ra_frame)) < 0) - av_log(ctx->avctx, AV_LOG_WARNING, - "Reading frame data failed. Skipping RA unit.\n"); - -- if (ctx->highest_decoded_channel == 0) -+ if (ctx->highest_decoded_channel == -1) { -+ av_log(ctx->avctx, AV_LOG_WARNING, -+ "No channel data decoded.\n"); - return AVERROR_INVALIDDATA; -+ } - - ctx->frame_id++; - -Index: jellyfin-ffmpeg/libavcodec/av1_metadata_bsf.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/av1_metadata_bsf.c -+++ jellyfin-ffmpeg/libavcodec/av1_metadata_bsf.c -@@ -28,6 +28,7 @@ typedef struct AV1MetadataContext { - CBSBSFContext common; - - int td; -+ AV1RawOBU td_obu; - - int color_primaries; - int transfer_characteristics; -@@ -107,12 +108,11 @@ static int av1_metadata_update_fragment( - CodedBitstreamFragment *frag) - { - AV1MetadataContext *ctx = bsf->priv_data; -- AV1RawOBU td, *obu; - int err, i; - - for (i = 0; i < frag->nb_units; i++) { - if (frag->units[i].type == AV1_OBU_SEQUENCE_HEADER) { -- obu = frag->units[i].content; -+ AV1RawOBU *obu = frag->units[i].content; - err = av1_metadata_update_sequence_header(bsf, &obu->obu.sequence_header); - if (err < 0) - return err; -@@ -124,12 +124,8 @@ static int av1_metadata_update_fragment( - if (ctx->td == BSF_ELEMENT_REMOVE) - ff_cbs_delete_unit(frag, 0); - } else if (pkt && ctx->td == BSF_ELEMENT_INSERT) { -- td = (AV1RawOBU) { -- .header.obu_type = AV1_OBU_TEMPORAL_DELIMITER, -- }; -- - err = ff_cbs_insert_unit_content(frag, 0, AV1_OBU_TEMPORAL_DELIMITER, -- &td, NULL); -+ &ctx->td_obu, NULL); - if (err < 0) { - av_log(bsf, AV_LOG_ERROR, "Failed to insert Temporal Delimiter.\n"); - return err; -@@ -155,6 +151,12 @@ static const CBSBSFType av1_metadata_typ - - static int av1_metadata_init(AVBSFContext *bsf) - { -+ AV1MetadataContext *ctx = bsf->priv_data; -+ -+ ctx->td_obu = (AV1RawOBU) { -+ .header.obu_type = AV1_OBU_TEMPORAL_DELIMITER, -+ }; -+ - return ff_cbs_bsf_generic_init(bsf, &av1_metadata_type); - } - -Index: jellyfin-ffmpeg/libavcodec/clearvideo.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/clearvideo.c -+++ jellyfin-ffmpeg/libavcodec/clearvideo.c -@@ -722,8 +722,8 @@ static av_cold int clv_decode_init(AVCod - } - - c->tile_shift = av_log2(c->tile_size); -- if (1U << c->tile_shift != c->tile_size) { -- av_log(avctx, AV_LOG_ERROR, "Tile size: %d, is not power of 2.\n", c->tile_size); -+ if (1U << c->tile_shift != c->tile_size || c->tile_shift < 1) { -+ av_log(avctx, AV_LOG_ERROR, "Tile size: %d, is not power of 2 > 1\n", c->tile_size); - return AVERROR_INVALIDDATA; - } - -Index: jellyfin-ffmpeg/libavcodec/crystalhd.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/crystalhd.c -+++ jellyfin-ffmpeg/libavcodec/crystalhd.c -@@ -785,6 +785,7 @@ static int crystalhd_receive_frame(AVCod - .flush = flush, \ - .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ -+ .caps_internal = FF_CODEC_CAP_SETS_FRAME_PROPS, \ - .pix_fmts = (const enum AVPixelFormat[]){AV_PIX_FMT_YUYV422, AV_PIX_FMT_NONE}, \ - .wrapper_name = "crystalhd", \ - }; -Index: jellyfin-ffmpeg/libavcodec/cuviddec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/cuviddec.c -+++ jellyfin-ffmpeg/libavcodec/cuviddec.c -@@ -1150,6 +1150,7 @@ static const AVCodecHWConfigInternal *co - .flush = cuvid_flush, \ - .bsfs = bsf_name, \ - .capabilities = AV_CODEC_CAP_DELAY | AV_CODEC_CAP_AVOID_PROBING | AV_CODEC_CAP_HARDWARE, \ -+ .caps_internal = FF_CODEC_CAP_SETS_FRAME_PROPS, \ - .pix_fmts = (const enum AVPixelFormat[]){ AV_PIX_FMT_CUDA, \ - AV_PIX_FMT_NV12, \ - AV_PIX_FMT_P010, \ -Index: jellyfin-ffmpeg/libavcodec/decode.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/decode.c -+++ jellyfin-ffmpeg/libavcodec/decode.c -@@ -233,9 +233,11 @@ int ff_decode_get_packet(AVCodecContext - if (ret < 0) - return ret; - -- ret = extract_packet_props(avctx->internal, pkt); -- if (ret < 0) -- goto finish; -+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { -+ ret = extract_packet_props(avctx->internal, pkt); -+ if (ret < 0) -+ goto finish; -+ } - - ret = apply_param_change(avctx, pkt); - if (ret < 0) -@@ -502,11 +504,13 @@ FF_ENABLE_DEPRECATION_WARNINGS - - pkt->data += consumed; - pkt->size -= consumed; -- avci->last_pkt_props->size -= consumed; // See extract_packet_props() comment. - pkt->pts = AV_NOPTS_VALUE; - pkt->dts = AV_NOPTS_VALUE; -- avci->last_pkt_props->pts = AV_NOPTS_VALUE; -- avci->last_pkt_props->dts = AV_NOPTS_VALUE; -+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { -+ avci->last_pkt_props->size -= consumed; // See extract_packet_props() comment. -+ avci->last_pkt_props->pts = AV_NOPTS_VALUE; -+ avci->last_pkt_props->dts = AV_NOPTS_VALUE; -+ } - } - - if (got_frame) -@@ -548,6 +552,11 @@ static int decode_receive_frame_internal - if (ret == AVERROR_EOF) - avci->draining_done = 1; - -+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS) && -+ IS_EMPTY(avci->last_pkt_props) && av_fifo_size(avci->pkt_props) >= sizeof(*avci->last_pkt_props)) -+ av_fifo_generic_read(avci->pkt_props, -+ avci->last_pkt_props, sizeof(*avci->last_pkt_props), NULL); -+ - if (!ret) { - frame->best_effort_timestamp = guess_correct_pts(avctx, - frame->pts, -@@ -1738,39 +1747,37 @@ int ff_decode_frame_props(AVCodecContext - { AV_PKT_DATA_S12M_TIMECODE, AV_FRAME_DATA_S12M_TIMECODE }, - }; - -- if (IS_EMPTY(pkt) && av_fifo_size(avctx->internal->pkt_props) >= sizeof(*pkt)) -- av_fifo_generic_read(avctx->internal->pkt_props, -- pkt, sizeof(*pkt), NULL); -- -- frame->pts = pkt->pts; -+ if (!(avctx->codec->caps_internal & FF_CODEC_CAP_SETS_FRAME_PROPS)) { -+ frame->pts = pkt->pts; - #if FF_API_PKT_PTS - FF_DISABLE_DEPRECATION_WARNINGS -- frame->pkt_pts = pkt->pts; -+ frame->pkt_pts = pkt->pts; - FF_ENABLE_DEPRECATION_WARNINGS - #endif -- frame->pkt_pos = pkt->pos; -- frame->pkt_duration = pkt->duration; -- frame->pkt_size = pkt->size; -- -- for (int i = 0; i < FF_ARRAY_ELEMS(sd); i++) { -- buffer_size_t size; -- uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size); -- if (packet_sd) { -- AVFrameSideData *frame_sd = av_frame_new_side_data(frame, -- sd[i].frame, -- size); -- if (!frame_sd) -- return AVERROR(ENOMEM); -+ frame->pkt_pos = pkt->pos; -+ frame->pkt_duration = pkt->duration; -+ frame->pkt_size = pkt->size; -+ -+ for (int i = 0; i < FF_ARRAY_ELEMS(sd); i++) { -+ buffer_size_t size; -+ uint8_t *packet_sd = av_packet_get_side_data(pkt, sd[i].packet, &size); -+ if (packet_sd) { -+ AVFrameSideData *frame_sd = av_frame_new_side_data(frame, -+ sd[i].frame, -+ size); -+ if (!frame_sd) -+ return AVERROR(ENOMEM); - -- memcpy(frame_sd->data, packet_sd, size); -+ memcpy(frame_sd->data, packet_sd, size); -+ } - } -- } -- add_metadata_from_side_data(pkt, frame); -+ add_metadata_from_side_data(pkt, frame); - -- if (pkt->flags & AV_PKT_FLAG_DISCARD) { -- frame->flags |= AV_FRAME_FLAG_DISCARD; -- } else { -- frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD); -+ if (pkt->flags & AV_PKT_FLAG_DISCARD) { -+ frame->flags |= AV_FRAME_FLAG_DISCARD; -+ } else { -+ frame->flags = (frame->flags & ~AV_FRAME_FLAG_DISCARD); -+ } - } - frame->reordered_opaque = avctx->reordered_opaque; - -Index: jellyfin-ffmpeg/libavcodec/dpx.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/dpx.c -+++ jellyfin-ffmpeg/libavcodec/dpx.c -@@ -242,6 +242,9 @@ static int decode_frame(AVCodecContext * - return AVERROR_PATCHWELCOME; - } - -+ if (bits_per_color > 31) -+ return AVERROR_INVALIDDATA; -+ - buf += 820; - avctx->sample_aspect_ratio.num = read32(&buf, endian); - avctx->sample_aspect_ratio.den = read32(&buf, endian); -@@ -316,7 +319,7 @@ static int decode_frame(AVCodecContext * - minCV = av_int2float(i); - maxCV = av_int2float(j); - if (bits_per_color >= 1 && -- minCV == 0.0f && maxCV == ((1<color_range = AVCOL_RANGE_JPEG; - } else if (bits_per_color >= 8 && - minCV == (1 <<(bits_per_color - 4)) && -Index: jellyfin-ffmpeg/libavcodec/exr.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/exr.c -+++ jellyfin-ffmpeg/libavcodec/exr.c -@@ -418,7 +418,7 @@ static int huf_decode(VLC *vlc, GetByteC - - init_get_bits(&gbit, gb->buffer, nbits); - while (get_bits_left(&gbit) > 0 && oe < no) { -- uint16_t x = get_vlc2(&gbit, vlc->table, 12, 2); -+ uint16_t x = get_vlc2(&gbit, vlc->table, 12, 3); - - if (x == run_sym) { - int run = get_bits(&gbit, 8); -@@ -1059,11 +1059,11 @@ static int dwa_uncompress(EXRContext *s, - bytestream2_skip(&gb, ac_size); - } - -- if (dc_size > 0) { -+ { - unsigned long dest_len = dc_count * 2LL; - GetByteContext agb = gb; - -- if (dc_count > (6LL * td->xsize * td->ysize + 63) / 64) -+ if (dc_count != dc_w * dc_h * 3) - return AVERROR_INVALIDDATA; - - av_fast_padded_malloc(&td->dc_data, &td->dc_size, FFALIGN(dest_len, 64) * 2); -@@ -1795,6 +1795,7 @@ static int decode_header(EXRContext *s, - ymax = bytestream2_get_le32(gb); - - if (xmin > xmax || ymin > ymax || -+ ymax == INT_MAX || xmax == INT_MAX || - (unsigned)xmax - xmin >= INT_MAX || - (unsigned)ymax - ymin >= INT_MAX) { - ret = AVERROR_INVALIDDATA; -Index: jellyfin-ffmpeg/libavcodec/faxcompr.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/faxcompr.c -+++ jellyfin-ffmpeg/libavcodec/faxcompr.c -@@ -144,6 +144,8 @@ static int decode_uncompressed(AVCodecCo - return AVERROR_INVALIDDATA; - } - cwi = 10 - av_log2(cwi); -+ if (get_bits_left(gb) < cwi + 1) -+ return AVERROR_INVALIDDATA; - skip_bits(gb, cwi + 1); - if (cwi > 5) { - newmode = get_bits1(gb); -@@ -209,6 +211,8 @@ static int decode_group3_1d_line(AVCodec - unsigned int run = 0; - unsigned int t; - for (;;) { -+ if (get_bits_left(gb) <= 0) -+ return AVERROR_INVALIDDATA; - t = get_vlc2(gb, ccitt_vlc[mode].table, 9, 2); - run += t; - if (t < 64) { -@@ -227,7 +231,7 @@ static int decode_group3_1d_line(AVCodec - run = 0; - mode = !mode; - } else if ((int)t == -1) { -- if (show_bits(gb, 12) == 15) { -+ if (get_bits_left(gb) > 12 && show_bits(gb, 12) == 15) { - int ret; - skip_bits(gb, 12); - ret = decode_uncompressed(avctx, gb, &pix_left, &runs, runend, &mode); -@@ -254,7 +258,10 @@ static int decode_group3_2d_line(AVCodec - unsigned int offs = 0, run = 0; - - while (offs < width) { -- int cmode = get_vlc2(gb, ccitt_group3_2d_vlc.table, 9, 1); -+ int cmode; -+ if (get_bits_left(gb) <= 0) -+ return AVERROR_INVALIDDATA; -+ cmode = get_vlc2(gb, ccitt_group3_2d_vlc.table, 9, 1); - if (cmode == -1) { - av_log(avctx, AV_LOG_ERROR, "Incorrect mode VLC\n"); - return AVERROR_INVALIDDATA; -@@ -299,7 +306,10 @@ static int decode_group3_2d_line(AVCodec - mode = !mode; - } - } else if (cmode == 9 || cmode == 10) { -- int xxx = get_bits(gb, 3); -+ int xxx; -+ if (get_bits_left(gb) < 3) -+ return AVERROR_INVALIDDATA; -+ xxx = get_bits(gb, 3); - if (cmode == 9 && xxx == 7) { - int ret; - int pix_left = width - offs; -Index: jellyfin-ffmpeg/libavcodec/h263.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/h263.c -+++ jellyfin-ffmpeg/libavcodec/h263.c -@@ -29,6 +29,7 @@ - - #include - -+#include "libavutil/thread.h" - #include "avcodec.h" - #include "mpegvideo.h" - #include "h263.h" -@@ -38,6 +39,17 @@ - #include "flv.h" - #include "mpeg4video.h" - -+static av_cold void h263_init_rl_inter(void) -+{ -+ static uint8_t h263_rl_inter_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; -+ ff_rl_init(&ff_h263_rl_inter, h263_rl_inter_table); -+} -+ -+av_cold void ff_h263_init_rl_inter(void) -+{ -+ static AVOnce init_static_once = AV_ONCE_INIT; -+ ff_thread_once(&init_static_once, h263_init_rl_inter); -+} - - void ff_h263_update_motion_val(MpegEncContext * s){ - const int mb_xy = s->mb_y * s->mb_stride + s->mb_x; -Index: jellyfin-ffmpeg/libavcodec/h263.h -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/h263.h -+++ jellyfin-ffmpeg/libavcodec/h263.h -@@ -66,6 +66,7 @@ int16_t *ff_h263_pred_motion(MpegEncCont - int *px, int *py); - void ff_h263_encode_init(MpegEncContext *s); - void ff_h263_decode_init_vlc(void); -+void ff_h263_init_rl_inter(void); - int ff_h263_decode_picture_header(MpegEncContext *s); - int ff_h263_decode_gob_header(MpegEncContext *s); - void ff_h263_update_motion_val(MpegEncContext * s); -Index: jellyfin-ffmpeg/libavcodec/h263data.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/h263data.c -+++ jellyfin-ffmpeg/libavcodec/h263data.c -@@ -25,8 +25,6 @@ - - #include - --#include "libavutil/thread.h" -- - #include "h263data.h" - #include "mpegvideo.h" - -@@ -290,15 +288,3 @@ const AVRational ff_h263_pixel_aspect[16 - { 0, 1 }, - { 0, 1 }, - }; -- --static av_cold void h263_init_rl_inter(void) --{ -- static uint8_t h263_rl_inter_table[2][2 * MAX_RUN + MAX_LEVEL + 3]; -- ff_rl_init(&ff_h263_rl_inter, h263_rl_inter_table); --} -- --av_cold void ff_h263_init_rl_inter(void) --{ -- static AVOnce init_static_once = AV_ONCE_INIT; -- ff_thread_once(&init_static_once, h263_init_rl_inter); --} -Index: jellyfin-ffmpeg/libavcodec/h263data.h -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/h263data.h -+++ jellyfin-ffmpeg/libavcodec/h263data.h -@@ -61,7 +61,6 @@ extern const int8_t ff_inter_run[102]; - - extern RLTable ff_h263_rl_inter; - extern RLTable ff_rl_intra_aic; --void ff_h263_init_rl_inter(void); - - extern const uint16_t ff_h263_format[8][2]; - -Index: jellyfin-ffmpeg/libavcodec/internal.h -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/internal.h -+++ jellyfin-ffmpeg/libavcodec/internal.h -@@ -78,6 +78,11 @@ - * Codec handles avctx->thread_count == 0 (auto) internally. - */ - #define FF_CODEC_CAP_AUTO_THREADS (1 << 7) -+/** -+ * Codec handles output frame properties internally instead of letting the -+ * internal logic derive them from AVCodecInternal.last_pkt_props. -+ */ -+#define FF_CODEC_CAP_SETS_FRAME_PROPS (1 << 8) - - /** - * AVCodec.codec_tags termination value -Index: jellyfin-ffmpeg/libavcodec/jpeglsdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/jpeglsdec.c -+++ jellyfin-ffmpeg/libavcodec/jpeglsdec.c -@@ -122,7 +122,7 @@ int ff_jpegls_decode_lse(MJpegDecodeCont - s->avctx->pix_fmt = AV_PIX_FMT_PAL8; - for (i=s->palette_index; i<=maxtab; i++) { - uint8_t k = i << shift; -- pal[k] = 0; -+ pal[k] = wt < 4 ? 0xFF000000 : 0; - for (j=0; jgb, 8) << (8*(wt-j-1)); - } -Index: jellyfin-ffmpeg/libavcodec/lpc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/lpc.c -+++ jellyfin-ffmpeg/libavcodec/lpc.c -@@ -189,7 +189,7 @@ double ff_lpc_calc_ref_coefs_f(LPCContex - compute_ref_coefs(autoc, order, ref, error); - for (i = 0; i < order; i++) - avg_err = (avg_err + error[i])/2.0f; -- return signal/avg_err; -+ return avg_err ? signal/avg_err : NAN; - } - - /** -Index: jellyfin-ffmpeg/libavcodec/mpegvideo_enc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/mpegvideo_enc.c -+++ jellyfin-ffmpeg/libavcodec/mpegvideo_enc.c -@@ -2016,6 +2016,7 @@ FF_ENABLE_DEPRECATION_WARNINGS - break; - default: - av_log(avctx, AV_LOG_ERROR, "vbv buffer overflow\n"); -+ s->stuffing_bits = 0; - } - flush_put_bits(&s->pb); - s->frame_bits = put_bits_count(&s->pb); -Index: jellyfin-ffmpeg/libavcodec/nellymoserenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/nellymoserenc.c -+++ jellyfin-ffmpeg/libavcodec/nellymoserenc.c -@@ -138,10 +138,8 @@ static av_cold int encode_end(AVCodecCon - - ff_mdct_end(&s->mdct_ctx); - -- if (s->avctx->trellis) { -- av_freep(&s->opt); -- av_freep(&s->path); -- } -+ av_freep(&s->opt); -+ av_freep(&s->path); - ff_af_queue_close(&s->afq); - av_freep(&s->fdsp); - -Index: jellyfin-ffmpeg/libavcodec/nvenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/nvenc.c -+++ jellyfin-ffmpeg/libavcodec/nvenc.c -@@ -144,6 +144,70 @@ static int nvenc_print_error(AVCodecCont - return ret; - } - -+typedef struct GUIDTuple { -+ const GUID guid; -+ int flags; -+} GUIDTuple; -+ -+#define PRESET_ALIAS(alias, name, ...) \ -+ [PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ } -+ -+#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__) -+ -+static void nvenc_map_preset(NvencContext *ctx) -+{ -+ GUIDTuple presets[] = { -+#ifdef NVENC_HAVE_NEW_PRESETS -+ PRESET(P1), -+ PRESET(P2), -+ PRESET(P3), -+ PRESET(P4), -+ PRESET(P5), -+ PRESET(P6), -+ PRESET(P7), -+ PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES), -+ PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS), -+ PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS), -+ // Compat aliases -+ PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET), -+ PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET), -+ PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET), -+ PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET), -+ PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -+ PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -+ PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -+ PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), -+ PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), -+#else -+ PRESET(DEFAULT), -+ PRESET(HP), -+ PRESET(HQ), -+ PRESET(BD), -+ PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES), -+ PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS), -+ PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS), -+ PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY), -+ PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY), -+ PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY), -+ PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS), -+ PRESET(LOSSLESS_HP, NVENC_LOSSLESS), -+#endif -+ }; -+ -+ GUIDTuple *t = &presets[ctx->preset]; -+ -+ ctx->init_encode_params.presetGUID = t->guid; -+ ctx->flags = t->flags; -+ -+#ifdef NVENC_HAVE_NEW_PRESETS -+ if (ctx->tuning_info == NV_ENC_TUNING_INFO_LOSSLESS) -+ ctx->flags |= NVENC_LOSSLESS; -+#endif -+} -+ -+#undef PRESET -+#undef PRESET_ALIAS -+ - static void nvenc_print_driver_requirement(AVCodecContext *avctx, int level) - { - #if NVENCAPI_CHECK_VERSION(11, 1) -@@ -358,7 +422,7 @@ static int nvenc_check_capabilities(AVCo - } - - ret = nvenc_check_cap(avctx, NV_ENC_CAPS_SUPPORT_LOSSLESS_ENCODE); -- if (ctx->preset >= PRESET_LOSSLESS_DEFAULT && ret <= 0) { -+ if (ctx->flags & NVENC_LOSSLESS && ret <= 0) { - av_log(avctx, AV_LOG_WARNING, "Lossless encoding not supported\n"); - return AVERROR(ENOSYS); - } -@@ -548,6 +612,11 @@ static av_cold int nvenc_setup_device(AV - return AVERROR_BUG; - } - -+ nvenc_map_preset(ctx); -+ -+ if (ctx->flags & NVENC_DEPRECATED_PRESET) -+ av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n"); -+ - if (avctx->pix_fmt == AV_PIX_FMT_CUDA || avctx->pix_fmt == AV_PIX_FMT_D3D11 || avctx->hw_frames_ctx || avctx->hw_device_ctx) { - AVHWFramesContext *frames_ctx; - AVHWDeviceContext *hwdev_ctx; -@@ -638,65 +707,6 @@ static av_cold int nvenc_setup_device(AV - return 0; - } - --typedef struct GUIDTuple { -- const GUID guid; -- int flags; --} GUIDTuple; -- --#define PRESET_ALIAS(alias, name, ...) \ -- [PRESET_ ## alias] = { NV_ENC_PRESET_ ## name ## _GUID, __VA_ARGS__ } -- --#define PRESET(name, ...) PRESET_ALIAS(name, name, __VA_ARGS__) -- --static void nvenc_map_preset(NvencContext *ctx) --{ -- GUIDTuple presets[] = { --#ifdef NVENC_HAVE_NEW_PRESETS -- PRESET(P1), -- PRESET(P2), -- PRESET(P3), -- PRESET(P4), -- PRESET(P5), -- PRESET(P6), -- PRESET(P7), -- PRESET_ALIAS(SLOW, P7, NVENC_TWO_PASSES), -- PRESET_ALIAS(MEDIUM, P4, NVENC_ONE_PASS), -- PRESET_ALIAS(FAST, P1, NVENC_ONE_PASS), -- // Compat aliases -- PRESET_ALIAS(DEFAULT, P4, NVENC_DEPRECATED_PRESET), -- PRESET_ALIAS(HP, P1, NVENC_DEPRECATED_PRESET), -- PRESET_ALIAS(HQ, P7, NVENC_DEPRECATED_PRESET), -- PRESET_ALIAS(BD, P5, NVENC_DEPRECATED_PRESET), -- PRESET_ALIAS(LOW_LATENCY_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -- PRESET_ALIAS(LOW_LATENCY_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -- PRESET_ALIAS(LOW_LATENCY_HQ, P7, NVENC_DEPRECATED_PRESET | NVENC_LOWLATENCY), -- PRESET_ALIAS(LOSSLESS_DEFAULT, P4, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), -- PRESET_ALIAS(LOSSLESS_HP, P1, NVENC_DEPRECATED_PRESET | NVENC_LOSSLESS), --#else -- PRESET(DEFAULT), -- PRESET(HP), -- PRESET(HQ), -- PRESET(BD), -- PRESET_ALIAS(SLOW, HQ, NVENC_TWO_PASSES), -- PRESET_ALIAS(MEDIUM, HQ, NVENC_ONE_PASS), -- PRESET_ALIAS(FAST, HP, NVENC_ONE_PASS), -- PRESET(LOW_LATENCY_DEFAULT, NVENC_LOWLATENCY), -- PRESET(LOW_LATENCY_HP, NVENC_LOWLATENCY), -- PRESET(LOW_LATENCY_HQ, NVENC_LOWLATENCY), -- PRESET(LOSSLESS_DEFAULT, NVENC_LOSSLESS), -- PRESET(LOSSLESS_HP, NVENC_LOSSLESS), --#endif -- }; -- -- GUIDTuple *t = &presets[ctx->preset]; -- -- ctx->init_encode_params.presetGUID = t->guid; -- ctx->flags = t->flags; --} -- --#undef PRESET --#undef PRESET_ALIAS -- - static av_cold void set_constqp(AVCodecContext *avctx) - { - NvencContext *ctx = avctx->priv_data; -@@ -1254,18 +1264,15 @@ static av_cold int nvenc_setup_encoder(A - - ctx->init_encode_params.encodeConfig = &ctx->encode_config; - -- nvenc_map_preset(ctx); -- -- if (ctx->flags & NVENC_DEPRECATED_PRESET) -- av_log(avctx, AV_LOG_WARNING, "The selected preset is deprecated. Use p1 to p7 + -tune or fast/medium/slow.\n"); -- - preset_config.version = NV_ENC_PRESET_CONFIG_VER; - preset_config.presetCfg.version = NV_ENC_CONFIG_VER; - - #ifdef NVENC_HAVE_NEW_PRESETS - ctx->init_encode_params.tuningInfo = ctx->tuning_info; - -- if (ctx->flags & NVENC_LOWLATENCY) -+ if (ctx->flags & NVENC_LOSSLESS) -+ ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOSSLESS; -+ else if (ctx->flags & NVENC_LOWLATENCY) - ctx->init_encode_params.tuningInfo = NV_ENC_TUNING_INFO_LOW_LATENCY; - - nv_status = p_nvenc->nvEncGetEncodePresetConfigEx(ctx->nvencoder, -@@ -1307,9 +1314,6 @@ static av_cold int nvenc_setup_encoder(A - * */ - if (ctx->rc_lookahead == 0 && ctx->encode_config.rcParams.enableLookahead) - ctx->rc_lookahead = ctx->encode_config.rcParams.lookaheadDepth; -- -- if (ctx->init_encode_params.tuningInfo == NV_ENC_TUNING_INFO_LOSSLESS) -- ctx->flags |= NVENC_LOSSLESS; - #endif - - if (ctx->weighted_pred == 1) -Index: jellyfin-ffmpeg/libavcodec/nvenc.h -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/nvenc.h -+++ jellyfin-ffmpeg/libavcodec/nvenc.h -@@ -103,7 +103,7 @@ enum { - PRESET_LOW_LATENCY_DEFAULT , - PRESET_LOW_LATENCY_HQ , - PRESET_LOW_LATENCY_HP, -- PRESET_LOSSLESS_DEFAULT, // lossless presets must be the last ones -+ PRESET_LOSSLESS_DEFAULT, - PRESET_LOSSLESS_HP, - #ifdef NVENC_HAVE_NEW_PRESETS - PRESET_P1, -Index: jellyfin-ffmpeg/libavcodec/nvenc_hevc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/nvenc_hevc.c -+++ jellyfin-ffmpeg/libavcodec/nvenc_hevc.c -@@ -148,7 +148,7 @@ static const AVOption options[] = { - { "middle", "", 0, AV_OPT_TYPE_CONST, { .i64 = 2 }, 0, 0, VE, "b_ref_mode" }, - #endif - { "a53cc", "Use A53 Closed Captions (if available)", OFFSET(a53_cc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, -- { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 1 }, 0, 1, VE }, -+ { "s12m_tc", "Use timecode (if available)", OFFSET(s12m_tc), AV_OPT_TYPE_BOOL, { .i64 = 0 }, 0, 1, VE }, - { "dpb_size", "Specifies the DPB size used for encoding (0 means automatic)", - OFFSET(dpb_size), AV_OPT_TYPE_INT, { .i64 = 0 }, 0, INT_MAX, VE }, - #ifdef NVENC_HAVE_MULTIPASS -Index: jellyfin-ffmpeg/libavcodec/pngdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/pngdec.c -+++ jellyfin-ffmpeg/libavcodec/pngdec.c -@@ -1644,7 +1644,7 @@ static int decode_frame_apng(AVCodecCont - if (!(avctx->active_thread_type & FF_THREAD_FRAME)) { - if (s->dispose_op == APNG_DISPOSE_OP_PREVIOUS) { - ff_thread_release_buffer(avctx, &s->picture); -- } else if (s->dispose_op == APNG_DISPOSE_OP_NONE) { -+ } else { - ff_thread_release_buffer(avctx, &s->last_picture); - FFSWAP(ThreadFrame, s->picture, s->last_picture); - } -@@ -1693,8 +1693,8 @@ static int update_thread_context(AVCodec - pdst->hdr_state |= psrc->hdr_state; - } - -- src_frame = psrc->dispose_op == APNG_DISPOSE_OP_NONE ? -- &psrc->picture : &psrc->last_picture; -+ src_frame = psrc->dispose_op == APNG_DISPOSE_OP_PREVIOUS ? -+ &psrc->last_picture : &psrc->picture; - - ff_thread_release_buffer(dst, &pdst->last_picture); - if (src_frame && src_frame->f->data[0]) { -Index: jellyfin-ffmpeg/libavcodec/rv10.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/rv10.c -+++ jellyfin-ffmpeg/libavcodec/rv10.c -@@ -154,7 +154,7 @@ static int rv10_decode_picture_header(Mp - return mb_count; - } - --static int rv20_decode_picture_header(RVDecContext *rv) -+static int rv20_decode_picture_header(RVDecContext *rv, int whole_size) - { - MpegEncContext *s = &rv->m; - int seq, mb_pos, i, ret; -@@ -232,6 +232,10 @@ static int rv20_decode_picture_header(RV - "attempting to change resolution to %dx%d\n", new_w, new_h); - if (av_image_check_size(new_w, new_h, 0, s->avctx) < 0) - return AVERROR_INVALIDDATA; -+ -+ if (whole_size < (new_w + 15)/16 * ((new_h + 15)/16) / 8) -+ return AVERROR_INVALIDDATA; -+ - ff_mpv_common_end(s); - - // attempt to keep aspect during typical resolution switches -@@ -447,7 +451,7 @@ static int rv10_decode_packet(AVCodecCon - if (s->codec_id == AV_CODEC_ID_RV10) - mb_count = rv10_decode_picture_header(s); - else -- mb_count = rv20_decode_picture_header(rv); -+ mb_count = rv20_decode_picture_header(rv, whole_size); - if (mb_count < 0) { - if (mb_count != ERROR_SKIP_FRAME) - av_log(s->avctx, AV_LOG_ERROR, "HEADER ERROR\n"); -Index: jellyfin-ffmpeg/libavcodec/svq1enc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/svq1enc.c -+++ jellyfin-ffmpeg/libavcodec/svq1enc.c -@@ -487,9 +487,10 @@ static av_cold int svq1_encode_end(AVCod - SVQ1EncContext *const s = avctx->priv_data; - int i; - -- av_log(avctx, AV_LOG_DEBUG, "RD: %f\n", -- s->rd_total / (double)(avctx->width * avctx->height * -- avctx->frame_number)); -+ if (avctx->frame_number) -+ av_log(avctx, AV_LOG_DEBUG, "RD: %f\n", -+ s->rd_total / (double)(avctx->width * avctx->height * -+ avctx->frame_number)); - - s->m.mb_type = NULL; - ff_mpv_common_end(&s->m); -Index: jellyfin-ffmpeg/libavcodec/ttadata.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/ttadata.c -+++ jellyfin-ffmpeg/libavcodec/ttadata.c -@@ -30,7 +30,8 @@ const uint32_t ff_tta_shift_1[] = { - 0x01000000, 0x02000000, 0x04000000, 0x08000000, - 0x10000000, 0x20000000, 0x40000000, 0x80000000, - 0x80000000, 0x80000000, 0x80000000, 0x80000000, -- 0x80000000, 0x80000000, 0x80000000, 0x80000000 -+ 0x80000000, 0x80000000, 0x80000000, 0x80000000, -+ 0xFFFFFFFF - }; - - const uint32_t * const ff_tta_shift_16 = ff_tta_shift_1 + 4; -Index: jellyfin-ffmpeg/libavcodec/ttmlenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/ttmlenc.c -+++ jellyfin-ffmpeg/libavcodec/ttmlenc.c -@@ -206,5 +206,5 @@ AVCodec ff_ttml_encoder = { - .init = ttml_encode_init, - .encode_sub = ttml_encode_frame, - .close = ttml_encode_close, -- .capabilities = FF_CODEC_CAP_INIT_CLEANUP, -+ .caps_internal = FF_CODEC_CAP_INIT_CLEANUP, - }; -Index: jellyfin-ffmpeg/libavcodec/utils.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/utils.c -+++ jellyfin-ffmpeg/libavcodec/utils.c -@@ -272,6 +272,16 @@ void avcodec_align_dimensions2(AVCodecCo - w_align = 8; - h_align = 8; - } -+ if (s->codec_id == AV_CODEC_ID_MJPEG || -+ s->codec_id == AV_CODEC_ID_MJPEGB || -+ s->codec_id == AV_CODEC_ID_LJPEG || -+ s->codec_id == AV_CODEC_ID_SMVJPEG || -+ s->codec_id == AV_CODEC_ID_AMV || -+ s->codec_id == AV_CODEC_ID_SP5X || -+ s->codec_id == AV_CODEC_ID_JPEGLS) { -+ w_align = 8; -+ h_align = 2*8; -+ } - break; - case AV_PIX_FMT_BGR24: - if ((s->codec_id == AV_CODEC_ID_MSZH) || -@@ -773,21 +783,33 @@ static int get_audio_frame_duration(enum - if (ba > 0) { - /* calc from frame_bytes, channels, and block_align */ - int blocks = frame_bytes / ba; -+ int64_t tmp = 0; - switch (id) { - case AV_CODEC_ID_ADPCM_IMA_WAV: - if (bps < 2 || bps > 5) - return 0; -- return blocks * (1 + (ba - 4 * ch) / (bps * ch) * 8); -+ tmp = blocks * (1LL + (ba - 4 * ch) / (bps * ch) * 8); -+ break; - case AV_CODEC_ID_ADPCM_IMA_DK3: -- return blocks * (((ba - 16) * 2 / 3 * 4) / ch); -+ tmp = blocks * (((ba - 16LL) * 2 / 3 * 4) / ch); -+ break; - case AV_CODEC_ID_ADPCM_IMA_DK4: -- return blocks * (1 + (ba - 4 * ch) * 2 / ch); -+ tmp = blocks * (1 + (ba - 4LL * ch) * 2 / ch); -+ break; - case AV_CODEC_ID_ADPCM_IMA_RAD: -- return blocks * ((ba - 4 * ch) * 2 / ch); -+ tmp = blocks * ((ba - 4LL * ch) * 2 / ch); -+ break; - case AV_CODEC_ID_ADPCM_MS: -- return blocks * (2 + (ba - 7 * ch) * 2LL / ch); -+ tmp = blocks * (2 + (ba - 7LL * ch) * 2LL / ch); -+ break; - case AV_CODEC_ID_ADPCM_MTAF: -- return blocks * (ba - 16) * 2 / ch; -+ tmp = blocks * (ba - 16LL) * 2 / ch; -+ break; -+ } -+ if (tmp) { -+ if (tmp != (int)tmp) -+ return 0; -+ return tmp; - } - } - -Index: jellyfin-ffmpeg/libavcodec/vaapi_av1.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/vaapi_av1.c -+++ jellyfin-ffmpeg/libavcodec/vaapi_av1.c -@@ -292,7 +292,7 @@ static int vaapi_av1_decode_slice(AVCode - err = ff_vaapi_decode_make_slice_buffer(avctx, pic, &slice_param, - sizeof(VASliceParameterBufferAV1), - buffer, -- s->tile_group_info[i].tile_size); -+ size); - if (err) { - ff_vaapi_decode_cancel(avctx, pic); - return err; -Index: jellyfin-ffmpeg/libavcodec/vc1.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/vc1.c -+++ jellyfin-ffmpeg/libavcodec/vc1.c -@@ -672,6 +672,8 @@ int ff_vc1_parse_frame_header(VC1Context - if (v->s.pict_type == AV_PICTURE_TYPE_P) - v->rnd ^= 1; - -+ if (get_bits_left(gb) < 5) -+ return AVERROR_INVALIDDATA; - /* Quantizer stuff */ - pqindex = get_bits(gb, 5); - if (!pqindex) -@@ -764,6 +766,9 @@ int ff_vc1_parse_frame_header(VC1Context - av_log(v->s.avctx, AV_LOG_DEBUG, "MB Skip plane encoding: " - "Imode: %i, Invert: %i\n", status>>1, status&1); - -+ if (get_bits_left(gb) < 4) -+ return AVERROR_INVALIDDATA; -+ - /* Hopefully this is correct for P-frames */ - v->s.mv_table_index = get_bits(gb, 2); //but using ff_vc1_ tables - v->cbptab = get_bits(gb, 2); -Index: jellyfin-ffmpeg/libavcodec/vc2enc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavcodec/vc2enc.c -+++ jellyfin-ffmpeg/libavcodec/vc2enc.c -@@ -982,6 +982,8 @@ static av_cold int vc2_encode_frame(AVCo - } - - s->slice_min_bytes = s->slice_max_bytes - s->slice_max_bytes*(s->tolerance/100.0f); -+ if (s->slice_min_bytes < 0) -+ return AVERROR(EINVAL); - - ret = encode_frame(s, avpkt, frame, aux_data, header_size, s->interlaced); - if (ret) -Index: jellyfin-ffmpeg/libavfilter/f_metadata.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/f_metadata.c -+++ jellyfin-ffmpeg/libavfilter/f_metadata.c -@@ -304,9 +304,6 @@ static int filter_frame(AVFilterLink *in - AVDictionary **metadata = &frame->metadata; - AVDictionaryEntry *e; - -- if (!*metadata && s->mode != METADATA_ADD) -- return ff_filter_frame(outlink, frame); -- - e = av_dict_get(*metadata, !s->key ? "" : s->key, NULL, - !s->key ? AV_DICT_IGNORE_SUFFIX: 0); - -Index: jellyfin-ffmpeg/libavfilter/vf_dctdnoiz.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_dctdnoiz.c -+++ jellyfin-ffmpeg/libavfilter/vf_dctdnoiz.c -@@ -564,6 +564,9 @@ static int config_input(AVFilterLink *in - inlink->h - s->pr_height); - - max_slice_h = s->pr_height / ((s->bsize - 1) * 2); -+ if (max_slice_h == 0) -+ return AVERROR(EINVAL); -+ - s->nb_threads = FFMIN3(MAX_THREADS, ff_filter_get_nb_threads(ctx), max_slice_h); - av_log(ctx, AV_LOG_DEBUG, "threads: [max=%d hmax=%d user=%d] => %d\n", - MAX_THREADS, max_slice_h, ff_filter_get_nb_threads(ctx), s->nb_threads); -Index: jellyfin-ffmpeg/libavfilter/vf_overlay_cuda.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_overlay_cuda.c -+++ jellyfin-ffmpeg/libavfilter/vf_overlay_cuda.c -@@ -63,6 +63,7 @@ typedef struct OverlayCUDAContext { - enum AVPixelFormat in_format_overlay; - enum AVPixelFormat in_format_main; - -+ AVBufferRef *hw_device_ctx; - AVCUDADeviceContext *hwctx; - - CUcontext cu_ctx; -@@ -256,6 +257,9 @@ static av_cold void overlay_cuda_uninit( - CHECK_CU(cu->cuModuleUnload(ctx->cu_module)); - CHECK_CU(cu->cuCtxPopCurrent(&dummy)); - } -+ -+ av_buffer_unref(&ctx->hw_device_ctx); -+ ctx->hwctx = NULL; - } - - /** -@@ -341,13 +345,19 @@ static int overlay_cuda_config_output(AV - - // initialize - -- ctx->hwctx = frames_ctx->device_ctx->hwctx; -+ ctx->hw_device_ctx = av_buffer_ref(frames_ctx->device_ref); -+ if (!ctx->hw_device_ctx) -+ return AVERROR(ENOMEM); -+ ctx->hwctx = ((AVHWDeviceContext*)ctx->hw_device_ctx->data)->hwctx; -+ - cuda_ctx = ctx->hwctx->cuda_ctx; - ctx->fs.time_base = inlink->time_base; - - ctx->cu_stream = ctx->hwctx->stream; - - outlink->hw_frames_ctx = av_buffer_ref(inlink->hw_frames_ctx); -+ if (!outlink->hw_frames_ctx) -+ return AVERROR(ENOMEM); - - // load functions - -Index: jellyfin-ffmpeg/libavfilter/vf_vmafmotion.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_vmafmotion.c -+++ jellyfin-ffmpeg/libavfilter/vf_vmafmotion.c -@@ -238,6 +238,9 @@ int ff_vmafmotion_init(VMAFMotionData *s - int i; - const AVPixFmtDescriptor *desc = av_pix_fmt_desc_get(fmt); - -+ if (w < 3 || h < 3) -+ return AVERROR(EINVAL); -+ - s->width = w; - s->height = h; - s->stride = FFALIGN(w * sizeof(uint16_t), 32); -Index: jellyfin-ffmpeg/libavfilter/vf_yadif.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavfilter/vf_yadif.c -+++ jellyfin-ffmpeg/libavfilter/vf_yadif.c -@@ -123,20 +123,22 @@ static void filter_edges(void *dst1, voi - uint8_t *next2 = parity ? cur : next; - - const int edge = MAX_ALIGN - 1; -+ int offset = FFMAX(w - edge, 3); - - /* Only edge pixels need to be processed here. A constant value of false - * for is_not_edge should let the compiler ignore the whole branch. */ -- FILTER(0, 3, 0) -+ FILTER(0, FFMIN(3, w), 0) - -- dst = (uint8_t*)dst1 + w - edge; -- prev = (uint8_t*)prev1 + w - edge; -- cur = (uint8_t*)cur1 + w - edge; -- next = (uint8_t*)next1 + w - edge; -+ dst = (uint8_t*)dst1 + offset; -+ prev = (uint8_t*)prev1 + offset; -+ cur = (uint8_t*)cur1 + offset; -+ next = (uint8_t*)next1 + offset; - prev2 = (uint8_t*)(parity ? prev : cur); - next2 = (uint8_t*)(parity ? cur : next); - -- FILTER(w - edge, w - 3, 1) -- FILTER(w - 3, w, 0) -+ FILTER(offset, w - 3, 1) -+ offset = FFMAX(offset, w - 3); -+ FILTER(offset, w, 0) - } - - -@@ -170,21 +172,23 @@ static void filter_edges_16bit(void *dst - uint16_t *next2 = parity ? cur : next; - - const int edge = MAX_ALIGN / 2 - 1; -+ int offset = FFMAX(w - edge, 3); - - mrefs /= 2; - prefs /= 2; - -- FILTER(0, 3, 0) -+ FILTER(0, FFMIN(3, w), 0) - -- dst = (uint16_t*)dst1 + w - edge; -- prev = (uint16_t*)prev1 + w - edge; -- cur = (uint16_t*)cur1 + w - edge; -- next = (uint16_t*)next1 + w - edge; -+ dst = (uint16_t*)dst1 + offset; -+ prev = (uint16_t*)prev1 + offset; -+ cur = (uint16_t*)cur1 + offset; -+ next = (uint16_t*)next1 + offset; - prev2 = (uint16_t*)(parity ? prev : cur); - next2 = (uint16_t*)(parity ? cur : next); - -- FILTER(w - edge, w - 3, 1) -- FILTER(w - 3, w, 0) -+ FILTER(offset, w - 3, 1) -+ offset = FFMAX(offset, w - 3); -+ FILTER(offset, w, 0) - } - - static int filter_slice(AVFilterContext *ctx, void *arg, int jobnr, int nb_jobs) -Index: jellyfin-ffmpeg/libavformat/asfdec_o.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/asfdec_o.c -+++ jellyfin-ffmpeg/libavformat/asfdec_o.c -@@ -685,7 +685,7 @@ static int asf_read_properties(AVFormatC - return 0; - } - --static int parse_video_info(AVIOContext *pb, AVStream *st) -+static int parse_video_info(AVFormatContext *avfmt, AVIOContext *pb, AVStream *st) - { - uint16_t size_asf; // ASF-specific Format Data size - uint32_t size_bmp; // BMP_HEADER-specific Format Data size -@@ -700,19 +700,10 @@ static int parse_video_info(AVIOContext - st->codecpar->codec_id = ff_codec_get_id(ff_codec_bmp_tags, tag); - size_bmp = FFMAX(size_asf, size_bmp); - -- if (size_bmp > BMP_HEADER_SIZE && -- size_bmp < INT_MAX - AV_INPUT_BUFFER_PADDING_SIZE) { -- int ret; -- st->codecpar->extradata_size = size_bmp - BMP_HEADER_SIZE; -- if (!(st->codecpar->extradata = av_malloc(st->codecpar->extradata_size + -- AV_INPUT_BUFFER_PADDING_SIZE))) { -- st->codecpar->extradata_size = 0; -- return AVERROR(ENOMEM); -- } -- memset(st->codecpar->extradata + st->codecpar->extradata_size , 0, -- AV_INPUT_BUFFER_PADDING_SIZE); -- if ((ret = avio_read(pb, st->codecpar->extradata, -- st->codecpar->extradata_size)) < 0) -+ if (size_bmp > BMP_HEADER_SIZE) { -+ int ret = ff_get_extradata(avfmt, st->codecpar, pb, size_bmp - BMP_HEADER_SIZE); -+ -+ if (ret < 0) - return ret; - } - return 0; -@@ -795,7 +786,7 @@ static int asf_read_stream_properties(AV - break; - case AVMEDIA_TYPE_VIDEO: - asf_st->type = AVMEDIA_TYPE_VIDEO; -- if ((ret = parse_video_info(pb, st)) < 0) -+ if ((ret = parse_video_info(s, pb, st)) < 0) - return ret; - break; - default: -Index: jellyfin-ffmpeg/libavformat/avio.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/avio.c -+++ jellyfin-ffmpeg/libavformat/avio.c -@@ -316,8 +316,11 @@ int ffurl_open_whitelist(URLContext **pu - int ret = ffurl_alloc(puc, filename, flags, int_cb); - if (ret < 0) - return ret; -- if (parent) -- av_opt_copy(*puc, parent); -+ if (parent) { -+ ret = av_opt_copy(*puc, parent); -+ if (ret < 0) -+ goto fail; -+ } - if (options && - (ret = av_opt_set_dict(*puc, options)) < 0) - goto fail; -Index: jellyfin-ffmpeg/libavformat/cafdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/cafdec.c -+++ jellyfin-ffmpeg/libavformat/cafdec.c -@@ -79,7 +79,7 @@ static int read_desc_chunk(AVFormatConte - st->codecpar->channels = avio_rb32(pb); - st->codecpar->bits_per_coded_sample = avio_rb32(pb); - -- if (caf->bytes_per_packet < 0 || caf->frames_per_packet < 0) -+ if (caf->bytes_per_packet < 0 || caf->frames_per_packet < 0 || st->codecpar->channels < 0) - return AVERROR_INVALIDDATA; - - /* calculate bit rate for constant size packets */ -Index: jellyfin-ffmpeg/libavformat/fifo.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/fifo.c -+++ jellyfin-ffmpeg/libavformat/fifo.c -@@ -593,7 +593,7 @@ static int fifo_write_packet(AVFormatCon - goto fail; - } - -- if (fifo->timeshift && pkt->dts != AV_NOPTS_VALUE) -+ if (fifo->timeshift && pkt && pkt->dts != AV_NOPTS_VALUE) - atomic_fetch_add_explicit(&fifo->queue_duration, next_duration(avf, pkt, &fifo->last_sent_dts), memory_order_relaxed); - - return ret; -Index: jellyfin-ffmpeg/libavformat/id3v2.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/id3v2.c -+++ jellyfin-ffmpeg/libavformat/id3v2.c -@@ -816,7 +816,7 @@ static void id3v2_parse(AVIOContext *pb, - int isv34, unsync; - unsigned tlen; - char tag[5]; -- int64_t next, end = avio_tell(pb) + len; -+ int64_t next, end = avio_tell(pb); - int taghdrlen; - const char *reason = NULL; - AVIOContext pb_local; -@@ -828,6 +828,10 @@ static void id3v2_parse(AVIOContext *pb, - av_unused int uncompressed_buffer_size = 0; - const char *comm_frame; - -+ if (end > INT64_MAX - len - 10) -+ return; -+ end += len; -+ - av_log(s, AV_LOG_DEBUG, "id3v2 ver:%d flags:%02X len:%d\n", version, flags, len); - - switch (version) { -Index: jellyfin-ffmpeg/libavformat/matroskaenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/matroskaenc.c -+++ jellyfin-ffmpeg/libavformat/matroskaenc.c -@@ -1768,6 +1768,7 @@ static int mkv_write_attachments(AVForma - put_ebml_string(dyn_cp, MATROSKA_ID_FILEDESC, t->value); - if (!(t = av_dict_get(st->metadata, "filename", NULL, 0))) { - av_log(s, AV_LOG_ERROR, "Attachment stream %d has no filename tag.\n", i); -+ ffio_free_dyn_buf(&dyn_cp); - return AVERROR(EINVAL); - } - put_ebml_string(dyn_cp, MATROSKA_ID_FILENAME, t->value); -Index: jellyfin-ffmpeg/libavformat/moflex.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/moflex.c -+++ jellyfin-ffmpeg/libavformat/moflex.c -@@ -172,7 +172,6 @@ static int moflex_read_sync(AVFormatCont - unsigned type, ssize, codec_id = 0; - unsigned codec_type, width = 0, height = 0, sample_rate = 0, channels = 0; - int stream_index = -1; -- int format; - AVRational fps; - - read_var_byte(s, &type); -@@ -213,7 +212,6 @@ static int moflex_read_sync(AVFormatCont - fps.den = avio_rb16(pb); - width = avio_rb16(pb); - height = avio_rb16(pb); -- format = AV_PIX_FMT_YUV420P; - avio_skip(pb, type == 3 ? 3 : 2); - break; - case 4: -@@ -235,7 +233,6 @@ static int moflex_read_sync(AVFormatCont - st->codecpar->height = height; - st->codecpar->sample_rate= sample_rate; - st->codecpar->channels = channels; -- st->codecpar->format = format; - st->priv_data = av_packet_alloc(); - if (!st->priv_data) - return AVERROR(ENOMEM); -Index: jellyfin-ffmpeg/libavformat/mov.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/mov.c -+++ jellyfin-ffmpeg/libavformat/mov.c -@@ -4700,6 +4700,8 @@ static int mov_read_chap(MOVContext *c, - for (i = 0; i < num && !pb->eof_reached; i++) - c->chapter_tracks[i] = avio_rb32(pb); - -+ c->nb_chapter_tracks = i; -+ - return 0; - } - -@@ -5124,7 +5126,9 @@ static int mov_read_sidx(MOVContext *c, - if (frag_stream_info) - frag_stream_info->sidx_pts = timestamp; - -- if (av_sat_add64(offset, size) != offset + size) -+ if (av_sat_add64(offset, size) != offset + size || -+ av_sat_add64(pts, duration) != pts + (uint64_t)duration -+ ) - return AVERROR_INVALIDDATA; - offset += size; - pts += duration; -@@ -5464,7 +5468,7 @@ static int mov_read_mdcv(MOVContext *c, - - sc = c->fc->streams[c->fc->nb_streams - 1]->priv_data; - -- if (atom.size < 24) { -+ if (atom.size < 24 || sc->mastering) { - av_log(c->fc, AV_LOG_ERROR, "Invalid Mastering Display Color Volume box\n"); - return AVERROR_INVALIDDATA; - } -@@ -5512,6 +5516,11 @@ static int mov_read_coll(MOVContext *c, - } - avio_skip(pb, 3); /* flags */ - -+ if (sc->coll){ -+ av_log(c->fc, AV_LOG_WARNING, "Ignoring duplicate COLL\n"); -+ return 0; -+ } -+ - sc->coll = av_content_light_metadata_alloc(&sc->coll_size); - if (!sc->coll) - return AVERROR(ENOMEM); -Index: jellyfin-ffmpeg/libavformat/movenc.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/movenc.c -+++ jellyfin-ffmpeg/libavformat/movenc.c -@@ -797,6 +797,7 @@ static int mov_write_dfla_tag(AVIOContex - static int mov_write_dops_tag(AVFormatContext *s, AVIOContext *pb, MOVTrack *track) - { - int64_t pos = avio_tell(pb); -+ int channels, channel_map; - avio_wb32(pb, 0); - ffio_wfourcc(pb, "dOps"); - avio_w8(pb, 0); /* Version */ -@@ -807,12 +808,22 @@ static int mov_write_dops_tag(AVFormatCo - /* extradata contains an Ogg OpusHead, other than byte-ordering and - OpusHead's preceeding magic/version, OpusSpecificBox is currently - identical. */ -- avio_w8(pb, AV_RB8(track->par->extradata + 9)); /* OuputChannelCount */ -+ channels = AV_RB8(track->par->extradata + 9); -+ channel_map = AV_RB8(track->par->extradata + 18); -+ -+ avio_w8(pb, channels); /* OuputChannelCount */ - avio_wb16(pb, AV_RL16(track->par->extradata + 10)); /* PreSkip */ - avio_wb32(pb, AV_RL32(track->par->extradata + 12)); /* InputSampleRate */ - avio_wb16(pb, AV_RL16(track->par->extradata + 16)); /* OutputGain */ -+ avio_w8(pb, channel_map); /* ChannelMappingFamily */ - /* Write the rest of the header out without byte-swapping. */ -- avio_write(pb, track->par->extradata + 18, track->par->extradata_size - 18); -+ if (channel_map) { -+ if (track->par->extradata_size < 21 + channels) { -+ av_log(s, AV_LOG_ERROR, "invalid extradata size\n"); -+ return AVERROR_INVALIDDATA; -+ } -+ avio_write(pb, track->par->extradata + 19, 2 + channels); /* ChannelMappingTable */ -+ } - - return update_size(pb, pos); - } -@@ -2166,11 +2177,13 @@ static int mov_write_video_tag(AVFormatC - avio_wb16(pb, 0x18); /* Reserved */ - - if (track->mode == MODE_MOV && track->par->format == AV_PIX_FMT_PAL8) { -- int pal_size = 1 << track->par->bits_per_coded_sample; -- int i; -+ int pal_size, i; - avio_wb16(pb, 0); /* Color table ID */ - avio_wb32(pb, 0); /* Color table seed */ - avio_wb16(pb, 0x8000); /* Color table flags */ -+ if (track->par->bits_per_coded_sample < 0 || track->par->bits_per_coded_sample > 8) -+ return AVERROR(EINVAL); -+ pal_size = 1 << track->par->bits_per_coded_sample; - avio_wb16(pb, pal_size - 1); /* Color table size (zero-relative) */ - for (i = 0; i < pal_size; i++) { - uint32_t rgb = track->palette[i]; -Index: jellyfin-ffmpeg/libavformat/mpegts.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/mpegts.c -+++ jellyfin-ffmpeg/libavformat/mpegts.c -@@ -2026,6 +2026,7 @@ int ff_parse_mpeg2_descriptor(AVFormatCo - return AVERROR_INVALIDDATA; - if (channel_config_code <= 0x8) { - st->codecpar->extradata[9] = channels = channel_config_code ? channel_config_code : 2; -+ AV_WL32(&st->codecpar->extradata[12], 48000); - st->codecpar->extradata[18] = channel_config_code ? (channels > 2) : /* Dual Mono */ 255; - st->codecpar->extradata[19] = opus_stream_cnt[channel_config_code]; - st->codecpar->extradata[20] = opus_coupled_stream_cnt[channel_config_code]; -Index: jellyfin-ffmpeg/libavformat/mvdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/mvdec.c -+++ jellyfin-ffmpeg/libavformat/mvdec.c -@@ -157,6 +157,8 @@ static int parse_audio_var(AVFormatConte - return set_channels(avctx, st, var_read_int(pb, size)); - } else if (!strcmp(name, "SAMPLE_RATE")) { - st->codecpar->sample_rate = var_read_int(pb, size); -+ if (st->codecpar->sample_rate <= 0) -+ return AVERROR_INVALIDDATA; - avpriv_set_pts_info(st, 33, 1, st->codecpar->sample_rate); - } else if (!strcmp(name, "SAMPLE_WIDTH")) { - uint64_t bpc = var_read_int(pb, size) * (uint64_t)8; -Index: jellyfin-ffmpeg/libavformat/mvi.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/mvi.c -+++ jellyfin-ffmpeg/libavformat/mvi.c -@@ -32,7 +32,6 @@ - - typedef struct MviDemuxContext { - unsigned int (*get_int)(AVIOContext *); -- uint32_t audio_data_size; - uint64_t audio_size_counter; - uint64_t audio_frame_size; - int audio_size_left; -@@ -46,6 +45,7 @@ static int read_header(AVFormatContext * - AVStream *ast, *vst; - unsigned int version, frames_count, msecs_per_frame, player_version; - int ret; -+ int audio_data_size; - - ast = avformat_new_stream(s, NULL); - if (!ast) -@@ -67,13 +67,13 @@ static int read_header(AVFormatContext * - vst->codecpar->height = avio_rl16(pb); - avio_r8(pb); - ast->codecpar->sample_rate = avio_rl16(pb); -- mvi->audio_data_size = avio_rl32(pb); -+ audio_data_size = avio_rl32(pb); - avio_r8(pb); - player_version = avio_rl32(pb); - avio_rl16(pb); - avio_r8(pb); - -- if (frames_count == 0 || mvi->audio_data_size == 0) -+ if (frames_count == 0 || audio_data_size <= 0) - return AVERROR_INVALIDDATA; - - if (version != 7 || player_version > 213) { -@@ -96,16 +96,16 @@ static int read_header(AVFormatContext * - - mvi->get_int = (vst->codecpar->width * (int64_t)vst->codecpar->height < (1 << 16)) ? avio_rl16 : avio_rl24; - -- mvi->audio_frame_size = ((uint64_t)mvi->audio_data_size << MVI_FRAC_BITS) / frames_count; -+ mvi->audio_frame_size = ((uint64_t)audio_data_size << MVI_FRAC_BITS) / frames_count; - if (mvi->audio_frame_size <= 1 << MVI_FRAC_BITS - 1) { - av_log(s, AV_LOG_ERROR, -- "Invalid audio_data_size (%"PRIu32") or frames_count (%u)\n", -- mvi->audio_data_size, frames_count); -+ "Invalid audio_data_size (%d) or frames_count (%u)\n", -+ audio_data_size, frames_count); - return AVERROR_INVALIDDATA; - } - - mvi->audio_size_counter = (ast->codecpar->sample_rate * 830 / mvi->audio_frame_size - 1) * mvi->audio_frame_size; -- mvi->audio_size_left = mvi->audio_data_size; -+ mvi->audio_size_left = audio_data_size; - - return 0; - } -Index: jellyfin-ffmpeg/libavformat/mxfdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/mxfdec.c -+++ jellyfin-ffmpeg/libavformat/mxfdec.c -@@ -2903,7 +2903,7 @@ static int mxf_read_local_tags(MXFContex - meta = NULL; - ctx = mxf; - } -- while (avio_tell(pb) + 4 < klv_end && !avio_feof(pb)) { -+ while (avio_tell(pb) + 4ULL < klv_end && !avio_feof(pb)) { - int ret; - int tag = avio_rb16(pb); - int size = avio_rb16(pb); /* KLV specified by 0x53 */ -Index: jellyfin-ffmpeg/libavformat/rpl.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/rpl.c -+++ jellyfin-ffmpeg/libavformat/rpl.c -@@ -103,7 +103,7 @@ static AVRational read_fps(const char* l - // Truncate any numerator too large to fit into an int64_t - if (num > (INT64_MAX - 9) / 10 || den > INT64_MAX / 10) - break; -- num = 10 * num + *line - '0'; -+ num = 10 * num + (*line - '0'); - den *= 10; - } - if (!num) -@@ -207,8 +207,10 @@ static int rpl_read_header(AVFormatConte - ast->codecpar->bits_per_coded_sample = 4; - - ast->codecpar->bit_rate = ast->codecpar->sample_rate * -- ast->codecpar->bits_per_coded_sample * -- ast->codecpar->channels; -+ (int64_t)ast->codecpar->channels; -+ if (ast->codecpar->bit_rate > INT64_MAX / ast->codecpar->bits_per_coded_sample) -+ return AVERROR_INVALIDDATA; -+ ast->codecpar->bit_rate *= ast->codecpar->bits_per_coded_sample; - - ast->codecpar->codec_id = AV_CODEC_ID_NONE; - switch (audio_format) { -@@ -334,7 +336,7 @@ static int rpl_read_packet(AVFormatConte - - avio_skip(pb, 4); /* flags */ - frame_size = avio_rl32(pb); -- if (avio_seek(pb, -8, SEEK_CUR) < 0) -+ if (avio_feof(pb) || avio_seek(pb, -8, SEEK_CUR) < 0 || !frame_size) - return AVERROR(EIO); - - ret = av_get_packet(pb, pkt, frame_size); -Index: jellyfin-ffmpeg/libavformat/utils.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/utils.c -+++ jellyfin-ffmpeg/libavformat/utils.c -@@ -1208,7 +1208,9 @@ static void update_initial_durations(AVF - (pktl->pkt.dts == AV_NOPTS_VALUE || - pktl->pkt.dts == st->first_dts || - pktl->pkt.dts == RELATIVE_TS_BASE) && -- !pktl->pkt.duration) { -+ !pktl->pkt.duration && -+ av_sat_add64(cur_dts, duration) == cur_dts + (uint64_t)duration -+ ) { - pktl->pkt.dts = cur_dts; - if (!st->internal->avctx->has_b_frames) - pktl->pkt.pts = cur_dts; -@@ -3913,7 +3915,9 @@ FF_ENABLE_DEPRECATION_WARNINGS - break; - } - if (pkt->duration) { -- if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE && pkt->pts >= st->start_time) { -+ if (avctx->codec_type == AVMEDIA_TYPE_SUBTITLE && pkt->pts != AV_NOPTS_VALUE && st->start_time != AV_NOPTS_VALUE && pkt->pts >= st->start_time -+ && (uint64_t)pkt->pts - st->start_time < INT64_MAX -+ ) { - st->internal->info->codec_info_duration = FFMIN(pkt->pts - st->start_time, st->internal->info->codec_info_duration + pkt->duration); - } else - st->internal->info->codec_info_duration += pkt->duration; -@@ -4059,7 +4063,7 @@ FF_ENABLE_DEPRECATION_WARNINGS - - if (!st->r_frame_rate.num) { - if ( avctx->time_base.den * (int64_t) st->time_base.num -- <= avctx->time_base.num * avctx->ticks_per_frame * (uint64_t) st->time_base.den) { -+ <= avctx->time_base.num * (uint64_t)avctx->ticks_per_frame * st->time_base.den) { - av_reduce(&st->r_frame_rate.num, &st->r_frame_rate.den, - avctx->time_base.den, (int64_t)avctx->time_base.num * avctx->ticks_per_frame, INT_MAX); - } else { -Index: jellyfin-ffmpeg/libavformat/wtvdec.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavformat/wtvdec.c -+++ jellyfin-ffmpeg/libavformat/wtvdec.c -@@ -817,7 +817,7 @@ static int parse_chunks(AVFormatContext - avio_skip(pb, 12); - ff_get_guid(pb, &formattype); - size = avio_rl32(pb); -- if (size < 0 || size > INT_MAX - 92) -+ if (size < 0 || size > INT_MAX - 92 - consumed) - return AVERROR_INVALIDDATA; - parse_media_type(s, 0, sid, mediatype, subtype, formattype, size); - consumed += 92 + size; -@@ -833,7 +833,7 @@ static int parse_chunks(AVFormatContext - avio_skip(pb, 12); - ff_get_guid(pb, &formattype); - size = avio_rl32(pb); -- if (size < 0 || size > INT_MAX - 76) -+ if (size < 0 || size > INT_MAX - 76 - consumed) - return AVERROR_INVALIDDATA; - parse_media_type(s, s->streams[stream_index], sid, mediatype, subtype, formattype, size); - consumed += 76 + size; -Index: jellyfin-ffmpeg/libavutil/cpu.c -=================================================================== ---- jellyfin-ffmpeg.orig/libavutil/cpu.c -+++ jellyfin-ffmpeg/libavutil/cpu.c -@@ -291,6 +291,12 @@ int av_cpu_count(void) - DWORD_PTR proc_aff, sys_aff; - if (GetProcessAffinityMask(GetCurrentProcess(), &proc_aff, &sys_aff)) - nb_cpus = av_popcount64(proc_aff); -+#elif HAVE_SYSCTL && defined(HW_NCPUONLINE) -+ int mib[2] = { CTL_HW, HW_NCPUONLINE }; -+ size_t len = sizeof(nb_cpus); -+ -+ if (sysctl(mib, 2, &nb_cpus, &len, NULL, 0) == -1) -+ nb_cpus = 0; - #elif HAVE_SYSCTL && defined(HW_NCPU) - int mib[2] = { CTL_HW, HW_NCPU }; - size_t len = sizeof(nb_cpus); -Index: jellyfin-ffmpeg/tests/ref/fate/ts-opus-demux -=================================================================== ---- jellyfin-ffmpeg.orig/tests/ref/fate/ts-opus-demux -+++ jellyfin-ffmpeg/tests/ref/fate/ts-opus-demux -@@ -1,4 +1,4 @@ --#extradata 0: 30, 0x53be0347 -+#extradata 0: 30, 0x69290482 - #tb 0: 1/90000 - #media_type 0: audio - #codec_id 0: opus diff --git a/debian/patches/series b/debian/patches/series deleted file mode 100644 index 40831a187..000000000 --- a/debian/patches/series +++ /dev/null @@ -1,9 +0,0 @@ -0001_fix-segment-muxer.patch -0002-lavfi-add-a-filter-for-uploading-normal-frames-to-VAAPI.patch -0003-fix-for-the-broken-tonemap_vaapi-filter.patch -0004-cuda-format-converter-impl.patch -0005-cuda-tonemap-impl.patch -0006-bt2390-and-fix-for-peak-detection-in-opencl-tonemap.patch -0007-fix-for-fmp4-in-hlsenc.patch -0008-fix-nvdec-exceeded-32-surfaces-error.patch -0009-fix-for-nvenc-from-upstream.patch