summaryrefslogtreecommitdiffstats
path: root/media/base/media_win.cc
diff options
context:
space:
mode:
authorenal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 02:02:21 +0000
committerenal@chromium.org <enal@chromium.org@0039d316-1c4b-4281-b951-d872f2087c98>2012-02-28 02:02:21 +0000
commitcde840d31743fe685066c92060a7e045516b9a84 (patch)
tree6465a2348833c3591ead4f39426834c68e69ebb7 /media/base/media_win.cc
parent09dd320b7078a141e312c0bcf7297c431ed6469f (diff)
downloadchromium_src-cde840d31743fe685066c92060a7e045516b9a84.zip
chromium_src-cde840d31743fe685066c92060a7e045516b9a84.tar.gz
chromium_src-cde840d31743fe685066c92060a7e045516b9a84.tar.bz2
Workaround for Windows-only crash inside delay load helper.
Crash report shows access violation inside LoadLibraryExA() called from DelayLoadHelper2(), and we cannot figure out what exactly causes the problem. In theory it can be caused by Chrome terminating while we are initializing ffmpeg code, but I am not sure. Workaround is to call delay load helper to patch import tables during renderer initialization. We are loading ffmpeg DLL at this moment anyways but do not patch import tables. Extra overhead is negligeable compared to disk access time. Also fixed potential problem -- LoadLibraryEx() does not accept relative paths when used as we are using it. During normal startup we are getting absolute path, but customer can specify relative path as a command-line flag. Fix is to call Windows API GetFullPathName() to get rid of relative path. BUG=110983. Review URL: http://codereview.chromium.org/9450001 git-svn-id: svn://svn.chromium.org/chrome/trunk/src@123865 0039d316-1c4b-4281-b951-d872f2087c98
Diffstat (limited to 'media/base/media_win.cc')
-rw-r--r--media/base/media_win.cc54
1 files changed, 43 insertions, 11 deletions
diff --git a/media/base/media_win.cc b/media/base/media_win.cc
index 9462c02..6b4c07e 100644
--- a/media/base/media_win.cc
+++ b/media/base/media_win.cc
@@ -1,10 +1,11 @@
-// Copyright (c) 2011 The Chromium Authors. All rights reserved.
+// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#include "media/base/media.h"
#include <windows.h>
+#include <delayimp.h>
#include "base/file_path.h"
#include "base/logging.h"
@@ -12,6 +13,8 @@
#include "base/native_library.h"
#include "base/path_service.h"
+#pragma comment(lib, "delayimp.lib")
+
namespace media {
enum FFmpegDLLKeys {
@@ -21,18 +24,18 @@ enum FFmpegDLLKeys {
};
// 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";
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 "";
}
}
@@ -44,6 +47,11 @@ bool InitializeMediaLibrary(const FilePath& base_path) {
if (g_media_library_is_initialized)
return true;
+ // LoadLibraryEx(..., LOAD_WITH_ALTERED_SEARCH_PATH) cannot handle
+ // relative path.
+ if (!base_path.IsAbsolute())
+ return false;
+
FFmpegDLLKeys path_keys[] = {
media::FILE_LIBAVCODEC,
media::FILE_LIBAVFORMAT,
@@ -52,12 +60,12 @@ bool InitializeMediaLibrary(const FilePath& base_path) {
HMODULE libs[arraysize(path_keys)] = {NULL};
for (size_t i = 0; i < arraysize(path_keys); ++i) {
- FilePath path = base_path.Append(GetDLLName(path_keys[i]));
+ FilePath path = base_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 +73,41 @@ bool InitializeMediaLibrary(const FilePath& base_path) {
// 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
+ // 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.
+ // TODO(enal): remove that code when we find underlying issue. Delay load
+ // should work if library is alreday in memory, regardless of permissions...
+ for (size_t i = 0; i < arraysize(path_keys); ++i) {
+ if (FAILED(::__HrLoadAllImportsForDll(GetDLLName(path_keys[i]))))
+ media_library_is_initialized = false;
+ }
+
+ g_media_library_is_initialized = media_library_is_initialized;
+ return media_library_is_initialized;
}
void InitializeMediaLibraryForTesting() {