提交 3fd9509c 编写于 作者: P PatTheMav 提交者: Jim

mac-virtualcam: Fix global namespace issues in DAL plugin

上级 2902cdb2
......@@ -25,24 +25,24 @@ include_directories(${AVFOUNDATION}
set(mac-dal-plugin_HEADERS
Defines.h
Logging.h
PlugInInterface.h
ObjectStore.h
PlugIn.h
Device.h
Stream.h
OBSDALPlugInInterface.h
OBSDALObjectStore.h
OBSDALPlugIn.h
OBSDALDevice.h
OBSDALStream.h
CMSampleBufferUtils.h
MachClient.h
OBSDALMachClient.h
../common/MachProtocol.h)
set(mac-dal-plugin_SOURCES
PlugInMain.mm
PlugInInterface.mm
ObjectStore.mm
PlugIn.mm
Device.mm
Stream.mm
OBSDALPlugInMain.mm
OBSDALPlugInInterface.mm
OBSDALObjectStore.mm
OBSDALPlugIn.mm
OBSDALDevice.mm
OBSDALStream.mm
CMSampleBufferUtils.mm
MachClient.mm)
OBSDALMachClient.mm)
add_library(mac-dal-plugin MODULE
${mac-dal-plugin_SOURCES}
......
......@@ -20,14 +20,14 @@
</array>
<key>CFPlugInFactories</key>
<dict>
<key>35FDFF29-BFCF-4644-AB77-B759DE932ABE</key>
<key>7E950B8C-5E49-4B9E-B7D0-B3608A08E8F6</key>
<string>PlugInMain</string>
</dict>
<key>CFPlugInTypes</key>
<dict>
<key>30010C1C-93BF-11D8-8B5B-000A95AF9C6A</key>
<array>
<string>35FDFF29-BFCF-4644-AB77-B759DE932ABE</string>
<string>7E950B8C-5E49-4B9E-B7D0-B3608A08E8F6</string>
</array>
</dict>
<key>LSMinimumSystemVersion</key>
......
......@@ -19,11 +19,11 @@
#import <Foundation/Foundation.h>
#import "ObjectStore.h"
#import "OBSDALObjectStore.h"
NS_ASSUME_NONNULL_BEGIN
@interface Device : NSObject <CMIOObject>
@interface OBSDALDevice : NSObject <CMIOObject>
@property CMIOObjectID objectId;
@property CMIOObjectID pluginId;
......
......@@ -17,20 +17,20 @@
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see <http://www.gnu.org/licenses/>.
#import "Device.h"
#import "OBSDALDevice.h"
#import <CoreFoundation/CoreFoundation.h>
#include <IOKit/audio/IOAudioTypes.h>
#import "PlugIn.h"
#import "OBSDALPlugin.h"
#import "Logging.h"
@interface Device ()
@interface OBSDALDevice ()
@property BOOL excludeNonDALAccess;
@property pid_t masterPid;
@end
@implementation Device
@implementation OBSDALDevice
// Note that the DAL's API calls HasProperty before calling GetPropertyDataSize. This means that it can be assumed that address is valid for the property involved.
- (UInt32)getPropertyDataSizeWithAddress:(CMIOObjectPropertyAddress)address
......@@ -87,7 +87,7 @@
return sizeof(pid_t);
default:
DLog(@"Device unhandled getPropertyDataSizeWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
};
......@@ -192,7 +192,7 @@
break;
default:
DLog(@"Device unhandled getPropertyDataWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
*dataUsed = 0;
break;
......@@ -228,7 +228,7 @@
return false;
default:
DLog(@"Device unhandled hasPropertyWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
};
......@@ -263,7 +263,7 @@
return true;
default:
DLog(@"Device unhandled isPropertySettableWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
};
......@@ -286,7 +286,7 @@
break;
default:
DLog(@"Device unhandled setPropertyDataWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
break;
};
......
......@@ -20,7 +20,7 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface MachClient : NSObject
@interface OBSDALMachClient : NSObject
@property (nullable, weak) id<MachClientDelegate> delegate;
......
......@@ -5,16 +5,16 @@
// Created by John Boiles on 5/5/20.
//
#import "MachClient.h"
#import "OBSDALMachClient.h"
#import "MachProtocol.h"
#import "Logging.h"
@interface MachClient () <NSPortDelegate> {
@interface OBSDALMachClient () <NSPortDelegate> {
NSPort *_receivePort;
}
@end
@implementation MachClient
@implementation OBSDALMachClient
- (void)dealloc
{
......
......@@ -43,9 +43,9 @@ NS_ASSUME_NONNULL_BEGIN
@end
@interface ObjectStore : NSObject
@interface OBSDALObjectStore : NSObject
+ (ObjectStore *)SharedObjectStore;
+ (OBSDALObjectStore *)SharedObjectStore;
+ (NSObject<CMIOObject> *)GetObjectWithId:(CMIOObjectID)objectId;
......
......@@ -17,13 +17,13 @@
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see <http://www.gnu.org/licenses/>.
#import "ObjectStore.h"
#import "OBSDALObjectStore.h"
@interface ObjectStore ()
@interface OBSDALObjectStore ()
@property NSMutableDictionary *objectMap;
@end
@implementation ObjectStore
@implementation OBSDALObjectStore
// 4-byte selectors to string for easy debugging
+ (NSString *)StringFromPropertySelector:(CMIOObjectPropertySelector)selector
......@@ -245,9 +245,9 @@
}
}
+ (ObjectStore *)SharedObjectStore
+ (OBSDALObjectStore *)SharedObjectStore
{
static ObjectStore *sObjectStore = nil;
static OBSDALObjectStore *sObjectStore = nil;
static dispatch_once_t sOnceToken;
dispatch_once(&sOnceToken, ^{
sObjectStore = [[self alloc] init];
......@@ -257,7 +257,7 @@
+ (NSObject<CMIOObject> *)GetObjectWithId:(CMIOObjectID)objectId
{
return [[ObjectStore SharedObjectStore] getObject:objectId];
return [[OBSDALObjectStore SharedObjectStore] getObject:objectId];
}
- (id)init
......
......@@ -20,4 +20,4 @@
#import <CoreMediaIO/CMIOHardwarePlugIn.h>
// The static singleton of the plugin interface
CMIOHardwarePlugInRef PlugInRef();
CMIOHardwarePlugInRef OBSDALPlugInRef();
......@@ -19,13 +19,13 @@
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see <http://www.gnu.org/licenses/>.
#import "PlugInInterface.h"
#import "OBSDALPlugInInterface.h"
#import <CoreFoundation/CFUUID.h>
#import "PlugIn.h"
#import "Device.h"
#import "Stream.h"
#import "OBSDALPlugin.h"
#import "OBSDALDevice.h"
#import "OBSDALStream.h"
#import "Logging.h"
#pragma mark Plug-In Operations
......@@ -68,7 +68,7 @@ HRESULT HardwarePlugIn_QueryInterface(CMIOHardwarePlugInRef self, REFIID uuid,
if (CFEqual(uuidString, hardwarePluginUuid)) {
// Return the interface;
sRefCount += 1;
*interface = PlugInRef();
*interface = OBSDALPlugInRef();
return kCMIOHardwareNoError;
} else {
DLogFunc(@"ERR Queried for some weird UUID %@", uuidString);
......@@ -91,13 +91,14 @@ OSStatus HardwarePlugIn_InitializeWithObjectID(CMIOHardwarePlugInRef self,
OSStatus error = kCMIOHardwareNoError;
PlugIn *plugIn = [PlugIn SharedPlugIn];
OBSDALPlugin *plugIn = [OBSDALPlugin SharedPlugIn];
plugIn.objectId = objectID;
[[ObjectStore SharedObjectStore] setObject:plugIn forObjectId:objectID];
[[OBSDALObjectStore SharedObjectStore] setObject:plugIn
forObjectId:objectID];
Device *device = [[Device alloc] init];
OBSDALDevice *device = [[OBSDALDevice alloc] init];
CMIOObjectID deviceId;
error = CMIOObjectCreate(PlugInRef(), kCMIOObjectSystemObject,
error = CMIOObjectCreate(OBSDALPlugInRef(), kCMIOObjectSystemObject,
kCMIODeviceClassID, &deviceId);
if (error != noErr) {
DLog(@"CMIOObjectCreate Error %d", error);
......@@ -105,24 +106,26 @@ OSStatus HardwarePlugIn_InitializeWithObjectID(CMIOHardwarePlugInRef self,
}
device.objectId = deviceId;
device.pluginId = objectID;
[[ObjectStore SharedObjectStore] setObject:device forObjectId:deviceId];
[[OBSDALObjectStore SharedObjectStore] setObject:device
forObjectId:deviceId];
Stream *stream = [[Stream alloc] init];
OBSDALStream *stream = [[OBSDALStream alloc] init];
CMIOObjectID streamId;
error = CMIOObjectCreate(PlugInRef(), deviceId, kCMIOStreamClassID,
&streamId);
error = CMIOObjectCreate(OBSDALPlugInRef(), deviceId,
kCMIOStreamClassID, &streamId);
if (error != noErr) {
DLog(@"CMIOObjectCreate Error %d", error);
return error;
}
stream.objectId = streamId;
[[ObjectStore SharedObjectStore] setObject:stream forObjectId:streamId];
[[OBSDALObjectStore SharedObjectStore] setObject:stream
forObjectId:streamId];
device.streamId = streamId;
plugIn.stream = stream;
// Tell the system about the Device
error = CMIOObjectsPublishedAndDied(
PlugInRef(), kCMIOObjectSystemObject, 1, &deviceId, 0, 0);
OBSDALPlugInRef(), kCMIOObjectSystemObject, 1, &deviceId, 0, 0);
if (error != kCMIOHardwareNoError) {
DLog(@"CMIOObjectsPublishedAndDied plugin/device Error %d",
error);
......@@ -130,8 +133,8 @@ OSStatus HardwarePlugIn_InitializeWithObjectID(CMIOHardwarePlugInRef self,
}
// Tell the system about the Stream
error = CMIOObjectsPublishedAndDied(PlugInRef(), deviceId, 1, &streamId,
0, 0);
error = CMIOObjectsPublishedAndDied(OBSDALPlugInRef(), deviceId, 1,
&streamId, 0, 0);
if (error != kCMIOHardwareNoError) {
DLog(@"CMIOObjectsPublishedAndDied device/stream Error %d",
error);
......@@ -147,7 +150,7 @@ OSStatus HardwarePlugIn_Teardown(CMIOHardwarePlugInRef self)
OSStatus error = kCMIOHardwareNoError;
PlugIn *plugIn = [PlugIn SharedPlugIn];
OBSDALPlugin *plugIn = [OBSDALPlugin SharedPlugIn];
[plugIn teardown];
return error;
......@@ -167,7 +170,8 @@ HardwarePlugIn_ObjectHasProperty(CMIOHardwarePlugInRef self,
const CMIOObjectPropertyAddress *address)
{
NSObject<CMIOObject> *object = [ObjectStore GetObjectWithId:objectID];
NSObject<CMIOObject> *object =
[OBSDALObjectStore GetObjectWithId:objectID];
if (object == nil) {
DLogFunc(@"ERR nil object");
......@@ -187,7 +191,8 @@ OSStatus HardwarePlugIn_ObjectIsPropertySettable(
const CMIOObjectPropertyAddress *address, Boolean *isSettable)
{
NSObject<CMIOObject> *object = [ObjectStore GetObjectWithId:objectID];
NSObject<CMIOObject> *object =
[OBSDALObjectStore GetObjectWithId:objectID];
if (object == nil) {
DLogFunc(@"ERR nil object");
......@@ -198,7 +203,8 @@ OSStatus HardwarePlugIn_ObjectIsPropertySettable(
DLogFunc(@"%@(%d) %@ self=%p settable=%d",
NSStringFromClass([object class]), objectID,
[ObjectStore StringFromPropertySelector:address->mSelector],
[OBSDALObjectStore
StringFromPropertySelector:address->mSelector],
self, *isSettable);
return kCMIOHardwareNoError;
......@@ -210,7 +216,8 @@ OSStatus HardwarePlugIn_ObjectGetPropertyDataSize(
const void *qualifierData, UInt32 *dataSize)
{
NSObject<CMIOObject> *object = [ObjectStore GetObjectWithId:objectID];
NSObject<CMIOObject> *object =
[OBSDALObjectStore GetObjectWithId:objectID];
if (object == nil) {
DLogFunc(@"ERR nil object");
......@@ -234,7 +241,8 @@ OSStatus HardwarePlugIn_ObjectGetPropertyData(
void *data)
{
NSObject<CMIOObject> *object = [ObjectStore GetObjectWithId:objectID];
NSObject<CMIOObject> *object =
[OBSDALObjectStore GetObjectWithId:objectID];
if (object == nil) {
DLogFunc(@"ERR nil object");
......@@ -266,7 +274,8 @@ OSStatus HardwarePlugIn_ObjectSetPropertyData(
const void *qualifierData, UInt32 dataSize, const void *data)
{
NSObject<CMIOObject> *object = [ObjectStore GetObjectWithId:objectID];
NSObject<CMIOObject> *object =
[OBSDALObjectStore GetObjectWithId:objectID];
if (object == nil) {
DLogFunc(@"ERR nil object");
......@@ -276,7 +285,8 @@ OSStatus HardwarePlugIn_ObjectSetPropertyData(
UInt32 *dataInt = (UInt32 *)data;
DLogFunc(@"%@(%d) %@ self=%p data(int)=%d",
NSStringFromClass([object class]), objectID,
[ObjectStore StringFromPropertySelector:address->mSelector],
[OBSDALObjectStore
StringFromPropertySelector:address->mSelector],
self, *dataInt);
[object setPropertyDataWithAddress:*address
......@@ -295,7 +305,8 @@ OSStatus HardwarePlugIn_StreamCopyBufferQueue(
void *queueAlteredRefCon, CMSimpleQueueRef *queue)
{
Stream *stream = (Stream *)[ObjectStore GetObjectWithId:streamID];
OBSDALStream *stream =
(OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID];
if (stream == nil) {
DLogFunc(@"ERR nil object");
......@@ -318,14 +329,15 @@ OSStatus HardwarePlugIn_DeviceStartStream(CMIOHardwarePlugInRef self,
{
DLogFunc(@"self=%p device=%d stream=%d", self, deviceID, streamID);
Stream *stream = (Stream *)[ObjectStore GetObjectWithId:streamID];
OBSDALStream *stream =
(OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID];
if (stream == nil) {
DLogFunc(@"ERR nil object");
return kCMIOHardwareBadObjectError;
}
[[PlugIn SharedPlugIn] startStream];
[[OBSDALPlugin SharedPlugIn] startStream];
return kCMIOHardwareNoError;
}
......@@ -350,14 +362,15 @@ OSStatus HardwarePlugIn_DeviceStopStream(CMIOHardwarePlugInRef self,
{
DLogFunc(@"self=%p device=%d stream=%d", self, deviceID, streamID);
Stream *stream = (Stream *)[ObjectStore GetObjectWithId:streamID];
OBSDALStream *stream =
(OBSDALStream *)[OBSDALObjectStore GetObjectWithId:streamID];
if (stream == nil) {
DLogFunc(@"ERR nil object");
return kCMIOHardwareBadObjectError;
}
[[PlugIn SharedPlugIn] stopStream];
[[OBSDALPlugin SharedPlugIn] stopStream];
return kCMIOHardwareNoError;
}
......@@ -438,7 +451,7 @@ static CMIOHardwarePlugInInterface sInterface = {
static CMIOHardwarePlugInInterface *sInterfacePtr = &sInterface;
static CMIOHardwarePlugInRef sPlugInRef = &sInterfacePtr;
CMIOHardwarePlugInRef PlugInRef()
CMIOHardwarePlugInRef OBSDALPlugInRef()
{
return sPlugInRef;
}
......@@ -20,9 +20,9 @@
#import <Foundation/Foundation.h>
#import <CoreMediaIO/CMIOHardwarePlugIn.h>
#import "ObjectStore.h"
#import "MachClient.h"
#import "Stream.h"
#import "OBSDALObjectStore.h"
#import "OBSDALMachClient.h"
#import "OBSDALStream.h"
#define kTestCardWidthKey @"obs-mac-virtualcam-test-card-width"
#define kTestCardHeightKey @"obs-mac-virtualcam-test-card-height"
......@@ -30,13 +30,13 @@
NS_ASSUME_NONNULL_BEGIN
@interface PlugIn : NSObject <CMIOObject>
@interface OBSDALPlugin : NSObject <CMIOObject>
@property CMIOObjectID objectId;
@property (readonly) MachClient *machClient;
@property Stream *stream;
@property (readonly) OBSDALMachClient *machClient;
@property OBSDALStream *stream;
+ (PlugIn *)SharedPlugIn;
+ (OBSDALPlugin *)SharedPlugIn;
- (void)initialize;
......
......@@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see <http://www.gnu.org/licenses/>.
#import "PlugIn.h"
#import "OBSDALPlugin.h"
#import <CoreMediaIO/CMIOHardwarePlugin.h>
......@@ -27,9 +27,9 @@ typedef enum {
PlugInStateNotStarted = 0,
PlugInStateWaitingForServer,
PlugInStateReceivingFrames,
} PlugInState;
} OBSDALPlugInState;
@interface PlugIn () <MachClientDelegate> {
@interface OBSDALPlugin () <MachClientDelegate> {
//! Serial queue for all state changes that need to be concerned with thread safety
dispatch_queue_t _stateQueue;
......@@ -39,16 +39,16 @@ typedef enum {
//! Timeout timer when we haven't received frames for 5s
dispatch_source_t _timeoutTimer;
}
@property PlugInState state;
@property MachClient *machClient;
@property OBSDALPlugInState state;
@property OBSDALMachClient *machClient;
@end
@implementation PlugIn
@implementation OBSDALPlugin
+ (PlugIn *)SharedPlugIn
+ (OBSDALPlugin *)SharedPlugIn
{
static PlugIn *sPlugIn = nil;
static OBSDALPlugin *sPlugIn = nil;
static dispatch_once_t sOnceToken;
dispatch_once(&sOnceToken, ^{
sPlugIn = [[self alloc] init];
......@@ -74,7 +74,7 @@ typedef enum {
}
});
_machClient = [[MachClient alloc] init];
_machClient = [[OBSDALMachClient alloc] init];
_machClient.delegate = self;
_machConnectTimer = dispatch_source_create(
......@@ -140,7 +140,7 @@ typedef enum {
return true;
default:
DLog(@"PlugIn unhandled hasPropertyWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
};
......@@ -153,7 +153,7 @@ typedef enum {
return false;
default:
DLog(@"PlugIn unhandled isPropertySettableWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
};
......@@ -168,7 +168,7 @@ typedef enum {
return sizeof(CFStringRef);
default:
DLog(@"PlugIn unhandled getPropertyDataSizeWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return 0;
};
......@@ -189,7 +189,7 @@ typedef enum {
return;
default:
DLog(@"PlugIn unhandled getPropertyDataWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return;
};
......@@ -202,7 +202,7 @@ typedef enum {
data:(nonnull const void *)data
{
DLog(@"PlugIn unhandled setPropertyDataWithAddress for %@",
[ObjectStore StringFromPropertySelector:address.mSelector]);
[OBSDALObjectStore StringFromPropertySelector:address.mSelector]);
}
#pragma mark - MachClientDelegate
......
......@@ -19,7 +19,7 @@
#import <CoreMediaIO/CMIOHardwarePlugin.h>
#import "PlugInInterface.h"
#import "OBSDALPlugInInterface.h"
#import "Logging.h"
#import "Defines.h"
......@@ -32,6 +32,6 @@ void *PlugInMain(CFAllocatorRef allocator, CFUUIDRef requestedTypeUUID)
return 0;
}
return PlugInRef();
return OBSDALPlugInRef();
}
}
......@@ -19,11 +19,11 @@
#import <Foundation/Foundation.h>
#import "ObjectStore.h"
#import "OBSDALObjectStore.h"
NS_ASSUME_NONNULL_BEGIN
@interface Stream : NSObject <CMIOObject>
@interface OBSDALStream : NSObject <CMIOObject>
@property CMIOStreamID objectId;
......
......@@ -17,7 +17,7 @@
// You should have received a copy of the GNU General Public License
// along with obs-mac-virtualcam. If not, see <http://www.gnu.org/licenses/>.
#import "Stream.h"
#import "OBSDALStream.h"
#import <AppKit/AppKit.h>
#import <mach/mach_time.h>
......@@ -25,9 +25,9 @@
#import "Logging.h"
#import "CMSampleBufferUtils.h"
#import "PlugIn.h"
#import "OBSDALPlugin.h"
@interface Stream () {
@interface OBSDALStream () {
CMSimpleQueueRef _queue;
CFTypeRef _clock;
NSImage *_testCardImage;
......@@ -47,7 +47,7 @@
@end
@implementation Stream
@implementation OBSDALStream
#define DEFAULT_FPS 30.0
#define DEFAULT_WIDTH 1280
......@@ -165,8 +165,8 @@
- (NSImage *)testCardImage
{
if (_testCardImage == nil) {
NSString *bundlePath =
[[NSBundle bundleForClass:[Stream class]] bundlePath];
NSString *bundlePath = [[NSBundle
bundleForClass:[OBSDALStream class]] bundlePath];
NSString *placeHolderPath = [bundlePath
stringByAppendingString:
@"/Contents/Resources/placeholder.png"];
......@@ -434,7 +434,7 @@
return sizeof(CFTypeRef);
default:
DLog(@"Stream unhandled getPropertyDataSizeWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return 0;
};
......@@ -510,7 +510,7 @@
break;
default:
DLog(@"Stream unhandled getPropertyDataWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
*dataUsed = 0;
};
......@@ -539,12 +539,12 @@
case kCMIOStreamPropertyInitialPresentationTimeStampForLinkedAndSyncedAudio:
case kCMIOStreamPropertyOutputBuffersNeededForThrottledPlayback:
DLog(@"TODO: %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
default:
DLog(@"Stream unhandled hasPropertyWithAddress for %@",
[ObjectStore
[OBSDALObjectStore
StringFromPropertySelector:address.mSelector]);
return false;
};
......@@ -553,7 +553,7 @@
- (BOOL)isPropertySettableWithAddress:(CMIOObjectPropertyAddress)address
{
DLog(@"Stream unhandled isPropertySettableWithAddress for %@",
[ObjectStore StringFromPropertySelector:address.mSelector]);
[OBSDALObjectStore StringFromPropertySelector:address.mSelector]);
return false;
}
......@@ -564,7 +564,7 @@
data:(nonnull const void *)data
{
DLog(@"Stream unhandled setPropertyDataWithAddress for %@",
[ObjectStore StringFromPropertySelector:address.mSelector]);
[OBSDALObjectStore StringFromPropertySelector:address.mSelector]);
}
@end
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册