21# include <libavutil/opt.h>
22# include <libavutil/pixfmt.h>
23# include <libswscale/swscale.h>
31static constexpr int64_t swscale_cache_max_entries = 32;
33struct SwscaleContext {
34 int src_width = 0, src_height = 0;
35 int dst_width = 0, dst_height = 0;
36 AVPixelFormat src_format = AV_PIX_FMT_NONE, dst_format = AV_PIX_FMT_NONE;
37 bool src_full_range =
false, dst_full_range =
false;
38 int src_colorspace = -1, dst_colorspace = -1;
47static int64_t swscale_cache_timestamp = 0;
50static SwsContext *sws_create_context(
int src_width,
58# if defined(FFMPEG_SWSCALE_THREADING)
61 SwsContext *c = sws_alloc_context();
65 av_opt_set_int(c,
"srcw", src_width, 0);
66 av_opt_set_int(c,
"srch", src_height, 0);
67 av_opt_set_int(c,
"src_format", av_src_format, 0);
68 av_opt_set_int(c,
"dstw", dst_width, 0);
69 av_opt_set_int(c,
"dsth", dst_height, 0);
70 av_opt_set_int(c,
"dst_format", av_dst_format, 0);
71 av_opt_set_int(c,
"sws_flags", sws_flags, 0);
72 av_opt_set_int(c,
"threads", MOV_thread_count(), 0);
74 if (sws_init_context(c,
nullptr,
nullptr) < 0) {
79 SwsContext *c = sws_getContext(src_width,
81 AVPixelFormat(av_src_format),
84 AVPixelFormat(av_dst_format),
94static void init_swscale_cache_if_needed()
96 if (swscale_cache ==
nullptr) {
98 swscale_cache_timestamp = 0;
102static bool remove_oldest_swscale_context()
106 for (
int64_t index = 0; index < swscale_cache->
size(); index++) {
107 SwscaleContext &ctx = (*swscale_cache)[index];
111 int64_t time = swscale_cache_timestamp - ctx.last_use_timestamp;
112 if (time > oldest_time) {
114 oldest_index = index;
118 if (oldest_index >= 0) {
119 SwscaleContext &ctx = (*swscale_cache)[oldest_index];
120 sws_freeContext(ctx.context);
127static void maintain_swscale_cache_size()
129 while (swscale_cache->
size() > swscale_cache_max_entries) {
130 if (!remove_oldest_swscale_context()) {
138SwsContext *ffmpeg_sws_get_context(
int src_width,
150 std::lock_guard
lock(swscale_cache_lock);
152 init_swscale_cache_if_needed();
154 swscale_cache_timestamp++;
157 SwsContext *ctx =
nullptr;
158 for (SwscaleContext &c : *swscale_cache) {
159 if (!c.is_used && c.src_width == src_width && c.src_height == src_height &&
160 c.src_format == av_src_format && c.src_full_range == src_full_range &&
161 c.src_colorspace == src_color_space && c.dst_width == dst_width &&
162 c.dst_height == dst_height && c.dst_format == av_dst_format &&
163 c.dst_full_range == dst_full_range && c.dst_colorspace == dst_color_space &&
164 c.flags == sws_flags)
169 c.last_use_timestamp = swscale_cache_timestamp;
173 if (ctx ==
nullptr) {
175 ctx = sws_create_context(
176 src_width, src_height, av_src_format, dst_width, dst_height, av_dst_format, sws_flags);
178 int src_range, dst_range, brightness, contrast, saturation;
179 const int *table, *inv_table;
180 if (sws_getColorspaceDetails(ctx,
189 if (src_full_range) {
192 if (dst_full_range) {
195 if (src_color_space >= 0) {
196 inv_table = sws_getCoefficients(src_color_space);
198 if (dst_color_space >= 0) {
199 table = sws_getCoefficients(dst_color_space);
201 sws_setColorspaceDetails(
202 ctx, (
int *)inv_table, src_range, table, dst_range, brightness, contrast, saturation);
206 c.src_width = src_width;
207 c.src_height = src_height;
208 c.dst_width = dst_width;
209 c.dst_height = dst_height;
210 c.src_format = AVPixelFormat(av_src_format);
211 c.dst_format = AVPixelFormat(av_dst_format);
212 c.src_full_range = src_full_range;
213 c.dst_full_range = dst_full_range;
214 c.src_colorspace = src_color_space;
215 c.dst_colorspace = dst_color_space;
219 c.last_use_timestamp = swscale_cache_timestamp;
220 swscale_cache->append(c);
222 maintain_swscale_cache_size();
227void ffmpeg_sws_release_context(SwsContext *ctx)
229 std::lock_guard
lock(swscale_cache_lock);
230 init_swscale_cache_if_needed();
233 for (SwscaleContext &c : *swscale_cache) {
234 if (c.context == ctx) {
235 BLI_assert_msg(c.is_used,
"Releasing ffmpeg swscale context that is not in use");
241 BLI_assert_msg(found,
"Releasing ffmpeg swscale context that is not in cache");
243 maintain_swscale_cache_size();
246void ffmpeg_sws_exit()
248 std::lock_guard
lock(swscale_cache_lock);
249 if (swscale_cache !=
nullptr) {
250 for (SwscaleContext &c : *swscale_cache) {
251 sws_freeContext(c.context);
253 delete swscale_cache;
254 swscale_cache =
nullptr;
258void ffmpeg_sws_scale_frame(SwsContext *ctx, AVFrame *dst,
const AVFrame *src)
260# if defined(FFMPEG_SWSCALE_THREADING)
261 sws_scale_frame(ctx, dst, src);
263 sws_scale(ctx, src->data, src->linesize, 0, src->height, dst->data, dst->linesize);
#define BLI_assert_msg(a, msg)
#define UNUSED_VARS_NDEBUG(...)
void remove_and_reorder(const int64_t index)
int context(const bContext *C, const char *member, bContextDataResult *result)