Bug 837539 - Fix crashes due to premature deinitialization. r=rjesup,bgirard a=lsblakk
authorSteven Michaud <smichaud@pobox.com>
Mon, 04 Mar 2013 11:12:32 -0600
changeset 132289 4ade964d1f6fcd33ccd2d7dbc67f5bae180188db
parent 132288 c38206da16d5286363fd8afb0087a5297328c130
child 132290 827fecd4e88964f44cf9f0b8b26113a570bcd367
push id2323
push userbbajaj@mozilla.com
push dateMon, 01 Apr 2013 19:47:02 +0000
treeherdermozilla-beta@7712be144d91 [default view] [failures only]
perfherder[talos] [build metrics] [platform microbench] (compared to previous push)
reviewersrjesup, bgirard, lsblakk
bugs837539
milestone21.0a2
Bug 837539 - Fix crashes due to premature deinitialization. r=rjesup,bgirard a=lsblakk
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.mm
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.h
media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.mm
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.mm
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit.mm
@@ -10,16 +10,30 @@
 
 #include "video_capture_qtkit.h"
 #import "video_capture_qtkit_objc.h"
 #import "video_capture_qtkit_info_objc.h"
 #include "trace.h"
 #include "critical_section_wrapper.h"
 #include "../../video_capture_config.h"
 
+class nsAutoreleasePool {
+public:
+    nsAutoreleasePool()
+    {
+        mLocalPool = [[NSAutoreleasePool alloc] init];
+    }
+    ~nsAutoreleasePool()
+    {
+        [mLocalPool release];
+    }
+private:
+    NSAutoreleasePool *mLocalPool;
+};
+
 namespace webrtc
 {
 
 namespace videocapturemodule
 {
 
 VideoCaptureMacQTKit::VideoCaptureMacQTKit(const WebRtc_Word32 id) :
     VideoCaptureImpl(id),
@@ -36,16 +50,17 @@ VideoCaptureMacQTKit::VideoCaptureMacQTK
     memset(_currentDeviceNameUTF8, 0, MAX_NAME_LENGTH);
     memset(_currentDeviceUniqueIdUTF8, 0, MAX_NAME_LENGTH);
     memset(_currentDeviceProductUniqueIDUTF8, 0, MAX_NAME_LENGTH);
 }
 
 VideoCaptureMacQTKit::~VideoCaptureMacQTKit()
 {
 
+    nsAutoreleasePool localPool;
     WEBRTC_TRACE(webrtc::kTraceDebug, webrtc::kTraceVideoCapture, _id,
                  "~VideoCaptureMacQTKit() called");
     if(_captureDevice)
     {
         [_captureDevice stopCapture];
         [_captureDevice release];
     }
 
@@ -65,16 +80,18 @@ WebRtc_Word32 VideoCaptureMacQTKit::Init
         (WebRtc_Word32) strlen((char*)iDeviceUniqueIdUTF8);
     if(nameLength>kVideoCaptureUniqueNameLength)
         return -1;
 
     // Store the device name
     _deviceUniqueId = new char[nameLength+1];
     memcpy(_deviceUniqueId, iDeviceUniqueIdUTF8,nameLength+1);
 
+    nsAutoreleasePool localPool;
+
     _captureDevice = [[VideoCaptureMacQTKitObjC alloc] init];
     if(NULL == _captureDevice)
     {
         WEBRTC_TRACE(webrtc::kTraceError, webrtc::kTraceVideoCapture, id,
                      "Failed to create an instance of "
                      "VideoCaptureMacQTKitObjC");
         return -1;
     }
@@ -164,16 +181,17 @@ WebRtc_Word32 VideoCaptureMacQTKit::Init
                  "successfully Init VideoCaptureMacQTKit" );
     return 0;
 }
 
 WebRtc_Word32 VideoCaptureMacQTKit::StartCapture(
     const VideoCaptureCapability& capability)
 {
 
+    nsAutoreleasePool localPool;
     _captureWidth = capability.width;
     _captureHeight = capability.height;
     _captureFrameRate = capability.maxFPS;
     _captureDelay = 120;
 
     if(-1 == [[_captureDevice setCaptureHeight:_captureHeight
                AndWidth:_captureWidth AndFrameRate:_captureFrameRate]intValue])
     {
@@ -188,16 +206,17 @@ WebRtc_Word32 VideoCaptureMacQTKit::Star
         return -1;
     }
     _isCapturing = true;
     return 0;
 }
 
 WebRtc_Word32 VideoCaptureMacQTKit::StopCapture()
 {
+    nsAutoreleasePool localPool;
     [_captureDevice stopCapture];
 
     _isCapturing = false;
     return 0;
 }
 
 bool VideoCaptureMacQTKit::CaptureStarted()
 {
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.mm
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info.mm
@@ -9,54 +9,71 @@
  */
 
 #include "trace.h"
 #include "../../video_capture_config.h"
 #import "video_capture_qtkit_info_objc.h"
 
 #include "video_capture.h"
 
+class nsAutoreleasePool {
+public:
+    nsAutoreleasePool()
+    {
+        mLocalPool = [[NSAutoreleasePool alloc] init];
+    }
+    ~nsAutoreleasePool()
+    {
+        [mLocalPool release];
+    }
+private:
+    NSAutoreleasePool *mLocalPool;
+};
+
 namespace webrtc
 {
 namespace videocapturemodule
 {
 
 VideoCaptureMacQTKitInfo::VideoCaptureMacQTKitInfo(const WebRtc_Word32 id) :
     DeviceInfoImpl(id)
 {
+    nsAutoreleasePool localPool;
     _captureInfo = [[VideoCaptureMacQTKitInfoObjC alloc] init];
 }
 
 VideoCaptureMacQTKitInfo::~VideoCaptureMacQTKitInfo()
 {
+    nsAutoreleasePool localPool;
     [_captureInfo release];
-
 }
 
 WebRtc_Word32 VideoCaptureMacQTKitInfo::Init()
 {
 
     return 0;
 }
 
 WebRtc_UWord32 VideoCaptureMacQTKitInfo::NumberOfDevices()
 {
 
+    nsAutoreleasePool localPool;
     WebRtc_UWord32 captureDeviceCount =
         [[_captureInfo getCaptureDeviceCount]intValue];
     return captureDeviceCount;
 
 }
 
 WebRtc_Word32 VideoCaptureMacQTKitInfo::GetDeviceName(
     WebRtc_UWord32 deviceNumber, char* deviceNameUTF8,
     WebRtc_UWord32 deviceNameLength, char* deviceUniqueIdUTF8,
     WebRtc_UWord32 deviceUniqueIdUTF8Length, char* productUniqueIdUTF8,
     WebRtc_UWord32 productUniqueIdUTF8Length)
 {
+    nsAutoreleasePool localPool;
     int errNum = [[_captureInfo getDeviceNamesFromIndex:deviceNumber
                    DefaultName:deviceNameUTF8 WithLength:deviceNameLength
                    AndUniqueID:deviceUniqueIdUTF8
                    WithLength:deviceUniqueIdUTF8Length
                    AndProductID:productUniqueIdUTF8
                    WithLength:productUniqueIdUTF8Length]intValue];
     return errNum;
 }
@@ -100,16 +117,17 @@ WebRtc_Word32 VideoCaptureMacQTKitInfo::
 }
 
 WebRtc_Word32 VideoCaptureMacQTKitInfo::DisplayCaptureSettingsDialogBox(
     const char* deviceUniqueIdUTF8,
     const char* dialogTitleUTF8, void* parentWindow,
     WebRtc_UWord32 positionX, WebRtc_UWord32 positionY)
 {
 
+    nsAutoreleasePool localPool;
     return [[_captureInfo
              displayCaptureSettingsDialogBoxWithDevice:deviceUniqueIdUTF8
              AndTitle:dialogTitleUTF8
              AndParentWindow:parentWindow AtX:positionX AndY:positionY]
              intValue];
 }
 
 WebRtc_Word32 VideoCaptureMacQTKitInfo::CreateCapabilityMap(
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.h
@@ -19,17 +19,16 @@
 #import <QTKit/QTKit.h>
 #import <Foundation/Foundation.h>
 #include "video_capture_qtkit_utility.h"
 #include "video_capture_qtkit_info.h"
 
 @interface VideoCaptureMacQTKitInfoObjC : NSObject{
     bool                                _OSSupportedInfo;
     NSArray*                            _captureDevicesInfo;
-    NSAutoreleasePool*                    _poolInfo;
     int                                    _captureDeviceCountInfo;
 
 }
 
 /**************************************************************************
  *
  *   The following functions are considered to be private
  *
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.mm
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_info_objc.mm
@@ -134,17 +134,16 @@ using namespace webrtc;
 
 - (NSNumber*)initializeVariables
 {
     if(NO == _OSSupportedInfo)
     {
         return [NSNumber numberWithInt:0];
     }
 
-    _poolInfo = [[NSAutoreleasePool alloc]init];
     _captureDeviceCountInfo = 0;
     [self getCaptureDevices];
 
     return [NSNumber numberWithInt:0];
 }
 
 // ***** Checks to see if the QTCaptureSession framework is available in the OS
 // ***** If it is not, isOSSupprted = NO
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.h
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.h
@@ -53,19 +53,16 @@
     NSString*                            _captureDeviceName;
     char                                _captureDeviceNameUTF8[1024];
     char                                _captureDeviceNameUniqueID[1024];
     char                                _captureDeviceNameProductID[1024];
     NSString*                            _key;
     NSNumber*                            _val;
     NSDictionary*                        _videoSettings;
     NSString*                            _captureQuality;
-    
-    // other
-    NSAutoreleasePool*                    _pool;
 
 }
 /**************************************************************************
  *
  *   The following functions are considered to be private.
  *
  ***************************************************************************/
 
--- a/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.mm
+++ b/media/webrtc/trunk/webrtc/modules/video_capture/mac/qtkit/video_capture_qtkit_objc.mm
@@ -255,17 +255,27 @@ using namespace videocapturemodule;
 
     if(NO == _capturing)
     {
         return [NSNumber numberWithInt:0];
     }
 
     if(YES == _capturing)
     {
-        [_captureSession stopRunning];
+        // This method is often called on a secondary thread.  Which means
+        // that the following can sometimes run "too early", causing crashes
+        // and/or weird errors concerning initialization.  On OS X 10.7 and
+        // 10.8, the CoreMediaIO method CMIOUninitializeGraph() is called from
+        // -[QTCaptureSession stopRunning].  If this is called too early,
+        // low-level session data gets uninitialized before low-level code
+        // is finished trying to use it.  The solution is to make stopRunning
+        // always run on the main thread.  See bug 837539.
+        [_captureSession performSelectorOnMainThread:@selector(stopRunning)
+                                          withObject:nil
+                                       waitUntilDone:NO];
     }
 
     _capturing = NO;
     return [NSNumber numberWithInt:0];
 }
 
 // ********** "private" functions below here **********
 #pragma mark **** "private" methods
@@ -274,18 +284,16 @@ using namespace videocapturemodule;
 /// ***** Returns 0 on success, -1 otherwise.
 - (NSNumber*)initializeVariables{
 
     if(NO == _OSSupported)
     {
         return [NSNumber numberWithInt:0];
     }
 
-    _pool = [[NSAutoreleasePool alloc]init];
-
     memset(_captureDeviceNameUTF8, 0, 1024);
     _counter = 0;
     _framesDelivered = 0;
     _framesRendered = 0;
     _captureDeviceCount = 0;
     _capturing = NO;
     _captureInitialized = NO;
     _frameRate = DEFAULT_FRAME_RATE;