萤石云 iOSSDK,移植跨平台相关工程
Davin
2024-12-18 b4e1288a9b63eb820e9c9489c56aac4bf6b31067
EZSDK/EZSDK/EZ/UIViewControllers/EZPlaybackViewController.m
@@ -10,27 +10,31 @@
#import "UIViewController+EZBackPop.h"
#import "DDCollectionViewFlowLayout.h"
#import "MJRefresh.h"
#import "EZRecordDownloader.h"
#import "EZDeviceRecordDownloadTask.h"
#import "EZCloudRecordDownloadTask.h"
#import <EZOpenSDKFramework/EZRecordDownloader.h>
#import <EZOpenSDKFramework/EZDeviceRecordDownloadTask.h>
#import <EZOpenSDKFramework/EZCloudRecordDownloadTask.h>
#import "EZRecordCell.h"
#import "DDKit.h"
#import "EZCloudRecordFile.h"
#import "EZDeviceRecordFile.h"
#import "EZPlayer.h"
#import <EZOpenSDKFramework/EZCloudRecordFile.h>
#import <EZOpenSDKFramework/EZDeviceRecordFile.h>
#import <EZOpenSDKFramework/EZPlayer.h>
#import "HIKLoadView.h"
#import "Masonry.h"
#import "EZCameraInfo.h"
#import <EZOpenSDKFramework/EZCameraInfo.h>
#import "MBProgressHUD.h"
#import "Toast+UIView.h"
#import "EZCustomTableView.h"
#import "EZStreamPlayer.h"
#import <EZOpenSDKFramework/EZStreamPlayer.h>
#import <Photos/Photos.h>
#import "FCFileManager.h"
#import <EZOpenSDKFramework/EZVideoTransformer.h>
@interface EZPlaybackViewController ()<DDCollectionViewDelegateFlowLayout, UICollectionViewDataSource,EZPlayerDelegate, UIAlertViewDelegate, EZRecordCellDelegate, EZCustomTableViewDelegate,EZStreamPlayerDelegate>
{
    BOOL _isOpenSound;
    BOOL _isPlaying;
    BOOL _landscape;    // 是否旋转
    
    NSTimeInterval _playSeconds; //播放秒数
    NSTimeInterval _duringSeconds; //录像时长
@@ -44,8 +48,8 @@
    NSArray *sdCardRate;
    NSArray *cloudRateStr;
    NSArray *sdCardRateStr;
//    BOOL _isDoBack;
    //    BOOL _isDoBack;
}
@property (nonatomic, strong) NSIndexPath *selectedIndexPath;
@@ -57,6 +61,7 @@
@property (nonatomic, strong) HIKLoadView *loadingView;
@property (nonatomic) BOOL isSelectedDevice;
@property (nonatomic, weak) IBOutlet UIView *playerView;
@property (weak, nonatomic) IBOutlet NSLayoutConstraint *playViewWHScale;
@property (nonatomic, weak) IBOutlet UILabel *largeTitleLabel;
@property (nonatomic, weak) IBOutlet UIDatePicker *datePicker;
@property (nonatomic, weak) IBOutlet UITextField *dateTextField;
@@ -102,12 +107,20 @@
    [EZOPENSDK releasePlayer:_player];
}
- (void)viewWillAppear:(BOOL)animated
{
    [super viewWillAppear:animated];
    self.navigationController.navigationBar.hidden = NO;//2021-02-01
}
- (void)viewDidLoad {
    [super viewDidLoad];
    // Do any additional setup after loading the view.
    self.isAutorotate = YES;
    self.largeTitleLabel.text = self.deviceInfo.deviceName;
    self.largeTitleLabel.hidden = YES;
    _landscape = NO;
    
    if(!_records)
        _records = [NSMutableArray new];
@@ -154,7 +167,7 @@
    
    [self.duringSlider setThumbImage:[UIImage imageNamed:@"slider"] forState:UIControlStateNormal];
    [self.duringSlider setThumbImage:[UIImage imageNamed:@"slider_sel"] forState:UIControlStateHighlighted];
    self.cloudButton.selected = YES;
    self.largeBackButton.hidden = YES;
    
@@ -166,7 +179,7 @@
    [self.dateButton setTitle:[dateFormatter stringFromDate:self.datePicker.date] forState:UIControlStateNormal];
    dateFormatter.dateFormat = @"MM-dd △";
    [self.dateButton setTitle:[dateFormatter stringFromDate:self.datePicker.date] forState:UIControlStateSelected];
    _isShowToolbox = YES;
    
    cloudRate = @[@(EZOPENSDK_PLAY_RATE_1),
@@ -183,6 +196,11 @@
    
    cloudRateStr = @[@"x1",@"x4",@"x8",@"x16",@"x32"];
    sdCardRateStr = @[@"x1",@"x4",@"x8",@"x16"];
    //2021-07-21 隐藏streamPlayBtn和rateBtn
    [self.streamPlayBtn setHidden:YES];
    [self.rateBtn setHidden:YES];
}
- (void)viewWillDisappear:(BOOL)animated {
@@ -204,18 +222,28 @@
}
/*
#pragma mark - Navigation
// In a storyboard-based application, you will often want to do a little preparation before navigation
- (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
    // Get the new view controller using [segue destinationViewController].
    // Pass the selected object to the new view controller.
}
*/
 #pragma mark - Navigation
 // In a storyboard-based application, you will often want to do a little preparation before navigation
 - (void)prepareForSegue:(UIStoryboardSegue *)segue sender:(id)sender {
 // Get the new view controller using [segue destinationViewController].
 // Pass the selected object to the new view controller.
 }
 */
- (UIInterfaceOrientationMask)supportedInterfaceOrientations
{
    return UIInterfaceOrientationMaskAllButUpsideDown;
    if (@available(iOS 16.0, *)) {
        if (_landscape) {
            //横屏
            return UIInterfaceOrientationMaskLandscape;
        } else {
            //竖屏
            return UIInterfaceOrientationMaskPortrait;
        }
    } else {
        return UIInterfaceOrientationMaskAllButUpsideDown;
    }
}
- (void)willRotateToInterfaceOrientation:(UIInterfaceOrientation)toInterfaceOrientation
@@ -230,6 +258,13 @@
    self.largeButton.hidden = NO;
    self.voiceButton.hidden = NO;
    self.playButton.hidden = NO;
    [self.playerView setTranslatesAutoresizingMaskIntoConstraints:NO];
    [NSLayoutConstraint deactivateConstraints:@[self.playViewWHScale]];
    self.playViewWHScale = [NSLayoutConstraint constraintWithItem:self.playerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.playerView attribute:NSLayoutAttributeHeight multiplier:16/9. constant:0];
    [NSLayoutConstraint activateConstraints:@[self.playViewWHScale]];
    dispatch_async(dispatch_get_main_queue(), ^{
        [self.playerView layoutIfNeeded];
    });
    if(toInterfaceOrientation == UIInterfaceOrientationLandscapeLeft ||
       toInterfaceOrientation == UIInterfaceOrientationLandscapeRight)
    {
@@ -242,6 +277,18 @@
        self.playbackList.hidden = YES;
        self.largeBackButton.hidden = NO;
        self.navigationController.navigationBarHidden = YES;
        CGFloat tureScreenW = HDLEZ_APP_SCREEN_WIDTH > HDLEZ_APP_SCREEN_HEIGHT ? HDLEZ_APP_SCREEN_HEIGHT : HDLEZ_APP_SCREEN_WIDTH;
        CGFloat tureScreenH = HDLEZ_APP_SCREEN_WIDTH < HDLEZ_APP_SCREEN_HEIGHT ? HDLEZ_APP_SCREEN_HEIGHT : HDLEZ_APP_SCREEN_WIDTH;
        [self.playerView setTranslatesAutoresizingMaskIntoConstraints:NO];
        [NSLayoutConstraint deactivateConstraints:@[self.playViewWHScale]];
        self.playViewWHScale = [NSLayoutConstraint constraintWithItem:self.playerView attribute:NSLayoutAttributeWidth relatedBy:NSLayoutRelationEqual toItem:self.playerView attribute:NSLayoutAttributeHeight multiplier:tureScreenH/(tureScreenW) constant:0];
        [NSLayoutConstraint activateConstraints:@[self.playViewWHScale]];
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.playerView layoutIfNeeded];
        });
    }
}
@@ -288,6 +335,8 @@
    cell.deviceSerial = _cameraInfo.deviceSerial;
    cell.isSelectedDevice = _isSelectedDevice;
    cell.delegate = self;
    //2021-07-21 隐藏下载按钮
    [cell.downloadBtn setHidden:NO];
    
    if(_isSelectedDevice)
    {
@@ -316,7 +365,7 @@
        
        [self invalidateTimer];
        
//        [_player stopPlayback];
        //        [_player stopPlayback];
        
        if(_isSelectedDevice)
        {
@@ -341,7 +390,7 @@
#pragma mark - ValidateCode Methods
- (void)repeatDelay{
    self.selectedCell = NO;
}
@@ -375,9 +424,16 @@
        
        EZDeviceRecordFile *deviceFile = (EZDeviceRecordFile *)recordFile;
        
        NSString *path = [NSString stringWithFormat:@"%@/ezopensdk/DeviceRecord/%@.ps",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) firstObject], [dateformatter stringFromDate:deviceFile.startTime]];
        NSString *path = [NSString stringWithFormat:@"%@/ezopensdk/DeviceRecord/%@.ps",[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], [dateformatter stringFromDate:deviceFile.startTime]];
        NSLog(@"path: %@ ", path);
        [self startDeviceRecordDownload:path deviceFile:deviceFile];
        __weak __typeof(self)weakSelf = self;
        [self authPhotoLibraries:^(BOOL isAblity) {
            if (isAblity) {
                [weakSelf startDeviceRecordDownload:path deviceFile:deviceFile];
            } else {
                [weakSelf guideUserOpenAuth];
            }
        }];
    }
    else {
        
@@ -399,7 +455,7 @@
                                           verifyCode:self.verifyCode
                                             savePath:path
                                           completion:^(EZDeviceRecordDownloadTask * _Nonnull task) {
        //设置回调函数
        __weak typeof(task) weakTask = task;
        [task setDownloadCallBackWithFinshed:^(EZRecordDownloaderStatus statusCode) {
@@ -408,10 +464,17 @@
            NSLog(@"statuCode:%ld", (long)statusCode);
            
            switch (statusCode) {
                case EZRecordDownloaderStatusFinish:
                    [self.navigationController.view makeToast:[NSString stringWithFormat:@"SDD Task:%lu-下载成功", (unsigned long)strongTask.taskID]];
                case EZRecordDownloaderStatusFinish:{
                    dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                        NSLog(@"#########开始保存视频!!!!%@", path);
                        NSDateFormatter *dateformatter = [[NSDateFormatter alloc] init];
                        dateformatter.dateFormat = @"yyyyMMddHHmmss";
                        NSString *mp4Path = [NSString stringWithFormat:@"%@/ezopensdk/DeviceRecord/%@.mp4", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], [dateformatter stringFromDate:deviceFile.startTime]];
                        [self videoFormatConvertAndSave2Album:path mp4Path:mp4Path];
                    });
                }
                    break;
                case EZRecordDownloaderStatusMoreToken:
                    
@@ -454,6 +517,40 @@
    }];
}
/** 如果需要把回放视频保存到相册,一定要先把.ps文件转成.mp4文件
    注意:下载录像过程中因为网络原因导致.ps文件未下载完,也可以调用此方法将已下载的录像片段解码成.mp4文件。
 */
- (void)videoFormatConvertAndSave2Album:(NSString *)psPath mp4Path:(NSString *)mp4Path {
    [FCFileManager createFileAtPath:mp4Path overwrite:YES];
    __weak typeof(self) weakSelf = self;
    [EZVideoTransformer videoTransFormerPSPath:psPath toPath:mp4Path type:EZVideoTransformerTypeMP4 withKey:_verifyCode succBlock:^{
        NSLog(@"转换成功");
        // 将.mp4文件保存到相册
        PHPhotoLibrary *photoLibrary = [PHPhotoLibrary sharedPhotoLibrary];
        [photoLibrary performChanges:^{
            [PHAssetChangeRequest creationRequestForAssetFromVideoAtFileURL:[NSURL fileURLWithPath:mp4Path]];
        } completionHandler:^(BOOL success, NSError * _Nullable error) {
            if (success) {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.navigationController.view makeToast:HDLEZLocallizedString(@"device_save_gallery")];
                });
                NSLog(@"########保存成功!!!");
                // 下载完成后删除.ps和.mp4文件
                [FCFileManager removeItemAtPath:psPath];
                [FCFileManager removeItemAtPath:mp4Path];
            } else {
                dispatch_async(dispatch_get_main_queue(), ^{
                    [weakSelf.navigationController.view makeToast:HDLEZLocallizedString(@"device_save_gallery_failure")];
                });
            }
        }];
    } processBlock:^(int rate) {
        // 转换进度
    } failBlock:^(int errCode) {
        NSLog(@"转换失败");
    }];
}
- (void) startCloudRecordDownload:(NSString*)path cloudFile:(EZCloudRecordFile *)cloudFile {
    
    EZCloudRecordDownloadTask *task = [[EZCloudRecordDownloadTask alloc] initTaskWithID:_selectedIndexPath.row cloudRecordFile:cloudFile verifyCode:self.verifyCode savePath:path];
@@ -466,9 +563,17 @@
        NSLog(@"statuCode:%ld", (long)statusCode);
        
        switch (statusCode) {
            case EZRecordDownloaderStatusFinish:
                [self.navigationController.view makeToast:[NSString stringWithFormat:@"CD Task:%lu-下载成功", (unsigned long)strongTask.taskID]];
            case EZRecordDownloaderStatusFinish: {
                dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0), ^{
                    NSLog(@"#########开始保存视频!!!!%@", path);
                    NSDateFormatter *dateformatter = [[NSDateFormatter alloc] init];
                    dateformatter.dateFormat = @"yyyyMMddHHmmss";
                    NSString *mp4Path = [NSString stringWithFormat:@"%@/ezopensdk/DeviceRecord/%@.mp4", [NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject], [dateformatter stringFromDate:cloudFile.startTime]];
                    [self videoFormatConvertAndSave2Album:path mp4Path:mp4Path];
                });
            }
                
                break;
            case EZRecordDownloaderStatusMoreToken:
@@ -505,6 +610,69 @@
            [self.navigationController.view makeToast:[NSString stringWithFormat:@"CD Task:%lu-任务已在下载中", (unsigned long)task.taskID]];
        }
    }
}
#pragma mark 视频保存完毕的回调
- (void)video:(NSString *)videoPath didFinishSavingWithError:(NSError *)error contextInfo:(void *)contextInfo{
    dispatch_async(dispatch_get_main_queue(), ^{
        if (error) {
            [self.navigationController.view makeToast:HDLEZLocallizedString(@"device_save_gallery_failure")];
            NSLog(@"保存视频过程中发生错误,错误信息:%@",error.localizedDescription);
            NSLog(@"保存视频过程中发生错误,错误信息:%@",error);
        }else{
            [self.navigationController.view makeToast:HDLEZLocallizedString(@"device_save_gallery")];
            NSLog(@"视频保存成功.");
        }
    });
}
/*访问相册权限
 */
-(void)authPhotoLibraries:(void(^)(BOOL isAblity))result {
    PHAuthorizationStatus author =[PHPhotoLibrary authorizationStatus];
    if (author == PHAuthorizationStatusRestricted || author ==PHAuthorizationStatusDenied){
        if (result) {
            result(NO);
        }
    } else if (author == PHAuthorizationStatusNotDetermined) {  // 首次授权
        dispatch_queue_t queue = dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_DEFAULT, 0);
        dispatch_async(queue, ^{
            [PHPhotoLibrary requestAuthorization:^(PHAuthorizationStatus status) {
                if (status != PHAuthorizationStatusAuthorized) {
                    if (result) {
                        result(NO);
                    }
                } else {
                    if (result) {
                        result(YES);
                    }
                }
            }];
        });
    } else {
        if (result) {
            result(YES);
        }
    }
}
/*引导用户授权获取图片
 */
- (void)guideUserOpenAuth{
    UIAlertController *alertC = [UIAlertController alertControllerWithTitle:NSLocalizedString(@"hdl_ez_download_tip", @"温馨提示") message:NSLocalizedString(@"hdl_ez_download_auth", @"请打开访问权限") preferredStyle:(UIAlertControllerStyleAlert)];
    UIAlertAction *alertA = [UIAlertAction actionWithTitle:NSLocalizedString(@"hdl_ez_download_cancle", @"取消") style:(UIAlertActionStyleDefault) handler:nil];
    UIAlertAction *act = [UIAlertAction actionWithTitle:NSLocalizedString(@"hdl_ez_download_toSet", @"去设置") style:UIAlertActionStyleDefault handler:^(UIAlertAction * _Nonnull action) {
        // 引导用户设置
        NSURL *url = [NSURL URLWithString:UIApplicationOpenSettingsURLString];
        if ([[UIApplication sharedApplication] canOpenURL:url]) {
            [[UIApplication sharedApplication] openURL:url options:@{} completionHandler:nil];
        }
    }];
    [alertC addAction:alertA];
    [alertC addAction:act];
    [self presentViewController:alertC animated:YES completion:nil];
}
#pragma mark - PlayerDelegate Methods
@@ -559,7 +727,7 @@
        
        NSLog(@"GetStreamFetchType:%d", [self.player getStreamFetchType]);
        
        [self showStreamFetchType];
        //        [self showStreamFetchType];
    }
    else if (messageCode == PLAYER_PLAYBACK_STOP)
    {
@@ -578,7 +746,7 @@
}
- (void) invalidateTimer {
    if(self.playbackTimer)
    {
        [self.playbackTimer invalidate];
@@ -604,13 +772,13 @@
- (IBAction)hiddenPlayerToolbox:(id)sender
{
//    [UIView animateWithDuration:0.3
//                     animations:^{
//                         self.playerToolbox.alpha = 0.0f;
//                     }
//                     completion:^(BOOL finished) {
//                         _isShowToolbox = NO;
//                     }];
    //    [UIView animateWithDuration:0.3
    //                     animations:^{
    //                         self.playerToolbox.alpha = 0.0f;
    //                     }
    //                     completion:^(BOOL finished) {
    //                         _isShowToolbox = NO;
    //                     }];
}
#pragma mark - MJRefresh Methods
@@ -620,7 +788,7 @@
    [self.operation cancel];
    [self.playbackList.header endRefreshing];
    __weak __typeof(self) weakSelf = self;
    self.playbackList.header = [MJRefreshNormalHeader headerWithRefreshingBlock:^{
        weakSelf.noVideoImageView.hidden = YES;
        weakSelf.noVideoLabel.hidden = YES;
@@ -630,34 +798,35 @@
                                                             beginTime:weakSelf.beginTime
                                                               endTime:weakSelf.endTime
                                                            completion:^(NSArray *deviceRecords, NSError *error) {
                                                                NSLog(@"deviceRecords is %@, error is %@", deviceRecords, error);
                                                                if (!error)
                                                                {
                                                                    [weakSelf.records removeAllObjects];
                                                                    if(deviceRecords.count == 0)
                                                                    {
                                                                        weakSelf.noVideoLabel.hidden = NO;
                                                                        weakSelf.noVideoImageView.hidden = NO;
                                                                        [weakSelf.playbackList reloadData];
                                                                        [weakSelf.playbackList.header endRefreshing];
                                                                        return;
                                                                    }
                                                                    if (deviceRecords.count > 0)
                                                                    {
                                                                        [weakSelf.records addObjectsFromArray:deviceRecords];
                                                                        [weakSelf.playbackList reloadData];
                                                                        [weakSelf.playbackList.header endRefreshing];
                                                                        [weakSelf doPlayback];
                                                                    }
                                                                }
                                                                else
                                                                {
                                                                    [UIView dd_showMessage:[NSString stringWithFormat:@"error code is %d",(int) error.code] onParentView:self.view];
                                                                    [weakSelf.playbackList.header endRefreshing];
                                                                    [weakSelf.records removeAllObjects];
                                                                    [weakSelf.playbackList reloadData];
                                                                }
                                                            }];
                NSLog(@"deviceRecords is %@, error is %@", deviceRecords, error);
                if (!error)
                {
                    [weakSelf.records removeAllObjects];
                    if(deviceRecords.count == 0)
                    {
                        weakSelf.noVideoLabel.hidden = NO;
                        weakSelf.noVideoImageView.hidden = NO;
                        [weakSelf.playbackList reloadData];
                        [weakSelf.playbackList.header endRefreshing];
                        return;
                    }
                    if (deviceRecords.count > 0)
                    {
                        [weakSelf.records addObjectsFromArray:deviceRecords];
                        [weakSelf.playbackList reloadData];
                        [weakSelf.playbackList.header endRefreshing];
                        [weakSelf doPlayback];
                    }
                }
                else
                {
                    NSString *mes = [NSString stringWithFormat:@"%@(%ld)",NSLocalizedString(@"setting_opration_fail", @"操作失败"), (long)error.code];
                    [UIView dd_showMessage:mes onParentView:self.view];
                    [weakSelf.playbackList.header endRefreshing];
                    [weakSelf.records removeAllObjects];
                    [weakSelf.playbackList reloadData];
                }
            }];
        }
        else
        {
@@ -666,36 +835,38 @@
                                                             beginTime:weakSelf.beginTime
                                                               endTime:weakSelf.endTime
                                                            completion:^(NSArray *cloudRecords, NSError *error) {
                                                                NSLog(@"cloudRecords is %@, error is %@", cloudRecords, error);
                                                                if (error)
                                                                {
                                                                    if (error.code > 0) {
                                                                        [UIView dd_showMessage:[NSString stringWithFormat:@"error code is %d",(int) error.code] onParentView:self.view];
                                                                    }
                                                                    [weakSelf.playbackList.header endRefreshing];
                                                                    [weakSelf.records removeAllObjects];
                                                                    [weakSelf.playbackList reloadData];
                                                                    return ;
                                                                }
                                                                [weakSelf.records removeAllObjects];
                                                                if(cloudRecords.count == 0)
                                                                {
                                                                    weakSelf.noVideoLabel.hidden = NO;
                                                                    weakSelf.noVideoImageView.hidden = NO;
                                                                    [weakSelf.playbackList reloadData];
                                                                    [weakSelf.playbackList.header endRefreshing];
                                                                    return;
                                                                }
                                                                if (cloudRecords.count > 0)
                                                                {
                                                                    [weakSelf.records addObjectsFromArray:cloudRecords];
                                                                    [weakSelf.playbackList reloadData];
                                                                    [weakSelf.playbackList.header endRefreshing];
                                                                    [weakSelf doPlayback];
                                                                }
                                                            }];
                NSLog(@"cloudRecords is %@, error is %@", cloudRecords, error);
                if (error)
                {
                    if (error.code > 0) {
                        NSString *mes = [NSString stringWithFormat:@"%@(%ld)",NSLocalizedString(@"setting_opration_fail", @"操作失败"), (long)error.code];
                        [UIView dd_showMessage:mes onParentView:self.view];
                    }
                    [weakSelf.playbackList.header endRefreshing];
                    [weakSelf.records removeAllObjects];
                    [weakSelf.playbackList reloadData];
                    return ;
                }
                [weakSelf.records removeAllObjects];
                if(cloudRecords.count == 0)
                {
                    weakSelf.noVideoLabel.hidden = NO;
                    weakSelf.noVideoImageView.hidden = NO;
                    [weakSelf.playbackList reloadData];
                    [weakSelf.playbackList.header endRefreshing];
                    return;
                }
                if (cloudRecords.count > 0)
                {
                    [weakSelf.records addObjectsFromArray:cloudRecords];
                    [weakSelf.playbackList reloadData];
                    [weakSelf.playbackList.header endRefreshing];
                    [weakSelf doPlayback];
                }
            }];
        }
    }];
    self.playbackList.header.automaticallyChangeAlpha = YES;
@@ -740,14 +911,60 @@
- (IBAction)large:(id)sender
{
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
//    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
//    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    if (_landscape == YES) {
        [self largeBack:self.largeBackButton];
        return;
    }
    _landscape = YES;
    if (@available(iOS 16.0, *)) {
        if (self.navigationController) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
            });
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self setNeedsUpdateOfSupportedInterfaceOrientations];
            });
        }
        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
        UIWindowScene *ws = (UIWindowScene *)array.firstObject;
        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] init];
        geometryPreferences.interfaceOrientations = UIInterfaceOrientationMaskLandscape;
        [ws requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) {
            NSLog(@"iOS 16 Error: %@",error);
        }];
    } else {
        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationLandscapeLeft];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}
- (IBAction)largeBack:(id)sender
{
    NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
    [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    _landscape = NO;
    if (@available(iOS 16.0, *)) {
        if (self.navigationController) {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self.navigationController setNeedsUpdateOfSupportedInterfaceOrientations];
            });
        } else {
            dispatch_async(dispatch_get_main_queue(), ^{
                [self setNeedsUpdateOfSupportedInterfaceOrientations];
            });
        }
        NSArray *array = [[[UIApplication sharedApplication] connectedScenes] allObjects];
        UIWindowScene *ws = (UIWindowScene *)array.firstObject;
        UIWindowSceneGeometryPreferencesIOS *geometryPreferences = [[UIWindowSceneGeometryPreferencesIOS alloc] init];
        geometryPreferences.interfaceOrientations = UIInterfaceOrientationMaskPortrait;
        [ws requestGeometryUpdateWithPreferences:geometryPreferences errorHandler:^(NSError * _Nonnull error) {
            NSLog(@"iOS 16 Error: %@",error);
        }];
    } else {
        NSNumber *value = [NSNumber numberWithInt:UIInterfaceOrientationPortrait];
        [[UIDevice currentDevice] setValue:value forKey:@"orientation"];
    }
}
- (IBAction)voiceButtonClicked:(id)sender
@@ -777,7 +994,7 @@
        [_player setPlaybackRate:rate mode:0];
    }
    else {
        EZPlaybackRate rate = [cloudRate[indexPath.row] intValue];
        [_player setPlaybackRate:rate mode:0];
    }
@@ -816,7 +1033,7 @@
}
- (IBAction)clickRateBtn:(UIButton *)sender {
    self.rateBtnTimer = [NSTimer scheduledTimerWithTimeInterval:2.5f target:self selector:@selector(hideRateView) userInfo:nil repeats:NO];
    
    if(_isSelectedDevice) {
@@ -888,14 +1105,14 @@
    self.selectedIndexPath = nil;
    [UIView animateWithDuration:0.3
                     animations:^{
                         self.selectedImageViewConstraint.constant = 0;
                         [self.toolView setNeedsUpdateConstraints];
                         [self.toolView layoutIfNeeded];
                     }
        self.selectedImageViewConstraint.constant = 0;
        [self.toolView setNeedsUpdateConstraints];
        [self.toolView layoutIfNeeded];
    }
                     completion:^(BOOL finished) {
                         self.cloudButton.selected = YES;
                         self.deviceButton.selected = NO;
                     }];
        self.cloudButton.selected = YES;
        self.deviceButton.selected = NO;
    }];
    _isSelectedDevice = NO;
    [self.records removeAllObjects];
    [self.playbackList reloadData];
@@ -912,14 +1129,14 @@
    self.selectedIndexPath = nil;
    [UIView animateWithDuration:0.3
                     animations:^{
                         self.selectedImageViewConstraint.constant = self.view.bounds.size.width / 2.0f;
                         [self.toolView setNeedsUpdateConstraints];
                         [self.toolView layoutIfNeeded];
                     }
        self.selectedImageViewConstraint.constant = self.view.bounds.size.width / 2.0f;
        [self.toolView setNeedsUpdateConstraints];
        [self.toolView layoutIfNeeded];
    }
                     completion:^(BOOL finished) {
                         self.cloudButton.selected = NO;
                         self.deviceButton.selected = YES;
                     }];
        self.cloudButton.selected = NO;
        self.deviceButton.selected = YES;
    }];
    _isSelectedDevice = YES;
    [self.records removeAllObjects];
    [self.playbackList reloadData];
@@ -983,7 +1200,7 @@
- (void)playBoxToolRefresh:(NSTimer *)timer
{
    NSDate *currentTime = [_player getOSDTime];
NSLog(@"getOSDTime === %@", currentTime);
    NSLog(@"getOSDTime === %@", currentTime);
    if(_isSelectedDevice)
    {
        _playSeconds = [currentTime timeIntervalSinceDate:_deviceRecord.startTime];
@@ -992,7 +1209,7 @@
    {
        _playSeconds = [currentTime timeIntervalSinceDate:_cloudRecord.startTime];
    }
    if(_playSeconds >= 3600)
    {
        int hour = (int)_playSeconds / 3600;
@@ -1100,19 +1317,19 @@
- (void)streamPlayer:(EZStreamPlayer *)player didReceivedMessage:(EZStreamPlayerMsgType)msgType
{
    dispatch_async(dispatch_get_main_queue(), ^{
        NSString *msg;
        switch (msgType) {
            case EZStreamPlayerMsgTypeRealPlayStart:
                msg = @"开启预览成功";
                break;
             case EZStreamPlayerMsgTypeRealPlayClose:
            case EZStreamPlayerMsgTypeRealPlayClose:
                msg = @"关闭预览成功";
                break;
             case EZStreamPlayerMsgTypePlayBackStart:
            case EZStreamPlayerMsgTypePlayBackStart:
                msg = @"开启设备回放成功";
                break;
             case EZStreamPlayerMsgTypePlayBackClose:
            case EZStreamPlayerMsgTypePlayBackClose:
                msg = @"关闭设备回放成功";
                break;
            default:
@@ -1126,14 +1343,14 @@
{
    if (dataType == EZStreamDataTypeHeader) {
        dispatch_async(dispatch_get_main_queue(), ^{
            [self.navigationController.view makeToast:@"开始写入文件"];
        });
    }
    else if (dataType == EZStreamDataTypeStreamEnd)
    {
        dispatch_async(dispatch_get_main_queue(), ^{
            self.streamPlayBtn.selected = NO;
        });
        
@@ -1143,4 +1360,8 @@
    }
}
- (BOOL)prefersHomeIndicatorAutoHidden {
    return YES;
}
@end