llmediaimplgstreamer_syms.cpp 6.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265
  1. /**
  2. * @file llmediaimplgstreamer_syms.cpp
  3. * @brief dynamic GStreamer symbol-grabbing code
  4. *
  5. * $LicenseInfo:firstyear=2007&license=viewergpl$
  6. *
  7. * Copyright (c) 2007-2009, Linden Research, Inc.
  8. *
  9. * Second Life Viewer Source Code
  10. * The source code in this file ("Source Code") is provided by Linden Lab
  11. * to you under the terms of the GNU General Public License, version 2.0
  12. * ("GPL"), unless you have obtained a separate licensing agreement
  13. * ("Other License"), formally executed by you and Linden Lab. Terms of
  14. * the GPL can be found in doc/GPL-license.txt in this distribution, or
  15. * online at http://secondlifegrid.net/programs/open_source/licensing/gplv2
  16. *
  17. * There are special exceptions to the terms and conditions of the GPL as
  18. * it is applied to this Source Code. View the full text of the exception
  19. * in the file doc/FLOSS-exception.txt in this software distribution, or
  20. * online at
  21. * http://secondlifegrid.net/programs/open_source/licensing/flossexception
  22. *
  23. * By copying, modifying or distributing this software, you acknowledge
  24. * that you have read and understood your obligations described above,
  25. * and agree to abide by those obligations.
  26. *
  27. * ALL LINDEN LAB SOURCE CODE IS PROVIDED "AS IS." LINDEN LAB MAKES NO
  28. * WARRANTIES, EXPRESS, IMPLIED OR OTHERWISE, REGARDING ITS ACCURACY,
  29. * COMPLETENESS OR PERFORMANCE.
  30. * $/LicenseInfo$
  31. */
  32. #if LL_WINDOWS
  33. # undef _WIN32_WINNT
  34. # define _WIN32_WINNT 0x0502
  35. #endif
  36. #include "linden_common.h"
  37. #include <iostream>
  38. #include <stdlib.h>
  39. #if LL_DARWIN
  40. // For stat()
  41. #include <sys/types.h>
  42. #include <sys/stat.h>
  43. #include <unistd.h>
  44. #endif
  45. #if LL_CLANG
  46. // When using C++11, clang warns about the "register" type usage in gst/gst.h
  47. // (actually stemming from glib-2.0/gobject/gtype.h), while this is a C
  48. // header (and gcc is fine with it)... And with C++17, clang just errors out...
  49. // So, let's nullify the "register" keyword before including the headers. HB
  50. # define register
  51. #endif
  52. #include "gst/gst.h"
  53. #include "gst/app/gstappsink.h"
  54. #include "apr_pools.h"
  55. #include "apr_dso.h"
  56. #ifdef LL_WINDOWS
  57. std::string getGStreamerDir()
  58. {
  59. std::string ret;
  60. HKEY hKey;
  61. #ifdef _WIN64
  62. if (::RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\Wow6432Node\\GStreamer1.0\\x86_64", 0,
  63. KEY_QUERY_VALUE , &hKey) == ERROR_SUCCESS)
  64. #else
  65. if (::RegOpenKeyExA(HKEY_LOCAL_MACHINE, "Software\\GStreamer1.0\\x86", 0,
  66. KEY_QUERY_VALUE , &hKey) == ERROR_SUCCESS)
  67. #endif
  68. {
  69. DWORD dwLen(0);
  70. ::RegQueryValueExA(hKey, "InstallDir", NULL, NULL, NULL, &dwLen);
  71. if (dwLen > 0)
  72. {
  73. std::vector<char> vctBuffer;
  74. vctBuffer.resize(dwLen);
  75. ::RegQueryValueExA(hKey, "InstallDir", NULL, NULL,
  76. reinterpret_cast<LPBYTE>(&vctBuffer[0]),
  77. &dwLen);
  78. ret = &vctBuffer[0];
  79. if (ret[dwLen - 1] != '\\')
  80. {
  81. ret += "\\";
  82. }
  83. #ifdef _WIN64
  84. ret += "1.0\\x86_64\\bin\\";
  85. #else
  86. ret += "1.0\\x86\\bin\\";
  87. #endif
  88. SetDllDirectoryA(ret.c_str());
  89. }
  90. ::RegCloseKey(hKey);
  91. }
  92. if (ret.empty())
  93. {
  94. #ifdef _WIN64
  95. char* path = getenv("GSTREAMER_SDK_ROOT_X86_64");
  96. #else
  97. char* path = getenv("GSTREAMER_SDK_ROOT_X86");
  98. #endif
  99. if (path)
  100. {
  101. ret.assign(path);
  102. if (ret.back() != '\\')
  103. {
  104. ret += '\\';
  105. }
  106. ret += "bin\\";
  107. SetDllDirectoryA(ret.c_str());
  108. }
  109. }
  110. return ret;
  111. }
  112. #elif LL_DARWIN
  113. #define GST_PATH "/Library/Frameworks/GStreamer.framework/Versions/1.0/lib/"
  114. std::string getGStreamerDir()
  115. {
  116. struct stat info;
  117. std::string path = GST_PATH;
  118. if (stat(path.c_str(), &info) == 0)
  119. {
  120. return path;
  121. }
  122. path = "~" + path;
  123. if (stat(path.c_str(), &info) == 0)
  124. {
  125. return path;
  126. }
  127. std::cerr << "Cannot find the GStreamer framework" << std::endl;
  128. return "";
  129. }
  130. #else // Linux or other ELFy unixoid
  131. std::string getGStreamerDir()
  132. {
  133. return "";
  134. }
  135. #endif
  136. #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) RTN (*ll##GSTSYM)(__VA_ARGS__) = NULL;
  137. #include "llmediaimplgstreamer_syms_raw.inc"
  138. #undef LL_GST_SYM
  139. struct Symloader
  140. {
  141. bool mRequired;
  142. char const* mName;
  143. apr_dso_handle_sym_t* mPPFunc;
  144. };
  145. #define LL_GST_SYM(REQ, GSTSYM, RTN, ...) { REQ, #GSTSYM , (apr_dso_handle_sym_t*)&ll##GSTSYM},
  146. Symloader sSyms[] = {
  147. #include "llmediaimplgstreamer_syms_raw.inc"
  148. { false, 0, 0 } };
  149. #undef LL_GST_SYM
  150. // a couple of stubs for disgusting reasons
  151. GstDebugCategory* ll_gst_debug_category_new(gchar* name, guint color,
  152. gchar* description)
  153. {
  154. static GstDebugCategory dummy;
  155. return &dummy;
  156. }
  157. void ll_gst_debug_register_funcptr(GstDebugFuncPtr func, gchar* ptrname)
  158. {
  159. }
  160. static bool sSymsGrabbed = false;
  161. static apr_pool_t* sSymGSTDSOMemoryPool = NULL;
  162. std::vector<apr_dso_handle_t*> sLoadedLibraries;
  163. bool grab_gst_syms(const std::vector<std::string>& dso_names)
  164. {
  165. if (sSymsGrabbed)
  166. {
  167. return true;
  168. }
  169. // attempt to load the shared libraries
  170. apr_pool_create(&sSymGSTDSOMemoryPool, NULL);
  171. std::string dso_name;
  172. for (std::vector<std::string>::const_iterator itr = dso_names.begin(),
  173. end = dso_names.end();
  174. itr != end; ++itr)
  175. {
  176. apr_dso_handle_t* dsop = NULL;
  177. dso_name = getGStreamerDir() + *itr;
  178. if (APR_SUCCESS == apr_dso_load(&dsop, dso_name.c_str(),
  179. sSymGSTDSOMemoryPool))
  180. {
  181. sLoadedLibraries.push_back(dsop);
  182. }
  183. for (int i = 0; sSyms[i].mName; ++i)
  184. {
  185. if (!*sSyms[i].mPPFunc)
  186. {
  187. apr_dso_sym(sSyms[i].mPPFunc, dsop, sSyms[i].mName);
  188. }
  189. }
  190. }
  191. std::stringstream strm;
  192. bool sym_error = false;
  193. for (int i = 0; sSyms[i].mName; ++i)
  194. {
  195. if (sSyms[i].mRequired && !*sSyms[i].mPPFunc)
  196. {
  197. sym_error = true;
  198. strm << sSyms[i].mName << " " << std::endl;
  199. }
  200. }
  201. if (sym_error)
  202. {
  203. std::cerr << "Failed to load the following symbols: " << strm.str()
  204. << std::endl;
  205. }
  206. sSymsGrabbed = !sym_error;
  207. return sSymsGrabbed;
  208. }
  209. // Should be safe to call regardless of whether we have actually grabbed syms.
  210. void ungrab_gst_syms()
  211. {
  212. for (std::vector<apr_dso_handle_t*>::iterator
  213. itr = sLoadedLibraries.begin(), end = sLoadedLibraries.end();
  214. itr != end; ++itr)
  215. {
  216. apr_dso_unload(*itr);
  217. }
  218. sLoadedLibraries.clear();
  219. if (sSymGSTDSOMemoryPool)
  220. {
  221. apr_pool_destroy(sSymGSTDSOMemoryPool);
  222. sSymGSTDSOMemoryPool = NULL;
  223. }
  224. for (int i = 0; sSyms[i].mName; ++i)
  225. {
  226. *sSyms[i].mPPFunc = NULL;
  227. }
  228. sSymsGrabbed = false;
  229. }