FreeRDP
Loading...
Searching...
No Matches
image_ffmpeg.c
1
20#include <freerdp/config.h>
21
22#if defined(WITH_SWSCALE) && defined(WITH_SWSCALE_LOADING)
23
24#include <winpr/library.h>
25#include <winpr/assert.h>
26#include <freerdp/log.h>
27
28#include "image_ffmpeg.h"
29
30#if !defined(__has_include)
31#define __has_include(x) 0
32#endif
33
34#if __has_include(<libswscale/version.h>)
35#include <libswscale/version.h>
36#endif
37
38#if __has_include(<libavutil/version.h>)
39#include <libavutil/version.h>
40#endif
41
42#define TAG FREERDP_TAG("codec.image")
43
44typedef struct SwsContext* (*pSws_getContext)(int srcW, int srcH, int srcFormat, int dstW, int dstH,
45 int dstFormat, int flags, void* srcFilter,
46 void* dstFilter, const double* param);
47typedef int (*pSws_scale)(struct SwsContext* c, const uint8_t* const srcSlice[],
48 const int srcStride[], int srcSliceY, int srcSliceH, uint8_t* const dst[],
49 const int dstStride[]);
50typedef void (*pSws_freeContext)(struct SwsContext* c);
51typedef int (*pAv_image_fill_linesizes)(int linesizes[4], int pix_fmt, int width);
52typedef int (*pAv_image_fill_pointers)(uint8_t* data[4], int pix_fmt, int height, uint8_t* ptr,
53 const int linesizes[4]);
54
55typedef struct
56{
57 HMODULE lib;
58 pSws_getContext getContext;
59 pSws_scale scale;
60 pSws_freeContext freeContext;
61 BOOL initialized;
62 BOOL available;
63} SWSCALE_LIBRARY;
64
65typedef struct
66{
67 HMODULE lib;
68 pAv_image_fill_linesizes fill_linesizes;
69 pAv_image_fill_pointers fill_pointers;
70 BOOL initialized;
71 BOOL available;
72} AVUTIL_LIBRARY;
73
74static SWSCALE_LIBRARY g_swscale = WINPR_C_ARRAY_INIT;
75static AVUTIL_LIBRARY g_avutil = WINPR_C_ARRAY_INIT;
76
77#define STRINGIFY(x) #x
78#define TOSTRING(x) STRINGIFY(x)
79
80#if defined(LIBSWSCALE_VERSION_MAJOR)
81#define SWSCALE_VERSION_STR TOSTRING(LIBSWSCALE_VERSION_MAJOR)
82#endif
83
84static const char* swscale_library_names[] = {
85#if defined(_WIN32)
86#if defined(SWSCALE_VERSION_STR)
87 "swscale-" SWSCALE_VERSION_STR ".dll",
88#endif
89 "swscale-9.dll",
90 "swscale-8.dll",
91 "swscale-7.dll",
92 "swscale-6.dll",
93 "swscale.dll"
94#elif defined(__APPLE__)
95#if defined(SWSCALE_VERSION_STR)
96 "libswscale." SWSCALE_VERSION_STR ".dylib",
97#endif
98 "libswscale.dylib",
99 "libswscale.9.dylib",
100 "libswscale.8.dylib",
101 "libswscale.7.dylib",
102 "libswscale.6.dylib"
103#else
104#if defined(SWSCALE_VERSION_STR)
105 "libswscale.so." SWSCALE_VERSION_STR,
106#endif
107 "libswscale.so.9",
108 "libswscale.so.8",
109 "libswscale.so.7",
110 "libswscale.so.6",
111 "libswscale.so"
112#endif
113};
114
115static BOOL swscale_load_library(const char* name)
116{
117 WINPR_ASSERT(name);
118
119 WLog_DBG(TAG, "Attempting to load swscale library: %s", name);
120
121 g_swscale.lib = LoadLibraryA(name);
122 if (!g_swscale.lib)
123 {
124 WLog_DBG(TAG, "Failed to load %s", name);
125 return FALSE;
126 }
127
128 g_swscale.getContext = (pSws_getContext)(void*)GetProcAddress(g_swscale.lib, "sws_getContext");
129 g_swscale.scale = (pSws_scale)(void*)GetProcAddress(g_swscale.lib, "sws_scale");
130 g_swscale.freeContext =
131 (pSws_freeContext)(void*)GetProcAddress(g_swscale.lib, "sws_freeContext");
132
133 if (!g_swscale.getContext || !g_swscale.scale || !g_swscale.freeContext)
134 {
135 WLog_WARN(TAG, "Failed to load required functions from %s", name);
136 FreeLibrary(g_swscale.lib);
137 g_swscale.lib = nullptr;
138 return FALSE;
139 }
140
141 WLog_INFO(TAG, "Successfully loaded swscale library: %s", name);
142 return TRUE;
143}
144
145BOOL freerdp_swscale_init(void)
146{
147 if (g_swscale.initialized)
148 return g_swscale.available;
149
150 g_swscale.initialized = TRUE;
151 g_swscale.available = FALSE;
152
153 WLog_DBG(TAG, "Searching for swscale library in default locations");
154 for (size_t i = 0; i < ARRAYSIZE(swscale_library_names); i++)
155 {
156 if (swscale_load_library(swscale_library_names[i]))
157 {
158 g_swscale.available = TRUE;
159 return TRUE;
160 }
161 }
162
163 WLog_INFO(TAG, "swscale library not found");
164
165 return FALSE;
166}
167
168BOOL freerdp_swscale_available(void)
169{
170 return freerdp_swscale_init() && g_swscale.available;
171}
172
173struct SwsContext* freerdp_sws_getContext(int srcW, int srcH, int srcFormat, int dstW, int dstH,
174 int dstFormat, int flags, void* srcFilter,
175 void* dstFilter, const double* param)
176{
177 if (!freerdp_swscale_available())
178 {
179 WLog_WARN(TAG, "sws_getContext called but swscale not available");
180 return nullptr;
181 }
182
183 WINPR_ASSERT(g_swscale.getContext);
184 return g_swscale.getContext(srcW, srcH, srcFormat, dstW, dstH, dstFormat, flags, srcFilter,
185 dstFilter, param);
186}
187
188int freerdp_sws_scale(struct SwsContext* ctx, const uint8_t* const srcSlice[],
189 const int srcStride[], int srcSliceY, int srcSliceH, uint8_t* const dst[],
190 const int dstStride[])
191{
192 if (!freerdp_swscale_available())
193 {
194 WLog_WARN(TAG, "sws_scale called but swscale not available");
195 return -1;
196 }
197
198 if (!ctx)
199 {
200 WLog_WARN(TAG, "sws_scale called with nullptr context");
201 return -1;
202 }
203
204 WINPR_ASSERT(g_swscale.scale);
205 return g_swscale.scale(ctx, srcSlice, srcStride, srcSliceY, srcSliceH, dst, dstStride);
206}
207
208void freerdp_sws_freeContext(struct SwsContext* ctx)
209{
210 if (!freerdp_swscale_available())
211 return;
212
213 if (!ctx)
214 return;
215
216 WINPR_ASSERT(g_swscale.freeContext);
217 g_swscale.freeContext(ctx);
218}
219
220/* =============================================================================
221 * libavutil Runtime Loading
222 * ============================================================================= */
223
224#if defined(LIBAVUTIL_VERSION_MAJOR)
225#define AVUTIL_VERSION_STR TOSTRING(LIBAVUTIL_VERSION_MAJOR)
226#endif
227
228static const char* avutil_library_names[] = {
229#if defined(_WIN32)
230#if defined(AVUTIL_VERSION_STR)
231 "avutil-" AVUTIL_VERSION_STR ".dll",
232#endif
233 "avutil-59.dll",
234 "avutil-58.dll",
235 "avutil-57.dll",
236 "avutil-56.dll",
237 "avutil.dll"
238#elif defined(__APPLE__)
239#if defined(AVUTIL_VERSION_STR)
240 "libavutil." AVUTIL_VERSION_STR ".dylib",
241#endif
242 "libavutil.dylib",
243 "libavutil.59.dylib",
244 "libavutil.58.dylib",
245 "libavutil.57.dylib",
246 "libavutil.56.dylib"
247#else
248#if defined(AVUTIL_VERSION_STR)
249 "libavutil.so." AVUTIL_VERSION_STR,
250#endif
251 "libavutil.so.59",
252 "libavutil.so.58",
253 "libavutil.so.57",
254 "libavutil.so.56",
255 "libavutil.so"
256#endif
257};
258
259static BOOL avutil_load_library(const char* name)
260{
261 WINPR_ASSERT(name);
262
263 WLog_DBG(TAG, "Attempting to load avutil library: %s", name);
264
265 g_avutil.lib = LoadLibraryA(name);
266 if (!g_avutil.lib)
267 {
268 WLog_DBG(TAG, "Failed to load %s", name);
269 return FALSE;
270 }
271
272 g_avutil.fill_linesizes =
273 (pAv_image_fill_linesizes)(void*)GetProcAddress(g_avutil.lib, "av_image_fill_linesizes");
274 g_avutil.fill_pointers =
275 (pAv_image_fill_pointers)(void*)GetProcAddress(g_avutil.lib, "av_image_fill_pointers");
276
277 if (!g_avutil.fill_linesizes || !g_avutil.fill_pointers)
278 {
279 WLog_WARN(TAG, "Failed to load required functions from %s", name);
280 FreeLibrary(g_avutil.lib);
281 g_avutil.lib = nullptr;
282 return FALSE;
283 }
284
285 WLog_INFO(TAG, "Successfully loaded avutil library: %s", name);
286 return TRUE;
287}
288
289BOOL freerdp_avutil_init(void)
290{
291 if (g_avutil.initialized)
292 return g_avutil.available;
293
294 g_avutil.initialized = TRUE;
295 g_avutil.available = FALSE;
296
297 WLog_DBG(TAG, "Searching for avutil library in default locations");
298 for (size_t i = 0; i < ARRAYSIZE(avutil_library_names); i++)
299 {
300 if (avutil_load_library(avutil_library_names[i]))
301 {
302 g_avutil.available = TRUE;
303 return TRUE;
304 }
305 }
306
307 WLog_INFO(TAG, "avutil library not found");
308
309 return FALSE;
310}
311
312BOOL freerdp_avutil_available(void)
313{
314 return freerdp_avutil_init() && g_avutil.available;
315}
316
317int freerdp_av_image_fill_linesizes(int linesizes[4], int pix_fmt, int width)
318{
319 if (!freerdp_avutil_available())
320 {
321 WLog_WARN(TAG, "av_image_fill_linesizes called but avutil not available");
322 return -1;
323 }
324
325 WINPR_ASSERT(g_avutil.fill_linesizes);
326 return g_avutil.fill_linesizes(linesizes, pix_fmt, width);
327}
328
329int freerdp_av_image_fill_pointers(uint8_t* data[4], int pix_fmt, int height, uint8_t* ptr,
330 const int linesizes[4])
331{
332 if (!freerdp_avutil_available())
333 {
334 WLog_WARN(TAG, "av_image_fill_pointers called but avutil not available");
335 return -1;
336 }
337
338 WINPR_ASSERT(g_avutil.fill_pointers);
339 return g_avutil.fill_pointers(data, pix_fmt, height, ptr, linesizes);
340}
341
342#endif /* WITH_SWSCALE && WITH_SWSCALE_LOADING */