Chromium Code Reviews| Index: media/base/media_win.cc |
| =================================================================== |
| --- media/base/media_win.cc (revision 122285) |
| +++ media/base/media_win.cc (working copy) |
| @@ -5,13 +5,18 @@ |
| #include "media/base/media.h" |
| #include <windows.h> |
| +#include <delayimp.h> |
| +#include <string> |
| + |
| #include "base/file_path.h" |
| #include "base/logging.h" |
| #include "base/memory/scoped_ptr.h" |
| #include "base/native_library.h" |
| #include "base/path_service.h" |
| +#pragma comment(lib, "delayimp.lib") |
| + |
| namespace media { |
| enum FFmpegDLLKeys { |
| @@ -21,23 +26,47 @@ |
| }; |
| // Retrieves the DLLName for the given key. |
| -static FilePath::CharType* GetDLLName(FFmpegDLLKeys dll_key) { |
| +static const char* GetDLLName(FFmpegDLLKeys dll_key) { |
| // TODO(ajwong): Do we want to lock to a specific ffmpeg version? |
| switch (dll_key) { |
| case FILE_LIBAVCODEC: |
| - return FILE_PATH_LITERAL("avcodec-53.dll"); |
| + return "avcodec-53.dll"; |
|
scherkus (not reviewing)
2012/02/23 05:22:55
dalecurtis: do these need updated?
DaleCurtis
2012/02/23 21:03:08
Not since the FFmpeg roll got reverted. Just make
|
| case FILE_LIBAVFORMAT: |
| - return FILE_PATH_LITERAL("avformat-53.dll"); |
| + return "avformat-53.dll"; |
| case FILE_LIBAVUTIL: |
| - return FILE_PATH_LITERAL("avutil-51.dll"); |
| + return "avutil-51.dll"; |
| default: |
| LOG(DFATAL) << "Invalid DLL key requested: " << dll_key; |
| - return FILE_PATH_LITERAL(""); |
| + return ""; |
| } |
| } |
| static bool g_media_library_is_initialized = false; |
| +// Handler for SEH when delay loading -- we want to catch everything |
| +// delayload-related, but crash on access violation and such. |
| +static int delay_load_exception_filter(unsigned int exception_code) { |
| + switch (exception_code) { |
| + case VcppException(ERROR_SEVERITY_ERROR, ERROR_INVALID_PARAMETER): |
| + case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND): |
| + case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND): |
| + return EXCEPTION_EXECUTE_HANDLER; |
|
cpu_(ooo_6.6-7.5)
2012/02/23 23:58:25
I don't understand the purpose of the patch. You s
|
| + default: |
| + return EXCEPTION_CONTINUE_SEARCH; |
| + } |
| +} |
| + |
| +// Fixes import table for DLL. Returns true if succeed, false otherwise. |
|
scherkus (not reviewing)
2012/02/23 05:22:55
so this function doesn't require absolute paths?
|
| +static bool PatchImportTable(const char *dll) { |
|
scherkus (not reviewing)
2012/02/23 05:22:55
pointer w/ type: const char* dll
|
| + __try { |
| + if (FAILED(::__HrLoadAllImportsForDll(dll))) |
| + return false; |
| + } __except(delay_load_exception_filter(GetExceptionCode())) { |
| + return false; |
| + } |
| + return true; |
| +} |
| + |
| // Attempts to initialize the media library (loading DLLs, DSOs, etc.). |
| // Returns true if everything was successfully initialized, false otherwise. |
| bool InitializeMediaLibrary(const FilePath& base_path) { |
| @@ -51,13 +80,30 @@ |
| }; |
| HMODULE libs[arraysize(path_keys)] = {NULL}; |
| + // Convert to absolute path, customer can specify relative path by |
| + // command-line flag, and LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH) |
| + // does not allow relative paths. |
| + DWORD full_path_len = ::GetFullPathName(base_path.value().c_str(), |
|
scherkus (not reviewing)
2012/02/23 05:22:55
perhaps turn this into a function like GetFullFile
|
| + 0, |
| + NULL, |
| + NULL); |
| + if (full_path_len == 0) |
| + return false; |
| + std::wstring full_path(full_path_len, 0); |
| + ::GetFullPathName(base_path.value().c_str(), |
| + full_path_len, |
| + &full_path[0], |
| + NULL); |
| + full_path.resize(full_path_len - 1); // Get rid of terminating NUL character. |
| + |
| for (size_t i = 0; i < arraysize(path_keys); ++i) { |
| - FilePath path = base_path.Append(GetDLLName(path_keys[i])); |
| + FilePath path(full_path); |
| + path = path.AppendASCII(GetDLLName(path_keys[i])); |
| // Use alternate DLL search path so we don't load dependencies from the |
| // system path. Refer to http://crbug.com/35857 |
| const wchar_t* cpath = path.value().c_str(); |
| - libs[i] = LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| + libs[i] = ::LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
| if (!libs[i]) |
| break; |
| } |
| @@ -65,17 +111,38 @@ |
| // Check that we loaded all libraries successfully. We only need to check the |
| // last array element because the loop above will break without initializing |
| // it on any prior error. |
| - g_media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); |
| + bool media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); |
| - if (!g_media_library_is_initialized) { |
| + if (!media_library_is_initialized) { |
| // Free any loaded libraries if we weren't successful. |
| for (size_t i = 0; i < arraysize(libs) && libs[i] != NULL; ++i) { |
| FreeLibrary(libs[i]); |
| libs[i] = NULL; // Just to be safe. |
| } |
| + return false; |
| } |
| - return g_media_library_is_initialized; |
| + // Workaround for http://crbug.com/110983 |
| + // LoadLibrary() sometimes AV's when called by delay load helper when we |
|
scherkus (not reviewing)
2012/02/23 05:22:55
what's AV?
|
| + // call function in ffmpeg for the first time, and we don't know why. |
| + // Force delay load helper to fix import table here instead. |
| + // Theoretically, there is no need to call LoadLibrary() before |
| + // __HrLoadAllImportsForDll(), it will call LoadLibrary() itself, but there |
| + // is no way to specify LOAD_WITH_ALTERED_SEARCH_PATH when calling |
| + // __HrLoadAllImportsForDll(). So we do everything in 2 steps -- first call |
| + // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH), then call |
| + // __HrLoadAllImportsForDll(). Overhead is negligible compared to disk |
| + // access time. |
| + // Note: in case of error we are not unloading DLL because unload requires |
| + // extra resources and should not be necessary; if we ever decide to |
| + // unload by calling __FUnloadDelayLoadedDLL() please add /DELAY:UNLOAD |
| + // to the linker command line. |
| + for (size_t i = 0; i < arraysize(path_keys); ++i) { |
| + media_library_is_initialized &= PatchImportTable(GetDLLName(path_keys[i])); |
| + } |
| + |
| + g_media_library_is_initialized = media_library_is_initialized; |
| + return media_library_is_initialized; |
| } |
| void InitializeMediaLibraryForTesting() { |