Files
real-e-party-iOS/YuMi/Tools/MedalMediaDisplayManager.m
2025-10-17 14:52:29 +08:00

326 lines
8.8 KiB
Objective-C

// Created by AI on 2025/1/20.
#import "MedalMediaDisplayManager.h"
#import <QGVAPWrapView.h>
#import "XPRoomGiftAnimationParser.h"
#import "NSString+XPExtension.h"
#import "UIImageConstant.h"
@interface MedalMediaDisplayManager () <HWDMP4PlayDelegate>
@property (nonatomic, copy, readwrite, nullable) NSString *currentImagePath;
@property (nonatomic, copy, readwrite, nullable) NSString *currentMP4Path;
@property (nonatomic, strong) XPRoomGiftAnimationParser *mp4Parser;
@property (nonatomic, assign) NSInteger mp4PlaybackTag;
@end
@implementation MedalMediaDisplayManager
#pragma mark - 初始化
- (instancetype)initWithDelegate:(id<MedalMediaDisplayDelegate>)delegate {
self = [super init];
if (self) {
_delegate = delegate;
_isVisible = YES;
_mp4PlaybackTag = 0;
[self setupNotifications];
}
return self;
}
- (void)dealloc {
[self cleanupResources];
[[NSNotificationCenter defaultCenter] removeObserver:self];
NSLog(@"MedalMediaDisplayManager dealloc");
}
#pragma mark - 公共接口
- (void)updateDisplayWithModel:(id)model {
self.currentModel = model;
[self handleMediaDisplayWithModel:model];
}
- (void)willDisplay {
self.isVisible = YES;
[self resumeMP4PlaybackIfNeeded];
}
- (void)didEndDisplaying {
self.isVisible = NO;
[self pauseMP4Playback];
}
- (void)stopMP4Playback {
VAPView *mp4View = [self.delegate getMP4View];
if (mp4View) {
[mp4View stopHWDMP4];
self.mp4PlaybackTag = 0;
}
}
- (void)pauseMP4Playback {
VAPView *mp4View = [self.delegate getMP4View];
if (mp4View && !mp4View.hidden) {
[mp4View pauseHWDMP4];
}
}
- (void)resumeMP4Playback {
[self resumeMP4PlaybackIfNeeded];
}
- (void)cleanupResources {
[self stopMP4Playback];
self.mp4Parser = nil;
self.currentImagePath = nil;
self.currentMP4Path = nil;
self.currentModel = nil;
}
#pragma mark - 核心媒体处理逻辑
- (void)handleMediaDisplayWithModel:(id)model {
if (!model || !self.delegate) {
[self showDefaultPlaceholder];
return;
}
NSString *mp4Url = [self.delegate getMP4UrlFromModel:model];
NSString *picUrl = [self.delegate getPicUrlFromModel:model];
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
[self setMp4Path:mp4Url];
return;
}
if (![NSString isEmpty:picUrl]) {
if ([self isValidMP4URL:picUrl]) {
[self setMp4Path:picUrl];
return;
} else if ([NSString isValidImageURL:picUrl]) {
[self setImagePath:picUrl];
return;
}
}
[self showDefaultPlaceholder];
}
- (void)setImagePath:(NSString *)imagePath {
[self stopMP4Playback];
self.currentImagePath = imagePath;
self.currentMP4Path = nil;
VAPView *mp4View = [self.delegate getMP4View];
NetImageView *imageView = [self.delegate getImageView];
mp4View.hidden = YES;
imageView.hidden = NO;
imageView.imageUrl = imagePath ?: @"";
[self notifyDisplayUpdated:NO success:![NSString isEmpty:imagePath]];
}
- (void)setMp4Path:(NSString *)mp4Path {
if ([NSString isEmpty:mp4Path]) {
[self showDefaultPlaceholder];
return;
}
[self stopMP4Playback];
self.currentMP4Path = mp4Path;
self.currentImagePath = nil;
VAPView *mp4View = [self.delegate getMP4View];
NetImageView *imageView = [self.delegate getImageView];
mp4View.hidden = NO;
imageView.hidden = YES;
if (!self.mp4Parser) {
self.mp4Parser = [[XPRoomGiftAnimationParser alloc] init];
}
@kWeakify(self);
[self.mp4Parser parseWithURL:mp4Path
completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if (![NSString isEmpty:videoUrl]) {
self.mp4PlaybackTag = 1;
if (self.isVisible) {
[self startMP4PlaybackWithURL:videoUrl];
}
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
NSLog(@"[MedalMediaDisplayManager] Failed to parse mp4: %@", error);
[self handleMP4FailureWithFallback];
}];
}
- (void)startMP4PlaybackWithURL:(NSString *)videoUrl {
if ([NSString isEmpty:videoUrl] || !self.delegate) {
return;
}
VAPView *mp4View = [self.delegate getMP4View];
if (mp4View && !mp4View.hidden) {
[mp4View playHWDMP4:videoUrl repeatCount:-1 delegate:self];
[self notifyDisplayUpdated:YES success:YES];
NSLog(@"[MedalMediaDisplayManager] Started MP4 playback: %@", videoUrl);
}
}
- (void)handleMP4FailureWithFallback {
if (!self.delegate || !self.currentModel) {
[self showDefaultPlaceholder];
return;
}
NSString *picUrl = [self.delegate getPicUrlFromModel:self.currentModel];
if (![NSString isEmpty:picUrl] && [NSString isValidImageURL:picUrl]) {
[self setImagePath:picUrl];
} else {
[self showDefaultPlaceholder];
}
}
- (void)showDefaultPlaceholder {
[self stopMP4Playback];
VAPView *mp4View = [self.delegate getMP4View];
NetImageView *imageView = [self.delegate getImageView];
mp4View.hidden = YES;
imageView.hidden = NO;
imageView.imageUrl = @"";
UIImage *placeholderImage = nil;
if ([self.delegate respondsToSelector:@selector(getDefaultPlaceholderImage)]) {
placeholderImage = [self.delegate getDefaultPlaceholderImage];
}
if (!placeholderImage) {
placeholderImage = [UIImageConstant defaultEmptyPlaceholder];
}
imageView.image = placeholderImage;
[self notifyDisplayUpdated:NO success:NO];
}
- (void)resumeMP4PlaybackIfNeeded {
if (!self.isVisible || [NSString isEmpty:self.currentMP4Path]) {
return;
}
VAPView *mp4View = [self.delegate getMP4View];
if (mp4View && !mp4View.hidden) {
if (self.mp4PlaybackTag == 1) {
@kWeakify(self);
[self.mp4Parser parseWithURL:self.currentMP4Path
completionBlock:^(NSString * _Nullable videoUrl) {
@kStrongify(self);
if (![NSString isEmpty:videoUrl] && self.isVisible) {
[self startMP4PlaybackWithURL:videoUrl];
}
} failureBlock:^(NSError * _Nullable error) {
@kStrongify(self);
[self handleMP4FailureWithFallback];
}];
} else {
[mp4View resumeHWDMP4];
}
}
}
#pragma mark - 辅助方法
- (BOOL)isValidMP4URL:(NSString *)url {
if ([NSString isEmpty:url]) {
return NO;
}
NSString *lowercaseUrl = [url lowercaseString];
return [lowercaseUrl hasSuffix:@".mp4"] ||
[lowercaseUrl containsString:@"mp4"] ||
[lowercaseUrl containsString:@"video"];
}
- (void)notifyDisplayUpdated:(BOOL)isMP4 success:(BOOL)success {
if ([self.delegate respondsToSelector:@selector(onMediaDisplayUpdated:success:)]) {
[self.delegate onMediaDisplayUpdated:isMP4 success:success];
}
}
#pragma mark - 通知处理
- (void)setupNotifications {
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAppDidEnterBackground)
name:UIApplicationDidEnterBackgroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleAppWillEnterForeground)
name:UIApplicationWillEnterForegroundNotification
object:nil];
[[NSNotificationCenter defaultCenter] addObserver:self
selector:@selector(handleMemoryWarning)
name:UIApplicationDidReceiveMemoryWarningNotification
object:nil];
}
- (void)handleAppDidEnterBackground {
[self pauseMP4Playback];
}
- (void)handleAppWillEnterForeground {
if (self.isVisible) {
[self resumeMP4PlaybackIfNeeded];
}
}
- (void)handleMemoryWarning {
if (!self.isVisible) {
[self stopMP4Playback];
}
}
#pragma mark - HWDMP4PlayDelegate
- (BOOL)shouldStartPlayMP4:(VAPView *)container config:(QGVAPConfigModel *)config {
return YES;
}
- (void)viewDidFinishPlayMP4:(NSInteger)totalFrameCount view:(VAPView *)container {
}
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
}
- (void)viewDidFailPlayMP4:(NSError *)error {
NSLog(@"[MedalMediaDisplayManager] MP4 播放失败: %@", error);
[self handleMP4FailureWithFallback];
}
@end