1 /*
2 * Common Plugin code for OpenH323/OPAL
3 *
4 * This code is based on the following files from the OPAL project which
5 * have been removed from the current build and distributions but are still
6 * available in the CVS "attic"
7 *
8 * src/codecs/h263codec.cxx
9 * include/codecs/h263codec.h
10
11 * The original files, and this version of the original code, are released under the same
12 * MPL 1.0 license. Substantial portions of the original code were contributed
13 * by Salyens and March Networks and their right to be identified as copyright holders
14 * of the original code portions and any parts now included in this new copy is asserted through
15 * their inclusion in the copyright notices below.
16 *
17 * Copyright (C) 2006 Post Increment
18 * Copyright (C) 2005 Salyens
19 * Copyright (C) 2001 March Networks Corporation
20 * Copyright (C) 1999-2000 Equivalence Pty. Ltd.
21 *
22 * The contents of this file are subject to the Mozilla Public License
23 * Version 1.0 (the "License"); you may not use this file except in
24 * compliance with the License. You may obtain a copy of the License at
25 * http://www.mozilla.org/MPL/
26 *
27 * Software distributed under the License is distributed on an "AS IS"
28 * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied. See
29 * the License for the specific language governing rights and limitations
30 * under the License.
31 *
32 * The Original Code is Open H323 Library.
33 *
34 * The Initial Developer of the Original Code is Equivalence Pty. Ltd.
35 *
36 * Contributor(s): Guilhem Tardy (gtardy@salyens.com)
37 * Craig Southeren (craigs@postincrement.com)
38 * Matthias Schneider (ma30002000@yahoo.de)
39 */
40 #include "dyna.h"
41
Open(const char * name)42 bool DynaLink::Open(const char *name)
43 {
44 // At first we try without a path
45 if (InternalOpen("", name))
46 return true;
47
48 // Try the current directory
49 if (InternalOpen(".", name))
50 return true;
51
52 // try directories specified in PTLIBPLUGINDIR
53 char ptlibPath[1024];
54 char * env = ::getenv("PTLIBPLUGINDIR");
55 if (env != NULL)
56 strcpy(ptlibPath, env);
57 else
58 #ifdef P_DEFAULT_PLUGIN_DIR
59 strcpy(ptlibPath, P_DEFAULT_PLUGIN_DIR);
60 #elif _WIN32
61 strcpy(ptlibPath, "C:\\PTLib_Plugins");
62 #else
63 strcpy(ptlibPath, "/usr/local/lib");
64 #endif
65 char * p = ::strtok(ptlibPath, DIR_TOKENISER);
66 while (p != NULL) {
67 if (InternalOpen(p, name))
68 return true;
69 p = ::strtok(NULL, DIR_TOKENISER);
70 }
71
72 return false;
73 }
74
InternalOpen(const char * dir,const char * name)75 bool DynaLink::InternalOpen(const char * dir, const char *name)
76 {
77 char path[1024];
78 memset(path, 0, sizeof(path));
79
80 // Copy the directory to "path" and add a separator if necessary
81 if (strlen(dir) > 0) {
82 strcpy(path, dir);
83 if (path[strlen(path)-1] != DIR_SEPARATOR[0])
84 strcat(path, DIR_SEPARATOR);
85 }
86 strcat(path, name);
87
88 if (strlen(path) == 0) {
89 PTRACE(1, m_codecString, "DynaLink: dir '" << (dir != NULL ? dir : "(NULL)")
90 << "', name '" << (name != NULL ? name : "(NULL)") << "' resulted in empty path");
91 return false;
92 }
93
94 // Load the Libary
95 #ifdef _WIN32
96 # ifdef UNICODE
97 // must be called before using avcodec lib
98 USES_CONVERSION;
99 m_hDLL = LoadLibraryEx(A2T(path), NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
100 # else
101 // must be called before using avcodec lib
102 m_hDLL = LoadLibraryEx(path, NULL, LOAD_WITH_ALTERED_SEARCH_PATH);
103 # endif /* UNICODE */
104 #else
105 // must be called before using avcodec lib
106 m_hDLL = dlopen((const char *)path, RTLD_NOW);
107 #endif /* _WIN32 */
108
109 // Check for errors
110 if (m_hDLL == NULL) {
111 #ifndef _WIN32
112 const char * err = dlerror();
113 if (err != NULL)
114 PTRACE(1, m_codecString, "dlopen error " << err);
115 else
116 PTRACE(1, m_codecString, "dlopen error loading " << path);
117 #else /* _WIN32 */
118 PTRACE(1, m_codecString, "Error loading " << path);
119 #endif /* _WIN32 */
120 return false;
121 }
122
123 #ifdef _WIN32
124 GetModuleFileName(m_hDLL, path, sizeof(path));
125 #endif
126
127 PTRACE(1, m_codecString, "Successfully loaded '" << path << "'");
128 return true;
129 }
130
Close()131 void DynaLink::Close()
132 {
133 if (m_hDLL != NULL) {
134 #ifdef _WIN32
135 FreeLibrary(m_hDLL);
136 #else
137 dlclose(m_hDLL);
138 #endif /* _WIN32 */
139 m_hDLL = NULL;
140 }
141 }
142
GetFunction(const char * name,Function & func)143 bool DynaLink::GetFunction(const char * name, Function & func)
144 {
145 if (m_hDLL == NULL)
146 return false;
147
148 #ifdef _WIN32
149
150 #ifdef UNICODE
151 USES_CONVERSION;
152 FARPROC p = GetProcAddress(m_hDLL, A2T(name));
153 #else
154 FARPROC p = GetProcAddress(m_hDLL, name);
155 #endif /* UNICODE */
156 if (p == NULL) {
157 PTRACE(1, m_codecString, "Error linking function " << name << ", error=" << GetLastError());
158 return false;
159 }
160
161 func = (Function)p;
162
163 #else // _WIN32
164
165 void * p = dlsym(m_hDLL, (const char *)name);
166 if (p == NULL) {
167 PTRACE(1, m_codecString, "Error linking function " << name << ", error=" << dlerror());
168 return false;
169 }
170 func = (Function &)p;
171
172 #endif // _WIN32
173
174 return true;
175 }
176
177
178 #if PLUGINCODEC_TRACING
logCallbackFFMPEG(void * avcl,int severity,const char * fmt,va_list arg)179 static void logCallbackFFMPEG(void * avcl, int severity, const char* fmt , va_list arg)
180 {
181 int level;
182 if (severity <= AV_LOG_FATAL)
183 level = 0;
184 else if (severity <= AV_LOG_ERROR)
185 level = 1;
186 else if (severity <= AV_LOG_WARNING)
187 level = 2;
188 else if (severity <= AV_LOG_INFO)
189 level = 3;
190 else if (severity <= AV_LOG_VERBOSE)
191 level = 4;
192 else
193 level = 5;
194
195 if (PTRACE_CHECK(level)) {
196 char buffer[512];
197 int len = vsnprintf(buffer, sizeof(buffer), fmt, arg);
198 if (len > 0) {
199 // Drop extra trailing line feed
200 --len;
201 if (buffer[len] == '\n')
202 buffer[len] = '\0';
203 // Check for bogus errors, everything works so what does this mean?
204 if (strstr(buffer, "Too many slices") == 0 && strstr(buffer, "Frame num gap") == 0) {
205 PluginCodec_LogFunctionInstance(level, __FILE__, __LINE__, "FFMPEG", buffer);
206 }
207 }
208 }
209 }
210 #endif
211
212
FFMPEGLibrary(AVCodecID codec)213 FFMPEGLibrary::FFMPEGLibrary(AVCodecID codec)
214 {
215 m_codec = codec;
216 if (m_codec==AV_CODEC_ID_H264)
217 snprintf( m_codecString, sizeof(m_codecString), "H264");
218 if (m_codec==AV_CODEC_ID_H263P)
219 snprintf( m_codecString, sizeof(m_codecString), "H263+");
220 if (m_codec==AV_CODEC_ID_MPEG4)
221 snprintf( m_codecString, sizeof(m_codecString), "MPEG4");
222 m_isLoadedOK = false;
223 }
224
~FFMPEGLibrary()225 FFMPEGLibrary::~FFMPEGLibrary()
226 {
227 m_libAvcodec.Close();
228 m_libAvutil.Close();
229 }
230
231 #define CHECK_AVUTIL(name, func) \
232 (seperateLibAvutil ? \
233 m_libAvutil.GetFunction(name, (DynaLink::Function &)func) : \
234 m_libAvcodec.GetFunction(name, (DynaLink::Function &)func) \
235 ) \
236
237
Load()238 bool FFMPEGLibrary::Load()
239 {
240 WaitAndSignal m(processLock);
241 if (IsLoaded())
242 return true;
243
244 bool seperateLibAvutil = false;
245
246 #ifdef LIBAVCODEC_LIB_NAME
247 if (m_libAvcodec.Open(LIBAVCODEC_LIB_NAME))
248 seperateLibAvutil = true;
249 else
250 #endif
251 if (m_libAvcodec.Open("libavcodec"))
252 seperateLibAvutil = false;
253 else if (m_libAvcodec.Open("avcodec-" AV_STRINGIFY(LIBAVCODEC_VERSION_MAJOR)))
254 seperateLibAvutil = true;
255 else {
256 PTRACE(1, m_codecString, "Failed to load FFMPEG libavcodec library");
257 return false;
258 }
259
260 if (seperateLibAvutil &&
261 !(
262 #ifdef LIBAVUTIL_LIB_NAME
263 m_libAvutil.Open(LIBAVUTIL_LIB_NAME) ||
264 #endif
265 m_libAvutil.Open("libavutil") ||
266 m_libAvutil.Open("avutil-" AV_STRINGIFY(LIBAVUTIL_VERSION_MAJOR))
267 ) ) {
268 PTRACE(1, m_codecString, "Failed to load FFMPEG libavutil library");
269 return false;
270 }
271
272 strcpy(m_libAvcodec.m_codecString, m_codecString);
273 strcpy(m_libAvutil.m_codecString, m_codecString);
274
275 if (!m_libAvcodec.GetFunction("avcodec_init", (DynaLink::Function &)Favcodec_init))
276 return false;
277
278 if (!m_libAvcodec.GetFunction("av_init_packet", (DynaLink::Function &)Fav_init_packet))
279 return false;
280
281 if (!m_libAvcodec.GetFunction("avcodec_register_all", (DynaLink::Function &)Favcodec_register_all))
282 return false;
283
284 if (!m_libAvcodec.GetFunction("avcodec_find_encoder", (DynaLink::Function &)Favcodec_find_encoder))
285 return false;
286
287 if (!m_libAvcodec.GetFunction("avcodec_find_decoder", (DynaLink::Function &)Favcodec_find_decoder))
288 return false;
289
290 if (!m_libAvcodec.GetFunction("avcodec_alloc_context", (DynaLink::Function &)Favcodec_alloc_context))
291 return false;
292
293 if (!m_libAvcodec.GetFunction("avcodec_alloc_frame", (DynaLink::Function &)Favcodec_alloc_frame))
294 return false;
295
296 if (!m_libAvcodec.GetFunction("avcodec_open", (DynaLink::Function &)Favcodec_open))
297 return false;
298
299 if (!m_libAvcodec.GetFunction("avcodec_close", (DynaLink::Function &)Favcodec_close))
300 return false;
301
302 if (!m_libAvcodec.GetFunction("avcodec_encode_video", (DynaLink::Function &)Favcodec_encode_video))
303 return false;
304
305 if (!m_libAvcodec.GetFunction("avcodec_decode_video2", (DynaLink::Function &)Favcodec_decode_video))
306 return false;
307
308 if (!m_libAvcodec.GetFunction("avcodec_set_dimensions", (DynaLink::Function &)Favcodec_set_dimensions))
309 return false;
310
311 if (!CHECK_AVUTIL("av_free", Favcodec_free))
312 return false;
313
314 if(!m_libAvcodec.GetFunction("avcodec_version", (DynaLink::Function &)Favcodec_version))
315 return false;
316
317 if (!CHECK_AVUTIL("av_log_set_level", FAv_log_set_level))
318 return false;
319
320 if (!CHECK_AVUTIL("av_log_set_callback", FAv_log_set_callback))
321 return false;
322
323 // must be called before using avcodec lib
324
325 unsigned libVer = Favcodec_version();
326 if (libVer != LIBAVCODEC_VERSION_INT) {
327 PTRACE(2, m_codecString, "Warning: compiled against libavcodec headers from version "
328 << LIBAVCODEC_VERSION_MAJOR << '.' << LIBAVCODEC_VERSION_MINOR << '.' << LIBAVCODEC_VERSION_MICRO
329 << ", loaded "
330 << (libVer >> 16) << ((libVer>>8) & 0xff) << (libVer & 0xff));
331 }
332 else {
333 PTRACE(3, m_codecString, "Loaded libavcodec version "
334 << (libVer >> 16) << ((libVer>>8) & 0xff) << (libVer & 0xff));
335 }
336
337 Favcodec_init();
338 Favcodec_register_all ();
339
340 #if PLUGINCODEC_TRACING
341 AvLogSetLevel(AV_LOG_DEBUG);
342 AvLogSetCallback(&logCallbackFFMPEG);
343 #endif
344
345 m_isLoadedOK = true;
346 PTRACE(4, m_codecString, "Successfully loaded libavcodec library and verified functions");
347
348 return true;
349 }
350
AvcodecFindEncoder(enum AVCodecID id)351 AVCodec *FFMPEGLibrary::AvcodecFindEncoder(enum AVCodecID id)
352 {
353 return Favcodec_find_encoder(id);
354 }
355
AvcodecFindDecoder(enum AVCodecID id)356 AVCodec *FFMPEGLibrary::AvcodecFindDecoder(enum AVCodecID id)
357 {
358 WaitAndSignal m(processLock);
359
360 return Favcodec_find_decoder(id);
361 }
362
AvcodecAllocContext(void)363 AVCodecContext *FFMPEGLibrary::AvcodecAllocContext(void)
364 {
365 WaitAndSignal m(processLock);
366
367 return Favcodec_alloc_context();
368 }
369
AvcodecAllocFrame(void)370 AVFrame *FFMPEGLibrary::AvcodecAllocFrame(void)
371 {
372 WaitAndSignal m(processLock);
373
374 return Favcodec_alloc_frame();
375 }
376
AvcodecOpen(AVCodecContext * ctx,AVCodec * codec,AVDictionary ** options)377 int FFMPEGLibrary::AvcodecOpen(AVCodecContext *ctx, AVCodec *codec, AVDictionary **options)
378 {
379 WaitAndSignal m(processLock);
380
381 return Favcodec_open(ctx, codec);
382 }
383
AvcodecClose(AVCodecContext * ctx)384 int FFMPEGLibrary::AvcodecClose(AVCodecContext *ctx)
385 {
386 WaitAndSignal m(processLock);
387
388 return Favcodec_close(ctx);
389 }
390
AvcodecEncodeVideo(AVCodecContext * ctx,BYTE * buf,int buf_size,const AVFrame * pict)391 int FFMPEGLibrary::AvcodecEncodeVideo(AVCodecContext *ctx, BYTE *buf, int buf_size, const AVFrame *pict)
392 {
393 int res;
394
395 res = Favcodec_encode_video(ctx, buf, buf_size, pict);
396
397 PTRACE(6, m_codecString, "DYNA\tEncoded into " << res << " bytes, max " << buf_size);
398 return res;
399 }
400
AvcodecDecodeVideo(AVCodecContext * ctx,AVFrame * pict,int * got_picture_ptr,BYTE * buf,int buf_size)401 int FFMPEGLibrary::AvcodecDecodeVideo(AVCodecContext *ctx, AVFrame *pict, int *got_picture_ptr, BYTE *buf, int buf_size)
402 {
403 AVPacket avpkt;
404 Fav_init_packet(&avpkt);
405 avpkt.data = buf;
406 avpkt.size = buf_size;
407
408 return Favcodec_decode_video(ctx, pict, got_picture_ptr, &avpkt);
409 }
410
AvcodecFree(void * ptr)411 void FFMPEGLibrary::AvcodecFree(void * ptr)
412 {
413 WaitAndSignal m(processLock);
414
415 Favcodec_free(ptr);
416 }
417
AvSetDimensions(AVCodecContext * s,int width,int height)418 void FFMPEGLibrary::AvSetDimensions(AVCodecContext *s, int width, int height)
419 {
420 WaitAndSignal m(processLock);
421
422 Favcodec_set_dimensions(s, width, height);
423 }
424
AvLogSetLevel(int level)425 void FFMPEGLibrary::AvLogSetLevel(int level)
426 {
427 FAv_log_set_level(level);
428 }
429
AvLogSetCallback(void (* callback)(void *,int,const char *,va_list))430 void FFMPEGLibrary::AvLogSetCallback(void (*callback)(void*, int, const char*, va_list))
431 {
432 FAv_log_set_callback(callback);
433 }
434
IsLoaded()435 bool FFMPEGLibrary::IsLoaded()
436 {
437 return m_isLoadedOK;
438 }
439