// // QXGiftPlayer.m // QXLive // // Created by 启星 on 2025/5/8. // #import "QXGiftPlayerManager.h" #import "QXEffectSvgaView.h" #import "QXFileManager.h" #import "FMDB.h" static NSString *TABLENAME = @"qxGitfPlayTable"; static NSString *ID = @"id"; static NSString *PLAY_IMAGE = @"play_image"; @interface QXGiftPlayerManager() @property (nonatomic,strong) FMDatabase *fmdb; @property (nonatomic,strong) UIView *bgEffectView; // 礼物、坐骑【全屏位置】特效 @property (nonatomic,strong) QXEffectContentView *fullEffectView; // 坐骑【公屏信息流位置】特效 @property (nonatomic,strong) QXEffectContentView *chatEffectView; @end @implementation QXGiftPlayerManager + (instancetype)shareManager{ static QXGiftPlayerManager *manager; static dispatch_once_t onceToken; dispatch_once(&onceToken, ^{ manager = [[QXGiftPlayerManager alloc] init]; // [manager creatDatabase]; }); return manager; } //获得存放数据库文件的沙盒地址 //- (NSString *)databaseFilePath //{ // NSArray *filePath = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES); // NSString *documentPath = [filePath objectAtIndex:0]; // NSString *dbFilePath = [documentPath stringByAppendingPathComponent:@"qx_gift.db"]; // return dbFilePath; //} // ////创建数据库 //- (void)creatDatabase //{ // _fmdb = [FMDatabase databaseWithPath:[self databaseFilePath]]; // //为数据库设置缓存,提高查询效率 // [_fmdb setShouldCacheStatements:YES]; // [_fmdb open]; // NSString *sqlCreateTable = [NSString stringWithFormat:@"CREATE TABLE IF NOT EXISTS '%@' ('%@' INTEGER PRIMARY KEY AUTOINCREMENT, '%@' TEXT)",TABLENAME,ID,PLAY_IMAGE]; // BOOL res = [_fmdb executeUpdate:sqlCreateTable]; // NSLog(@"%@",res?@"数据库创建成功":@"数据库创建失败"); // [_fmdb close]; //} // //-(void)insertGiftWithPlayImage:(NSString*)giftImage{ // if ([_fmdb open]) { // NSString *insertSql1= [NSString stringWithFormat: // @"INSERT INTO '%@' ('%@') VALUES ('%@');", // TABLENAME, PLAY_IMAGE, giftImage]; // BOOL res = [_fmdb executeUpdate:insertSql1]; // NSLog(@"%@",res?@"礼物添加成功":@"礼物添加失败"); // [_fmdb close]; // } //} //- (BOOL)deleteRecordWithId:(NSInteger)recordId { // if ([_fmdb open]) { // NSString *deleteSQL = [NSString stringWithFormat: // @"DELETE FROM %@ WHERE id = ('%ld');", // TABLENAME, recordId]; // BOOL success = [_fmdb executeUpdate:deleteSQL]; // if (!success) { // NSLog(@"删除失败: %@", [_fmdb lastErrorMessage]); // }else{ // NSLog(@"删除成功"); // } // [_fmdb close]; // return success; // } // return NO; //} // //-(BOOL)deleFirstImage{ // if ([_fmdb open]) { // NSString *querySQL= [NSString stringWithFormat: // @"SELECT id FROM '%@' ORDER BY id ASC LIMIT 1", // TABLENAME]; // FMResultSet *resultSet = [_fmdb executeQuery:querySQL]; // [_fmdb close]; // if ([resultSet next]) { // NSInteger recordId = [resultSet intForColumn:@"id"]; // return [self deleteRecordWithId:recordId]; // } // } // return NO; //} // //-(NSString*)readFirstImage{ // if ([_fmdb open]) { // NSString *querySQL= [NSString stringWithFormat: // @"SELECT id FROM '%@' ORDER BY id ASC LIMIT 1", // TABLENAME]; // FMResultSet *resultSet = [_fmdb executeQuery:querySQL]; // [_fmdb close]; // if ([resultSet next]) { // NSString *playImage = [resultSet stringForColumn:PLAY_IMAGE]; // return playImage; // } // } // return nil; //} - (UIView *)defaultBgEffectView { return self.bgEffectView; } /// 礼物、坐骑【全屏位置】特效 - (QXEffectContentView *)defaultFullEffectView { return self.fullEffectView; } /// 坐骑【公屏信息流位置】特效 - (QXEffectContentView *)defaultChatEffectView { return self.chatEffectView; } - (void)displayFullEffectView:(NSString *)gift { // [self insertGiftWithPlayImage:gift]; [self.fullEffectView displayEffectView:gift]; } - (void)displayFullEffectViewWithMorePlayImages:(NSArray *)playImages{ [self.fullEffectView displayEffectViewWithMorePlayImages:playImages]; } - (void)displayChatEffectView:(NSString *)gift { [self.chatEffectView displayEffectView:gift]; } /// 关闭打开动效 - (void)openOrCloseEffectViewWith:(BOOL)isShow { [self.fullEffectView openOrCloseEffectViewWith:isShow]; [self.chatEffectView openOrCloseEffectViewWith:isShow]; } /// 销毁 - (void)destroyEffectSvga { [self.fullEffectView destroyEffectView]; [self.chatEffectView destroyEffectView]; [self.fullEffectView removeFromSuperview]; [self.chatEffectView removeFromSuperview]; [self.bgEffectView removeFromSuperview]; _fullEffectView = nil; _chatEffectView = nil; _bgEffectView = nil; } -(void)stopPlay{ [self.fullEffectView stopPlay]; [self.chatEffectView stopPlay]; } -(void)startPlay{ [self.fullEffectView startPlay]; [self.chatEffectView startPlay]; } - (UIView *)bgEffectView { if (!_bgEffectView) { _bgEffectView = [[UIView alloc] init]; _bgEffectView.userInteractionEnabled = NO; [_bgEffectView addSubview:self.fullEffectView]; [_bgEffectView addSubview:self.chatEffectView]; } return _bgEffectView; } - (QXEffectContentView *)fullEffectView { if (!_fullEffectView) { _fullEffectView = [[QXEffectContentView alloc] initWithFrame:CGRectZero]; _fullEffectView.queue = dispatch_queue_create("qx_room_full_svga_message.com", NULL); } return _fullEffectView; } - (QXEffectContentView *)chatEffectView { if (!_chatEffectView) { _chatEffectView = [[QXEffectContentView alloc] initWithFrame:CGRectZero]; [_chatEffectView.playerMp4View mas_remakeConstraints:^(MASConstraintMaker *make) { // make.centerX.centerY.equalTo(_chatEffectView); // make.width.mas_equalTo(ScaleWidth(375)); // make.height.mas_equalTo(ScaleWidth(375)); make.edges.equalTo(_chatEffectView); }]; _chatEffectView.queue = dispatch_queue_create("qx_room_chat_svga_message.com", NULL); } return _chatEffectView; } @end @interface QXEffectContentView () @property (nonatomic,strong) QXEffectSvgaView *svagView; @property (nonatomic,strong) QXGiftModel *playModel; @property (nonatomic, assign) BOOL isLoadEffect; ///< 是否正在加载 @property (nonatomic, strong) NSRecursiveLock *lock; @property (nonatomic, strong) NSMutableArray *giftArray; @end @implementation QXEffectContentView - (instancetype)initWithFrame:(CGRect)frame { self = [super initWithFrame:frame]; if (self) { self.userInteractionEnabled = NO; self.isLoadEffect = NO; [self addSubview:self.svagView]; [self addSubview:self.playerMp4View]; [self.svagView mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; [self.playerMp4View mas_makeConstraints:^(MASConstraintMaker *make) { make.edges.equalTo(self); }]; } return self; } /// 礼物特效进来 gift为礼物实体类 - (void)displayEffectView:(NSString *)play_image { dispatch_async(self.queue, ^{ /// 如果play_image不存在return if (![play_image isExist]) { return; } /// 将play_image链接转为小写 NSString *pathExtension = [play_image pathExtension].lowercaseString; /// 判定礼物的后缀是否为svga或者mp4如果非这两种 则return if (!([pathExtension isEqualToString:@"svga"] || [pathExtension isEqualToString:@"mp4"])) { return; } /// 锁住list [self.lock lock]; /// 添加礼物进list [self.giftArray addObject:play_image]; NSLog(@"当前礼物有---%ld个",self.giftArray.count); /// 解锁 [self.lock unlock]; /// 如果没有在加载则开始加载 if (self.isLoadEffect == NO) { /// 更改加载状态标记 self.isLoadEffect = YES; [self loadStartSVGAPlayer]; } }); } /// 礼物特效进来 gift为礼物实体类 - (void)displayEffectViewWithMorePlayImages:(NSArray *)playImages { dispatch_async(self.queue, ^{ /// 如果play_image不存在return if (playImages.count == 0) { return; } /// 锁住list [self.lock lock]; /// 添加礼物进list [self.giftArray addObjectsFromArray:playImages]; NSLog(@"当前礼物有---%ld个",self.giftArray.count); /// 解锁 [self.lock unlock]; /// 如果没有在加载则开始加载 if (self.isLoadEffect == NO) { /// 更改加载状态标记 self.isLoadEffect = YES; [self loadStartSVGAPlayer]; } }); } -(void)previewEffectWith:(NSString *)play_image{ self.isOnece = YES; dispatch_async(dispatch_get_main_queue(), ^{ if ([play_image hasSuffix:@"mp4"]) { __weak typeof(self)weakSelf = self; /// mp4格式下载播放 [[QXRequset shareInstance] downloadVideoPlayerWithUrl:play_image completion:^(BOOL result, NSString * _Nonnull fileName) { NSString *videoPath = [QXFileManager getGiftVideoPath:fileName]; dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.playerMp4View.hidden = NO; weakSelf.svagView.hidden = YES; }); [weakSelf.playerMp4View stopHWDMP4]; [weakSelf.playerMp4View playHWDMP4:videoPath delegate:self]; }]; }else if ([play_image hasSuffix:@"svg"] || [play_image hasSuffix:@"svga"]) { __weak typeof(self)weakSelf = self; /// svga下载播放 [[QXRequset shareInstance] downloadVideoPlayerWithUrl:play_image completion:^(BOOL result, NSString * _Nonnull fileName) { dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.playerMp4View.hidden = YES; weakSelf.svagView.hidden = NO; }); NSString *filePath = [QXFileManager getGiftVideoPath:fileName]; [weakSelf.svagView loadSVGAPlayerWith:filePath]; }]; } }); } - (void)openOrCloseEffectViewWith:(BOOL)isShow { _isShow = isShow; [self removeSvgaQueueData]; [self.svagView stopEffectSvgaPlay]; // [self.playerView stop]; [self.playerMp4View stopHWDMP4]; // [self.alphaVideoView stop]; self.playerMp4View.hidden = YES; [self setHidden:!isShow]; } -(void)stopPlay{ // [self removeSvgaQueueData]; self.isLoadEffect = NO; [self.svagView stopEffectSvgaPlay]; // [self.playerView stop]; [self.playerMp4View stopHWDMP4]; // [self.alphaVideoView stop]; self.playerMp4View.hidden = YES; self.svagView.hidden = YES; } -(void)startPlay{ [self loadStartSVGAPlayer]; } -(void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container{ dispatch_async(dispatch_get_main_queue(), ^{ self.playerMp4View.hidden = YES; }); if (self.isOnece) { return; } dispatch_async(dispatch_get_main_queue(), ^{ [self loadStartSVGAPlayer]; }); } -(void)viewDidFailPlayMP4:(NSError *)error{ dispatch_async(dispatch_get_main_queue(), ^{ self.playerMp4View.hidden = YES; }); if (self.isOnece) { return; } dispatch_async(dispatch_get_main_queue(), ^{ [self loadStartSVGAPlayer]; }); } - (void)loadStartSVGAPlayer { if (!_isShow) { /// isshow 为是否开启特效 如果未开启则return return; } NSString *play_image = nil; /// list加锁 [self.lock lock]; /// 如果list长度大于0 if (self.giftArray.count > 0) { /// gift的实体类则赋值,取list中的第一个数据 play_image = self.giftArray.firstObject; /// 移除list的第一条数据 [self.giftArray removeObjectAtIndex:0]; self.isLoadEffect = YES; }else { self.isLoadEffect = NO; } /// 解锁 [self.lock unlock]; if (self.isLoadEffect && [play_image isExist]) { dispatch_async(dispatch_get_main_queue(), ^{ if ([play_image hasSuffix:@"mp4"]) { __weak typeof(self)weakSelf = self; /// mp4格式下载播放 [[QXRequset shareInstance] downloadVideoPlayerWithUrl:play_image completion:^(BOOL result, NSString * _Nonnull fileName) { NSString *videoPath = [QXFileManager getGiftVideoPath:fileName]; dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.playerMp4View.hidden = NO; weakSelf.svagView.hidden = YES; }); [weakSelf.playerMp4View stopHWDMP4]; [weakSelf.playerMp4View playHWDMP4:videoPath delegate:self]; }]; }else if ([play_image hasSuffix:@"svg"] || [play_image hasSuffix:@"svga"]) { __weak typeof(self)weakSelf = self; /// svga下载播放 [[QXRequset shareInstance] downloadVideoPlayerWithUrl:play_image completion:^(BOOL result, NSString * _Nonnull fileName) { dispatch_async(dispatch_get_main_queue(), ^{ weakSelf.playerMp4View.hidden = YES; weakSelf.svagView.hidden = NO; }); NSString *filePath = [QXFileManager getGiftVideoPath:fileName]; [weakSelf.svagView loadSVGAPlayerWith:filePath]; }]; }else { [self.lock lock]; self.isLoadEffect = NO; [self.lock unlock]; [self loadStartSVGAPlayer]; } }); } } - (void)loadEndSvgaPlayer { dispatch_async(self.queue, ^{ [self loadStartSVGAPlayer]; }); } - (void)destroyEffectView { [self removeSvgaQueueData]; [self.svagView destroySvga]; // [self.playerView destroyPlayer]; [self.playerMp4View stopHWDMP4]; [self.svagView removeFromSuperview]; [self.playerMp4View removeFromSuperview]; _svagView = nil; // _playerView = nil; _playModel = nil; _playerMp4View = nil; // _alphaVideoView = nil; } - (void)removeSvgaQueueData { [self.lock lock]; [self.giftArray removeAllObjects]; self.isLoadEffect = NO; [self.lock unlock]; } -(NSMutableArray *)giftArray{ if (!_giftArray) { _giftArray = [NSMutableArray array]; } return _giftArray; } - (QXEffectSvgaView *)svagView { if (!_svagView) { _svagView = [[QXEffectSvgaView alloc] initWithFrame:CGRectZero isAutoPlay:YES]; __weak typeof(self)weakSelf = self; _svagView.didFinishedDisplay = ^(QXEffectSvgaView * _Nonnull svgaView) { [svgaView destroySvga]; if (weakSelf.isOnece) { return; } [weakSelf loadEndSvgaPlayer]; }; } return _svagView; } -(VAPView *)playerMp4View{ if (!_playerMp4View) { _playerMp4View = [[VAPView alloc] initWithFrame:CGRectZero]; _playerMp4View.hwd_enterBackgroundOP = HWDMP4EBOperationTypeStop; _playerMp4View.contentMode = UIViewContentModeScaleAspectFit; _playerMp4View.userInteractionEnabled = NO; _playerMp4View.backgroundColor = [UIColor clearColor]; // _playerMp4View.hwd_Delegate = self; } return _playerMp4View; } @end