OLD | NEW |
---|---|
1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. | 1 // Copyright (c) 2011 The Chromium Authors. All rights reserved. |
2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
4 | 4 |
5 #include "media/base/media.h" | 5 #include "media/base/media.h" |
6 | 6 |
7 #include <windows.h> | 7 #include <windows.h> |
8 #include <delayimp.h> | |
9 | |
10 #include <string> | |
8 | 11 |
9 #include "base/file_path.h" | 12 #include "base/file_path.h" |
10 #include "base/logging.h" | 13 #include "base/logging.h" |
11 #include "base/memory/scoped_ptr.h" | 14 #include "base/memory/scoped_ptr.h" |
12 #include "base/native_library.h" | 15 #include "base/native_library.h" |
13 #include "base/path_service.h" | 16 #include "base/path_service.h" |
14 | 17 |
18 #pragma comment(lib, "delayimp.lib") | |
19 | |
15 namespace media { | 20 namespace media { |
16 | 21 |
17 enum FFmpegDLLKeys { | 22 enum FFmpegDLLKeys { |
18 FILE_LIBAVCODEC, // full path to libavcodec media decoding library. | 23 FILE_LIBAVCODEC, // full path to libavcodec media decoding library. |
19 FILE_LIBAVFORMAT, // full path to libavformat media parsing library. | 24 FILE_LIBAVFORMAT, // full path to libavformat media parsing library. |
20 FILE_LIBAVUTIL, // full path to libavutil media utility library. | 25 FILE_LIBAVUTIL, // full path to libavutil media utility library. |
21 }; | 26 }; |
22 | 27 |
23 // Retrieves the DLLName for the given key. | 28 // Retrieves the DLLName for the given key. |
24 static FilePath::CharType* GetDLLName(FFmpegDLLKeys dll_key) { | 29 static const char* GetDLLName(FFmpegDLLKeys dll_key) { |
25 // TODO(ajwong): Do we want to lock to a specific ffmpeg version? | 30 // TODO(ajwong): Do we want to lock to a specific ffmpeg version? |
26 switch (dll_key) { | 31 switch (dll_key) { |
27 case FILE_LIBAVCODEC: | 32 case FILE_LIBAVCODEC: |
28 return FILE_PATH_LITERAL("avcodec-53.dll"); | 33 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
| |
29 case FILE_LIBAVFORMAT: | 34 case FILE_LIBAVFORMAT: |
30 return FILE_PATH_LITERAL("avformat-53.dll"); | 35 return "avformat-53.dll"; |
31 case FILE_LIBAVUTIL: | 36 case FILE_LIBAVUTIL: |
32 return FILE_PATH_LITERAL("avutil-51.dll"); | 37 return "avutil-51.dll"; |
33 default: | 38 default: |
34 LOG(DFATAL) << "Invalid DLL key requested: " << dll_key; | 39 LOG(DFATAL) << "Invalid DLL key requested: " << dll_key; |
35 return FILE_PATH_LITERAL(""); | 40 return ""; |
36 } | 41 } |
37 } | 42 } |
38 | 43 |
39 static bool g_media_library_is_initialized = false; | 44 static bool g_media_library_is_initialized = false; |
40 | 45 |
46 // Handler for SEH when delay loading -- we want to catch everything | |
47 // delayload-related, but crash on access violation and such. | |
48 static int delay_load_exception_filter(unsigned int exception_code) { | |
49 switch (exception_code) { | |
50 case VcppException(ERROR_SEVERITY_ERROR, ERROR_INVALID_PARAMETER): | |
51 case VcppException(ERROR_SEVERITY_ERROR, ERROR_MOD_NOT_FOUND): | |
52 case VcppException(ERROR_SEVERITY_ERROR, ERROR_PROC_NOT_FOUND): | |
53 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
| |
54 default: | |
55 return EXCEPTION_CONTINUE_SEARCH; | |
56 } | |
57 } | |
58 | |
59 // 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?
| |
60 static bool PatchImportTable(const char *dll) { | |
scherkus (not reviewing)
2012/02/23 05:22:55
pointer w/ type: const char* dll
| |
61 __try { | |
62 if (FAILED(::__HrLoadAllImportsForDll(dll))) | |
63 return false; | |
64 } __except(delay_load_exception_filter(GetExceptionCode())) { | |
65 return false; | |
66 } | |
67 return true; | |
68 } | |
69 | |
41 // Attempts to initialize the media library (loading DLLs, DSOs, etc.). | 70 // Attempts to initialize the media library (loading DLLs, DSOs, etc.). |
42 // Returns true if everything was successfully initialized, false otherwise. | 71 // Returns true if everything was successfully initialized, false otherwise. |
43 bool InitializeMediaLibrary(const FilePath& base_path) { | 72 bool InitializeMediaLibrary(const FilePath& base_path) { |
44 if (g_media_library_is_initialized) | 73 if (g_media_library_is_initialized) |
45 return true; | 74 return true; |
46 | 75 |
47 FFmpegDLLKeys path_keys[] = { | 76 FFmpegDLLKeys path_keys[] = { |
48 media::FILE_LIBAVCODEC, | 77 media::FILE_LIBAVCODEC, |
49 media::FILE_LIBAVFORMAT, | 78 media::FILE_LIBAVFORMAT, |
50 media::FILE_LIBAVUTIL | 79 media::FILE_LIBAVUTIL |
51 }; | 80 }; |
52 HMODULE libs[arraysize(path_keys)] = {NULL}; | 81 HMODULE libs[arraysize(path_keys)] = {NULL}; |
53 | 82 |
83 // Convert to absolute path, customer can specify relative path by | |
84 // command-line flag, and LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH) | |
85 // does not allow relative paths. | |
86 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
| |
87 0, | |
88 NULL, | |
89 NULL); | |
90 if (full_path_len == 0) | |
91 return false; | |
92 std::wstring full_path(full_path_len, 0); | |
93 ::GetFullPathName(base_path.value().c_str(), | |
94 full_path_len, | |
95 &full_path[0], | |
96 NULL); | |
97 full_path.resize(full_path_len - 1); // Get rid of terminating NUL character. | |
98 | |
54 for (size_t i = 0; i < arraysize(path_keys); ++i) { | 99 for (size_t i = 0; i < arraysize(path_keys); ++i) { |
55 FilePath path = base_path.Append(GetDLLName(path_keys[i])); | 100 FilePath path(full_path); |
101 path = path.AppendASCII(GetDLLName(path_keys[i])); | |
56 | 102 |
57 // Use alternate DLL search path so we don't load dependencies from the | 103 // Use alternate DLL search path so we don't load dependencies from the |
58 // system path. Refer to http://crbug.com/35857 | 104 // system path. Refer to http://crbug.com/35857 |
59 const wchar_t* cpath = path.value().c_str(); | 105 const wchar_t* cpath = path.value().c_str(); |
60 libs[i] = LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); | 106 libs[i] = ::LoadLibraryEx(cpath, NULL, LOAD_WITH_ALTERED_SEARCH_PATH); |
61 if (!libs[i]) | 107 if (!libs[i]) |
62 break; | 108 break; |
63 } | 109 } |
64 | 110 |
65 // Check that we loaded all libraries successfully. We only need to check the | 111 // Check that we loaded all libraries successfully. We only need to check the |
66 // last array element because the loop above will break without initializing | 112 // last array element because the loop above will break without initializing |
67 // it on any prior error. | 113 // it on any prior error. |
68 g_media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); | 114 bool media_library_is_initialized = (libs[arraysize(libs) - 1] != NULL); |
69 | 115 |
70 if (!g_media_library_is_initialized) { | 116 if (!media_library_is_initialized) { |
71 // Free any loaded libraries if we weren't successful. | 117 // Free any loaded libraries if we weren't successful. |
72 for (size_t i = 0; i < arraysize(libs) && libs[i] != NULL; ++i) { | 118 for (size_t i = 0; i < arraysize(libs) && libs[i] != NULL; ++i) { |
73 FreeLibrary(libs[i]); | 119 FreeLibrary(libs[i]); |
74 libs[i] = NULL; // Just to be safe. | 120 libs[i] = NULL; // Just to be safe. |
75 } | 121 } |
122 return false; | |
76 } | 123 } |
77 | 124 |
78 return g_media_library_is_initialized; | 125 // Workaround for http://crbug.com/110983 |
126 // LoadLibrary() sometimes AV's when called by delay load helper when we | |
scherkus (not reviewing)
2012/02/23 05:22:55
what's AV?
| |
127 // call function in ffmpeg for the first time, and we don't know why. | |
128 // Force delay load helper to fix import table here instead. | |
129 // Theoretically, there is no need to call LoadLibrary() before | |
130 // __HrLoadAllImportsForDll(), it will call LoadLibrary() itself, but there | |
131 // is no way to specify LOAD_WITH_ALTERED_SEARCH_PATH when calling | |
132 // __HrLoadAllImportsForDll(). So we do everything in 2 steps -- first call | |
133 // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH), then call | |
134 // __HrLoadAllImportsForDll(). Overhead is negligible compared to disk | |
135 // access time. | |
136 // Note: in case of error we are not unloading DLL because unload requires | |
137 // extra resources and should not be necessary; if we ever decide to | |
138 // unload by calling __FUnloadDelayLoadedDLL() please add /DELAY:UNLOAD | |
139 // to the linker command line. | |
140 for (size_t i = 0; i < arraysize(path_keys); ++i) { | |
141 media_library_is_initialized &= PatchImportTable(GetDLLName(path_keys[i])); | |
142 } | |
143 | |
144 g_media_library_is_initialized = media_library_is_initialized; | |
145 return media_library_is_initialized; | |
79 } | 146 } |
80 | 147 |
81 void InitializeMediaLibraryForTesting() { | 148 void InitializeMediaLibraryForTesting() { |
82 FilePath file_path; | 149 FilePath file_path; |
83 CHECK(PathService::Get(base::DIR_EXE, &file_path)); | 150 CHECK(PathService::Get(base::DIR_EXE, &file_path)); |
84 CHECK(InitializeMediaLibrary(file_path)); | 151 CHECK(InitializeMediaLibrary(file_path)); |
85 } | 152 } |
86 | 153 |
87 bool IsMediaLibraryInitialized() { | 154 bool IsMediaLibraryInitialized() { |
88 return g_media_library_is_initialized; | 155 return g_media_library_is_initialized; |
89 } | 156 } |
90 | 157 |
91 bool InitializeOpenMaxLibrary(const FilePath& module_dir) { | 158 bool InitializeOpenMaxLibrary(const FilePath& module_dir) { |
92 NOTIMPLEMENTED() << "OpenMAX is not used in Windows."; | 159 NOTIMPLEMENTED() << "OpenMAX is not used in Windows."; |
93 return false; | 160 return false; |
94 } | 161 } |
95 | 162 |
96 } // namespace media | 163 } // namespace media |
OLD | NEW |