1 /** 2 * Copyright 2012 JogAmp Community. All rights reserved. 3 * 4 * Redistribution and use in source and binary forms, with or without modification, are 5 * permitted provided that the following conditions are met: 6 * 7 * 1. Redistributions of source code must retain the above copyright notice, this list of 8 * conditions and the following disclaimer. 9 * 10 * 2. Redistributions in binary form must reproduce the above copyright notice, this list 11 * of conditions and the following disclaimer in the documentation and/or other materials 12 * provided with the distribution. 13 * 14 * THIS SOFTWARE IS PROVIDED BY JogAmp Community ``AS IS'' AND ANY EXPRESS OR IMPLIED 15 * WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND 16 * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL JogAmp Community OR 17 * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 18 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON 20 * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING 21 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF 22 * ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 23 * 24 * The views and conclusions contained in the software and documentation are those of the 25 * authors and should not be interpreted as representing official policies, either expressed 26 * or implied, of JogAmp Community. 27 */ 28 29 package jogamp.opengl.util.av.impl; 30 31 import java.security.AccessController; 32 import java.security.PrivilegedAction; 33 import java.util.ArrayList; 34 import java.util.Arrays; 35 import java.util.HashSet; 36 import java.util.List; 37 import java.util.Set; 38 39 import com.jogamp.opengl.GLProfile; 40 import com.jogamp.common.ExceptionUtils; 41 import com.jogamp.common.os.DynamicLibraryBundle; 42 import com.jogamp.common.os.DynamicLibraryBundleInfo; 43 import com.jogamp.common.util.RunnableExecutor; 44 import com.jogamp.common.util.VersionNumber; 45 46 /** 47 * See {@link FFMPEGMediaPlayer#compatibility}. 48 */ 49 class FFMPEGDynamicLibraryBundleInfo implements DynamicLibraryBundleInfo { 50 private static final boolean DEBUG = FFMPEGMediaPlayer.DEBUG || DynamicLibraryBundleInfo.DEBUG; 51 52 private static final List<String> glueLibNames = new ArrayList<String>(); // none 53 54 private static final int symbolCount = 65; 55 private static final String[] symbolNames = { 56 "avutil_version", 57 "avformat_version", 58 "avcodec_version", 59 "avresample_version", 60 /* 5 */ "swresample_version", 61 62 // libavcodec 63 "avcodec_register_all", 64 "avcodec_close", 65 "avcodec_string", 66 "avcodec_find_decoder", 67 "avcodec_open2", // 53.6.0 (opt) 68 "avcodec_alloc_frame", 69 "avcodec_get_frame_defaults", 70 "avcodec_free_frame", // 54.28.0 (opt) 71 "avcodec_default_get_buffer", // <= 54 (opt), else sp_avcodec_default_get_buffer2 72 "avcodec_default_release_buffer", // <= 54 (opt), else sp_av_frame_unref 73 "avcodec_default_get_buffer2", // 55 (opt) 74 "avcodec_get_edge_width", 75 "av_image_fill_linesizes", 76 "avcodec_align_dimensions", 77 "avcodec_align_dimensions2", 78 "avcodec_flush_buffers", 79 "av_init_packet", 80 "av_new_packet", 81 "av_destruct_packet", 82 "av_free_packet", 83 "avcodec_decode_audio4", // 53.25.0 (opt) 84 /* 27 */ "avcodec_decode_video2", // 52.23.0 85 86 // libavutil 87 "av_pix_fmt_descriptors", 88 "av_frame_unref", // 55.0.0 (opt) 89 "av_realloc", 90 "av_free", 91 "av_get_bits_per_pixel", 92 "av_samples_get_buffer_size", 93 "av_get_bytes_per_sample", // 51.4.0 94 "av_opt_set_int", // 51.12.0 95 "av_dict_get", 96 "av_dict_count", // 54.* (opt) 97 "av_dict_set", 98 /* 28 */ "av_dict_free", 99 100 // libavformat 101 "avformat_alloc_context", 102 "avformat_free_context", // 52.96.0 (opt) 103 "avformat_close_input", // 53.17.0 (opt) 104 "av_register_all", 105 "av_find_input_format", 106 "avformat_open_input", 107 "av_dump_format", 108 "av_read_frame", 109 "av_seek_frame", 110 "avformat_seek_file", // ??? (opt) 111 "av_read_play", 112 "av_read_pause", 113 "avformat_network_init", // 53.13.0 (opt) 114 "avformat_network_deinit", // 53.13.0 (opt) 115 /* 54 */ "avformat_find_stream_info", // 53.3.0 (opt) 116 117 // libavdevice 118 /* 55 */ "avdevice_register_all", // supported in all version <= 56 119 120 // libavresample 121 "avresample_alloc_context", // 1.0.1 122 "avresample_open", 123 "avresample_close", 124 "avresample_free", 125 /* 60 */ "avresample_convert", 126 127 // libavresample 128 "av_opt_set_sample_fmt", // actually lavu .. but exist only w/ swresample! 129 "swr_alloc", 130 "swr_init", 131 "swr_free", 132 /* 65 */ "swr_convert", 133 134 }; 135 136 // optional symbol names 137 private static final String[] optionalSymbolNames = { 138 "avformat_seek_file", // ??? (opt) 139 "avcodec_free_frame", // 54.28.0 (opt) 140 "av_frame_unref", // 55.0.0 (opt) 141 "av_dict_count", // 54.* (opt) 142 "avcodec_default_get_buffer", // <= 54 (opt), else sp_avcodec_default_get_buffer2 143 "avcodec_default_release_buffer", // <= 54 (opt), else sp_av_frame_unref 144 "avcodec_default_get_buffer2", // 55 (opt) 145 146 // libavdevice 147 "avdevice_register_all", // 53.0.0 (opt) 148 149 // libavresample 150 "avresample_version", // 1.0.1 151 "avresample_alloc_context", // 1.0.1 152 "avresample_open", 153 "avresample_close", 154 "avresample_free", 155 "avresample_convert", 156 157 // libswresample 158 "av_opt_set_sample_fmt", // actually lavu .. but exist only w/ swresample! 159 "swresample_version", // 0 160 "swr_alloc", 161 "swr_init", 162 "swr_free", 163 "swr_convert", 164 }; 165 166 /** util, format, codec, device, avresample, swresample */ 167 private static final boolean[] libLoaded = new boolean[6]; 168 private static final long[] symbolAddr = new long[symbolCount]; 169 private static final boolean ready; 170 private static final boolean libsUFCLoaded; 171 static final VersionNumber avCodecVersion; 172 static final VersionNumber avFormatVersion; 173 static final VersionNumber avUtilVersion; 174 static final VersionNumber avResampleVersion; 175 static final VersionNumber swResampleVersion; 176 private static final FFMPEGNatives natives; 177 178 private static final int LIB_IDX_UTI = 0; 179 private static final int LIB_IDX_FMT = 1; 180 private static final int LIB_IDX_COD = 2; 181 private static final int LIB_IDX_DEV = 3; 182 private static final int LIB_IDX_AVR = 4; 183 private static final int LIB_IDX_SWR = 5; 184 185 private static final PrivilegedAction<DynamicLibraryBundle> privInitSymbolsAction = new PrivilegedAction<DynamicLibraryBundle>() { 186 @Override 187 public DynamicLibraryBundle run() { 188 final DynamicLibraryBundle dl = new DynamicLibraryBundle(new FFMPEGDynamicLibraryBundleInfo()); 189 for(int i=0; i<6; i++) { 190 libLoaded[i] = dl.isToolLibLoaded(i); 191 } 192 if( !libLoaded[LIB_IDX_UTI] || !libLoaded[LIB_IDX_FMT] || !libLoaded[LIB_IDX_COD] ) { 193 System.err.println("FFMPEG Tool library incomplete: [ avutil "+libLoaded[LIB_IDX_UTI]+", avformat "+libLoaded[LIB_IDX_FMT]+", avcodec "+libLoaded[LIB_IDX_COD]+"]"); 194 return null; 195 } 196 dl.claimAllLinkPermission(); 197 try { 198 for(int i = 0; i<symbolCount; i++) { 199 symbolAddr[i] = dl.dynamicLookupFunction(symbolNames[i]); 200 } 201 } finally { 202 dl.releaseAllLinkPermission(); 203 } 204 return dl; 205 } }; 206 207 /** 208 * @param loaded 6: util, format, codec, device, avresample, swresample 209 * @param versions 5: util, format, codec, avresample, swresample 210 * @return 211 */ initSymbols(final VersionNumber[] versions)212 private static final boolean initSymbols(final VersionNumber[] versions) { 213 for(int i=0; i<6; i++) { 214 libLoaded[i] = false; 215 } 216 if(symbolNames.length != symbolCount) { 217 throw new InternalError("XXX0 "+symbolNames.length+" != "+symbolCount); 218 } 219 220 final DynamicLibraryBundle dl = AccessController.doPrivileged(privInitSymbolsAction); 221 if( null == dl ) { 222 return false; 223 } 224 225 // optional symbol name set 226 final Set<String> optionalSymbolNameSet = new HashSet<String>(); 227 optionalSymbolNameSet.addAll(Arrays.asList(optionalSymbolNames)); 228 229 // validate results 230 boolean res = true; 231 for(int i = 0; i<symbolCount; i++) { 232 if( 0 == symbolAddr[i] ) { 233 // no symbol, check optional and alternative symbols 234 final String symbol = symbolNames[i]; 235 if ( !optionalSymbolNameSet.contains(symbol) ) { 236 System.err.println("Fail: Could not resolve symbol <"+symbolNames[i]+">: not optional, no alternatives."); 237 res = false; 238 } else if(DEBUG) { 239 System.err.println("OK: Unresolved optional symbol <"+symbolNames[i]+">"); 240 } 241 } 242 } 243 versions[0] = FFMPEGStaticNatives.getAVVersion(FFMPEGStaticNatives.getAvVersion0(symbolAddr[0])); 244 versions[1] = FFMPEGStaticNatives.getAVVersion(FFMPEGStaticNatives.getAvVersion0(symbolAddr[1])); 245 versions[2] = FFMPEGStaticNatives.getAVVersion(FFMPEGStaticNatives.getAvVersion0(symbolAddr[2])); 246 versions[3] = FFMPEGStaticNatives.getAVVersion(FFMPEGStaticNatives.getAvVersion0(symbolAddr[3])); 247 versions[4] = FFMPEGStaticNatives.getAVVersion(FFMPEGStaticNatives.getAvVersion0(symbolAddr[4])); 248 249 return res; 250 } 251 252 static { 253 // native ffmpeg media player implementation is included in jogl_desktop and jogl_mobile GLProfile.initSingleton()254 GLProfile.initSingleton(); 255 boolean _ready = false; 256 /** util, format, codec, avresample, swresample */ 257 final VersionNumber[] _versions = new VersionNumber[5]; 258 try { 259 _ready = initSymbols(_versions); 260 } catch (final Throwable t) { 261 ExceptionUtils.dumpThrowable("", t); 262 } 263 libsUFCLoaded = libLoaded[LIB_IDX_UTI] && libLoaded[LIB_IDX_FMT] && libLoaded[LIB_IDX_COD]; 264 avUtilVersion = _versions[0]; 265 avFormatVersion = _versions[1]; 266 avCodecVersion = _versions[2]; 267 avResampleVersion = _versions[3]; 268 swResampleVersion = _versions[4]; 269 if(!libsUFCLoaded) { 270 System.err.println("LIB_AV Not Available: lavu, lavc, lavu"); 271 natives = null; 272 ready = false; 273 } else if(!_ready) { 274 System.err.println("LIB_AV Not Matching"); 275 natives = null; 276 ready = false; 277 } else { 278 final int avCodecMajor = avCodecVersion.getMajor(); 279 final int avFormatMajor = avFormatVersion.getMajor(); 280 final int avUtilMajor = avUtilVersion.getMajor(); 281 if( avCodecMajor == 53 && avFormatMajor == 53 && avUtilMajor == 51 ) { 282 // lavc53.lavf53.lavu51 283 natives = new FFMPEGv08Natives(); 284 } else if( avCodecMajor == 54 && avFormatMajor == 54 && avUtilMajor == 52 ) { 285 // lavc54.lavf54.lavu52.lavr01 286 natives = new FFMPEGv09Natives(); 287 } else if( avCodecMajor == 55 && avFormatMajor == 55 && ( avUtilMajor == 52 || avUtilMajor == 53 ) ) { 288 // lavc55.lavf55.lavu52.lavr01 (ffmpeg) or lavc55.lavf55.lavu53.lavr01 (libav) 289 natives = new FFMPEGv10Natives(); 290 } else if( avCodecMajor == 56 && avFormatMajor == 56 && avUtilMajor == 54 ) { 291 // lavc56.lavf56.lavu54.lavr02 292 natives = new FFMPEGv11Natives(); 293 } else { 294 System.err.println("LIB_AV No Version/Native-Impl Match"); 295 natives = null; 296 } 297 if( null != natives && FFMPEGStaticNatives.initIDs0() ) { 298 ready = natives.initSymbols0(symbolAddr, symbolCount); 299 } else { 300 ready = false; 301 } 302 } 303 } 304 libsLoaded()305 static boolean libsLoaded() { return libsUFCLoaded; } avDeviceLoaded()306 static boolean avDeviceLoaded() { return libLoaded[LIB_IDX_DEV]; } avResampleLoaded()307 static boolean avResampleLoaded() { return libLoaded[LIB_IDX_AVR]; } swResampleLoaded()308 static boolean swResampleLoaded() { return libLoaded[LIB_IDX_SWR]; } getNatives()309 static FFMPEGNatives getNatives() { return natives; } initSingleton()310 static boolean initSingleton() { return ready; } 311 FFMPEGDynamicLibraryBundleInfo()312 protected FFMPEGDynamicLibraryBundleInfo() { 313 } 314 315 @Override shallLinkGlobal()316 public final boolean shallLinkGlobal() { return true; } 317 318 /** 319 * {@inheritDoc} 320 * <p> 321 * Returns <code>true</code>. 322 * </p> 323 */ 324 @Override shallLookupGlobal()325 public final boolean shallLookupGlobal() { 326 return true; 327 } 328 329 @Override getGlueLibNames()330 public final List<String> getGlueLibNames() { 331 return glueLibNames; 332 } 333 334 @Override getToolLibNames()335 public final List<List<String>> getToolLibNames() { 336 final List<List<String>> libsList = new ArrayList<List<String>>(); 337 338 // 6: util, format, codec, device, avresample, swresample 339 340 final List<String> avutil = new ArrayList<String>(); 341 avutil.add("avutil"); // default 342 343 avutil.add("libavutil.so.55"); // dummy future proof 344 avutil.add("libavutil.so.54"); // ffmpeg 2.[4-x] / libav 11 345 avutil.add("libavutil.so.53"); // ffmpeg 2.[0-3] / libav 10 346 avutil.add("libavutil.so.52"); // ffmpeg 1.2 + 2.[0-3] / libav 9 347 avutil.add("libavutil.so.51"); // 0.8 348 avutil.add("libavutil.so.50"); // 0.7 349 350 avutil.add("avutil-55"); // dummy future proof 351 avutil.add("avutil-54"); // ffmpeg 2.[4-x] / libav 11 352 avutil.add("avutil-53"); // ffmpeg 2.[0-3] / libav 10 353 avutil.add("avutil-52"); // ffmpeg 1.2 + 2.[0-3] / libav 9 354 avutil.add("avutil-51"); // 0.8 355 avutil.add("avutil-50"); // 0.7 356 libsList.add(avutil); 357 358 final List<String> avformat = new ArrayList<String>(); 359 avformat.add("avformat"); // default 360 361 avformat.add("libavformat.so.57"); // dummy future proof 362 avformat.add("libavformat.so.56"); // ffmpeg 2.[4-x] / libav 11 363 avformat.add("libavformat.so.55"); // ffmpeg 2.[0-3] / libav 10 364 avformat.add("libavformat.so.54"); // ffmpeg 1.2 / libav 9 365 avformat.add("libavformat.so.53"); // 0.8 366 avformat.add("libavformat.so.52"); // 0.7 367 368 avformat.add("avformat-57"); // dummy future proof 369 avformat.add("avformat-56"); // ffmpeg 2.[4-x] / libav 11 370 avformat.add("avformat-55"); // ffmpeg 2.[0-3] / libav 10 371 avformat.add("avformat-54"); // ffmpeg 1.2 / libav 9 372 avformat.add("avformat-53"); // 0.8 373 avformat.add("avformat-52"); // 0.7 374 libsList.add(avformat); 375 376 final List<String> avcodec = new ArrayList<String>(); 377 avcodec.add("avcodec"); // default 378 379 avcodec.add("libavcodec.so.57"); // dummy future proof 380 avcodec.add("libavcodec.so.56"); // ffmpeg 2.[4-x] / libav 11 381 avcodec.add("libavcodec.so.55"); // ffmpeg 2.[0-3] / libav 10 382 avcodec.add("libavcodec.so.54"); // ffmpeg 1.2 / libav 9 383 avcodec.add("libavcodec.so.53"); // 0.8 384 avcodec.add("libavcodec.so.52"); // 0.7 385 386 avcodec.add("avcodec-57"); // dummy future proof 387 avcodec.add("avcodec-56"); // ffmpeg 2.[4-x] / libav 11 388 avcodec.add("avcodec-55"); // ffmpeg 2.[0-3] / libav 10 389 avcodec.add("avcodec-54"); // ffmpeg 1.2 / libav 9 390 avcodec.add("avcodec-53"); // 0.8 391 avcodec.add("avcodec-52"); // 0.7 392 libsList.add(avcodec); 393 394 final List<String> avdevice = new ArrayList<String>(); 395 avdevice.add("avdevice"); // default 396 397 avdevice.add("libavdevice.so.57"); // dummy future proof 398 avdevice.add("libavdevice.so.56"); // ffmpeg 2.[4-x] 399 avdevice.add("libavdevice.so.55"); // ffmpeg 2.[0-3] / libav 11 400 avdevice.add("libavdevice.so.54"); // ffmpeg 1.2 / libav 10 401 avdevice.add("libavdevice.so.53"); // 0.8 && libav 9 402 403 avdevice.add("avdevice-57"); // dummy future proof 404 avdevice.add("avdevice-56"); // ffmpeg 2.[4-x] 405 avdevice.add("avdevice-55"); // ffmpeg 2.[0-3] / libav 11 406 avdevice.add("avdevice-54"); // ffmpeg 1.2 / libav 10 407 avdevice.add("avdevice-53"); // 0.8 && libav 9 408 libsList.add(avdevice); 409 410 final List<String> avresample = new ArrayList<String>(); 411 avresample.add("avresample"); // default 412 413 avresample.add("libavresample.so.3"); // dummy future proof 414 avresample.add("libavresample.so.2"); // libav 11 415 avresample.add("libavresample.so.1"); // libav 9 + 10 416 417 avresample.add("avresample-3"); // dummy future proof 418 avresample.add("avresample-2"); // libav 11 419 avresample.add("avresample-1"); // libav 9 + 10 420 libsList.add(avresample); 421 422 final List<String> swresample = new ArrayList<String>(); 423 swresample.add("swresample"); // default 424 425 swresample.add("libswresample.so.2"); // dummy future proof 426 swresample.add("libswresample.so.1"); // ffmpeg 2.[4-x] 427 swresample.add("libswresample.so.0"); // ffmpeg 1.2 + 2.[0-3] 428 429 swresample.add("swresample-2"); // dummy future proof 430 swresample.add("swresample-1"); // ffmpeg 2.[4-x] 431 swresample.add("swresample-0"); // ffmpeg 1.2 + 2.[0-3] 432 libsList.add(swresample); 433 434 return libsList; 435 } 436 437 @Override getToolGetProcAddressFuncNameList()438 public final List<String> getToolGetProcAddressFuncNameList() { 439 return null; 440 } 441 442 @Override toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName)443 public final long toolGetProcAddress(final long toolGetProcAddressHandle, final String funcName) { 444 return 0; 445 } 446 447 @Override useToolGetProcAdressFirst(final String funcName)448 public final boolean useToolGetProcAdressFirst(final String funcName) { 449 return false; 450 } 451 452 @Override getLibLoaderExecutor()453 public final RunnableExecutor getLibLoaderExecutor() { 454 return DynamicLibraryBundle.getDefaultRunnableExecutor(); 455 } 456 } 457