20# include <libavutil/opt.h>
21# include <libavutil/pixfmt.h>
22# include <libswscale/swscale.h>
30static constexpr int64_t swscale_cache_max_entries = 32;
32struct SwscaleContext {
33 int src_width = 0, src_height = 0;
34 int dst_width = 0, dst_height = 0;
35 AVPixelFormat src_format = AV_PIX_FMT_NONE, dst_format = AV_PIX_FMT_NONE;
36 bool src_full_range =
false, dst_full_range =
false;
37 int src_colorspace = -1, dst_colorspace = -1;
46static int64_t swscale_cache_timestamp = 0;
49static SwsContext *sws_create_context(
int src_width,
57# if defined(FFMPEG_SWSCALE_THREADING)
60 SwsContext *c = sws_alloc_context();
64 av_opt_set_int(c,
"srcw", src_width, 0);
65 av_opt_set_int(c,
"srch", src_height, 0);
66 av_opt_set_int(c,
"src_format", av_src_format, 0);
67 av_opt_set_int(c,
"dstw", dst_width, 0);
68 av_opt_set_int(c,
"dsth", dst_height, 0);
69 av_opt_set_int(c,
"dst_format", av_dst_format, 0);
70 av_opt_set_int(c,
"sws_flags", sws_flags, 0);
73 if (sws_init_context(c,
nullptr,
nullptr) < 0) {
78 SwsContext *c = sws_getContext(src_width,
80 AVPixelFormat(av_src_format),
83 AVPixelFormat(av_dst_format),
93static void init_swscale_cache_if_needed()
95 if (swscale_cache ==
nullptr) {
97 swscale_cache_timestamp = 0;
101static bool remove_oldest_swscale_context()
105 for (
int64_t index = 0; index < swscale_cache->
size(); index++) {
106 SwscaleContext &ctx = (*swscale_cache)[index];
110 int64_t time = swscale_cache_timestamp - ctx.last_use_timestamp;
111 if (time > oldest_time) {
113 oldest_index = index;
117 if (oldest_index >= 0) {
118 SwscaleContext &ctx = (*swscale_cache)[oldest_index];
119 sws_freeContext(ctx.context);
126static void maintain_swscale_cache_size()
128 while (swscale_cache->
size() > swscale_cache_max_entries) {
129 if (!remove_oldest_swscale_context()) {
137SwsContext *ffmpeg_sws_get_context(
int src_width,
149 std::lock_guard
lock(swscale_cache_lock);
151 init_swscale_cache_if_needed();
153 swscale_cache_timestamp++;
156 SwsContext *ctx =
nullptr;
157 for (SwscaleContext &c : *swscale_cache) {
158 if (!c.is_used && c.src_width == src_width && c.src_height == src_height &&
159 c.src_format == av_src_format && c.src_full_range == src_full_range &&
160 c.src_colorspace == src_color_space && c.dst_width == dst_width &&
161 c.dst_height == dst_height && c.dst_format == av_dst_format &&
162 c.dst_full_range == dst_full_range && c.dst_colorspace == dst_color_space &&
163 c.flags == sws_flags)
168 c.last_use_timestamp = swscale_cache_timestamp;
172 if (ctx ==
nullptr) {
174 ctx = sws_create_context(
175 src_width, src_height, av_src_format, dst_width, dst_height, av_dst_format, sws_flags);
177 int src_range, dst_range, brightness, contrast, saturation;
178 const int *table, *inv_table;
179 if (sws_getColorspaceDetails(ctx,
188 if (src_full_range) {
191 if (dst_full_range) {
194 if (src_color_space >= 0) {
195 inv_table = sws_getCoefficients(src_color_space);
197 if (dst_color_space >= 0) {
198 table = sws_getCoefficients(dst_color_space);
200 sws_setColorspaceDetails(
201 ctx, (
int *)inv_table, src_range, table, dst_range, brightness, contrast, saturation);
205 c.src_width = src_width;
206 c.src_height = src_height;
207 c.dst_width = dst_width;
208 c.dst_height = dst_height;
209 c.src_format = AVPixelFormat(av_src_format);
210 c.dst_format = AVPixelFormat(av_dst_format);
211 c.src_full_range = src_full_range;
212 c.dst_full_range = dst_full_range;
213 c.src_colorspace = src_color_space;
214 c.dst_colorspace = dst_color_space;
218 c.last_use_timestamp = swscale_cache_timestamp;
219 swscale_cache->append(c);
221 maintain_swscale_cache_size();
226void ffmpeg_sws_release_context(SwsContext *ctx)
228 std::lock_guard
lock(swscale_cache_lock);
229 init_swscale_cache_if_needed();
232 for (SwscaleContext &c : *swscale_cache) {
233 if (c.context == ctx) {
234 BLI_assert_msg(c.is_used,
"Releasing ffmpeg swscale context that is not in use");
240 BLI_assert_msg(found,
"Releasing ffmpeg swscale context that is not in cache");
242 maintain_swscale_cache_size();
245void ffmpeg_sws_exit()
247 std::lock_guard
lock(swscale_cache_lock);
248 if (swscale_cache !=
nullptr) {
249 for (SwscaleContext &c : *swscale_cache) {
250 sws_freeContext(c.context);
252 delete swscale_cache;
253 swscale_cache =
nullptr;
257void ffmpeg_sws_scale_frame(SwsContext *ctx, AVFrame *dst,
const AVFrame *src)
259# if defined(FFMPEG_SWSCALE_THREADING)
260 sws_scale_frame(ctx, dst, src);
262 sws_scale(ctx, src->data, src->linesize, 0, src->height, dst->data, dst->linesize);
#define BLI_assert_msg(a, msg)
int BLI_system_thread_count(void)
#define UNUSED_VARS_NDEBUG(...)
void remove_and_reorder(const int64_t index)
int context(const bContext *C, const char *member, bContextDataResult *result)