
- 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
328 lines
9.3 KiB
Objective-C
328 lines
9.3 KiB
Objective-C
//
|
||
// 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 |