Files
real-e-party-iOS/YuMi/Tools/MedalMediaDisplayManager.m
edwinQQQ a35a711be6 chore: Initial clean commit
- Removed YuMi/Library/ (138 MB, not tracked)
- Removed YuMi/Resources/ (23 MB, not tracked)
- Removed old version assets (566 files, not tracked)
- Excluded Pods/, xcuserdata/ and other build artifacts
- Clean repository optimized for company server deployment
2025-10-09 16:19:14 +08:00

328 lines
9.3 KiB
Objective-C
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

//
// MedalMediaDisplayManager.m
// YuMi
//
// 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];
// 优先判断 MP4 URL
if (![NSString isEmpty:mp4Url] && [self isValidMP4URL:mp4Url]) {
[self setMp4Path:mp4Url];
return;
}
// MP4 URL 无效,检查图片 URL
if (![NSString isEmpty:picUrl]) {
if ([self isValidMP4URL:picUrl]) {
// picUrl 实际上是 MP4兼容旧逻辑
[self setMp4Path:picUrl];
return;
} else if ([NSString isValidImageURL:picUrl]) {
// 有效的图片 URL
[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;
}
// MP4 失败,尝试降级到图片
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 {
// MP4 播放完成,循环播放会自动重新开始
}
- (void)viewDidStopPlayMP4:(NSInteger)lastFrameIndex view:(VAPView *)container {
// MP4 播放停止
}
- (void)viewDidFailPlayMP4:(NSError *)error {
NSLog(@"[MedalMediaDisplayManager] MP4 播放失败: %@", error);
[self handleMP4FailureWithFallback];
}
@end