// // LocalRecordViewController.m // lechangeDemo // // Created by mac318340418 on 16/7/11. // Copyright © 2016年 dh-Test. All rights reserved. // #import "LCOpenSDK_Prefix.h" #import "DownloadPicture.h" #import "RecordPlayViewController.h" #import "RecordViewController.h" #import "RestApiService.h" #import "LocalPlayViewController.h" #import "PHAsset+Lechange.h" #define RECORD_NUM_MAX 10 @interface RecordViewController () { LCOpenSDK_Utils* m_util; LCOpenSDK_Download* m_download; NSString* m_downloadPath; int64_t m_totalDataSize[RECORD_NUM_MAX]; int64_t m_receiveDataSize[RECORD_NUM_MAX]; BOOL m_isCloudDownload[RECORD_NUM_MAX]; NSInteger m_index; /**Ch:正在下载的index,用于限制下载数目为1 En:The index being downloaded, used to limit the number of downloads to 1.*/ CGFloat m_cellWidth; CGFloat m_cellHeight; CGFloat m_separatorHeight; NSMutableArray* m_recInfo; DownloadPicture* m_downloadPicture[RECORD_NUM_MAX]; NSString* m_dateSelected; NSLock* m_listViewLock; UITableView* m_listView; BOOL m_isStarting; NSLock* m_recInfoLock; NSLock* m_downStatusLock; BOOL m_looping; NSInteger m_iPos; NSInteger m_downloadingPos; NSURL* m_httpUrl; NSMutableURLRequest* m_req; NSURLConnection* m_conn; NSInteger m_interval; NSTimer* m_timer; NSMutableSet* m_downloadSet; UIButton* m_right; } @end @implementation RecordViewController - (void)viewDidLoad { [super viewDidLoad]; [self initWindow]; [self initDatePicker]; UINavigationItem* item; if (m_recordType == DeviceRecord) { item = [[UINavigationItem alloc] initWithTitle:NSLocalizedString(LOCAL_RECORD_TITLE_TXT, nil)]; } else if (m_recordType == CloudRecord) { item = [[UINavigationItem alloc] initWithTitle:NSLocalizedString(NET_RECORD_TITLE_TXT, nil)]; } UIButton* left = [UIButton buttonWithType:UIButtonTypeCustom]; [left setFrame:CGRectMake(0, 0, 50, 30)]; [left setBackgroundImage:[UIImage leChangeImageNamed:Back_Btn_Png] forState:UIControlStateNormal]; [left addTarget:self action:@selector(onBack) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem* leftBtn = [[UIBarButtonItem alloc] initWithCustomView:left]; [item setLeftBarButtonItem:leftBtn animated:NO]; m_right = [UIButton buttonWithType:UIButtonTypeCustom]; [m_right setFrame:CGRectMake([UIScreen mainScreen].bounds.size.width - 5 - 40, 0, 50, 30)]; [m_right setBackgroundImage:[UIImage leChangeImageNamed:Search_Icon_Png] forState:UIControlStateNormal]; [m_right addTarget:self action:@selector(onSearch) forControlEvents:UIControlEventTouchUpInside]; UIBarButtonItem* rightBtn = [[UIBarButtonItem alloc] initWithCustomView:m_right]; [item setRightBarButtonItem:rightBtn animated:NO]; [super.m_navigationBar pushNavigationItem:item animated:NO]; [self.view addSubview:super.m_navigationBar]; [self.m_dateCancelBtn setTitle:NSLocalizedString(DATE_CANCEL_TXT, nil) forState:UIControlStateNormal]; [self.m_dateSelectBtn setTitle:NSLocalizedString(DATE_QUERY_TXT, nil) forState:UIControlStateNormal]; [self.m_dateLab setText:NSLocalizedString(DATE_TIP_TXT, nil)]; m_listView = [[UITableView alloc] initWithFrame:CGRectMake(0, super.m_yOffset, self.view.frame.size.width, self.view.frame.size.height - super.m_yOffset)]; m_listView.delegate = (id)self; m_listView.dataSource = (id)self; m_listView.backgroundColor = [UIColor clearColor]; m_listView.separatorColor = [UIColor clearColor]; m_listView.allowsSelection = YES; [self.view addSubview:m_listView]; m_progressInd = [[UIActivityIndicatorView alloc] initWithActivityIndicatorStyle:UIActivityIndicatorViewStyleGray]; m_progressInd.transform = CGAffineTransformMakeScale(2.0, 2.0); m_progressInd.center = CGPointMake(self.view.center.x, self.view.center.y); [self.view addSubview:m_progressInd]; m_toastLab = [[UILabel alloc] initWithFrame:CGRectMake(0, 0, 300, 50)]; m_toastLab.center = self.view.center; m_toastLab.backgroundColor = [UIColor whiteColor]; m_toastLab.textAlignment = NSTextAlignmentCenter; m_toastLab.hidden = YES; [self.view addSubview:m_toastLab]; m_recInfo = [[NSMutableArray alloc] init]; m_util = [[LCOpenSDK_Utils alloc] init]; [self.view bringSubviewToFront:self.m_viewDateBar]; [self.view bringSubviewToFront:m_toastLab]; [self.view bringSubviewToFront:m_progressInd]; [self.m_ImgRecordNull setImage:[UIImage leChangeImageNamed:Video_None_Png]]; for (int i = 0; i < RECORD_NUM_MAX; i++) { m_downloadPicture[i] = [[DownloadPicture alloc] init]; } m_index = -1; m_iPos = 0; m_downloadingPos = -1; m_listViewLock = [[NSLock alloc] init]; m_downStatusLock = [[NSLock alloc] init]; m_recInfoLock = [[NSLock alloc] init]; m_looping = YES; m_conn = nil; m_downloadSet = [[NSMutableSet alloc] init]; m_timer = [NSTimer scheduledTimerWithTimeInterval:1 target:self selector:@selector(onSmsTimer:) userInfo:nil repeats:YES]; m_download = [LCOpenSDK_Download shareMyInstance]; [m_download setListener:(id)self]; [self getRecords]; dispatch_queue_t downQueue = dispatch_queue_create("cloudThumbnailDown", nil); dispatch_async(downQueue, ^{ [self downloadThread]; }); } - (void)didReceiveMemoryWarning { [super didReceiveMemoryWarning]; } - (void)setInfo:(NSString*)token playToken:(NSString *)playToken Dev:(NSString*)deviceId Key:(NSString*)key Chn:(NSInteger)chn Type:(RecordType)type accessType:(NSString*)accessType; { m_accessToken = [token mutableCopy]; m_strDevSelected = [deviceId mutableCopy]; m_encryptKey = [key mutableCopy]; m_devChnSelected = chn; m_recordType = type; m_playToken = [playToken copy]; m_accessType = [accessType copy]; } - (NSString*)timeTransformFormatter:(NSString*)time { NSString* regex = @"[1-9]\\d{3}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"; NSPredicate* pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; if (![pred evaluateWithObject:time]) { NSLog(@"Time format error:%@", time); return nil; } NSDateFormatter* formatter = [[NSDateFormatter alloc] init]; [formatter setDateFormat:@"yyyy-MM-dd HH:mm:ss"]; NSDate* date = [formatter dateFromString:time]; [formatter setDateFormat:@"yyyy/MM/dd HH:mm:ss"]; NSString* retTime = [formatter stringFromDate:date]; return [retTime substringFromIndex:2]; } - (NSInteger)numberOfSectionsInTableView:(UITableView*)tableView { return 1; } - (NSInteger)tableView:(UITableView*)tableView numberOfRowsInSection:(NSInteger)section { self.m_ImgRecordNull.hidden = (0 == m_recInfo.count && m_isStarting) ? NO : YES; NSInteger iCount = 0; [m_recInfoLock lock]; iCount = m_recInfo.count; [m_recInfoLock unlock]; return iCount; } - (CGFloat)tableView:(UITableView*)tableView heightForRowAtIndexPath:(NSIndexPath*)indexPath { return m_cellHeight; } - (UITableViewCell*)tableView:(UITableView*)tableView cellForRowAtIndexPath:(NSIndexPath*)indexPath { static NSString* cellIdentifier = @"Cell"; UITableViewCell* cell = [[UITableViewCell alloc] initWithStyle:UITableViewCellStyleDefault reuseIdentifier:cellIdentifier]; [m_recInfoLock lock]; if ([indexPath row] >= m_recInfo.count) { NSLog(@"RecordViewController cellForRowAtIndexPath not valid,row[%ld],count[%lu]", (long)[indexPath row], (unsigned long)m_recInfo.count); [m_recInfoLock unlock]; return cell; } NSString* beginTime = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->beginTime; NSString* endTime = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->endTime; [m_recInfoLock unlock]; UIImage* imgPic = nil; if (nil != m_downloadPicture[[indexPath row]].picData) { imgPic = [UIImage imageWithData:m_downloadPicture[[indexPath row]].picData]; NSLog(@"cell[%ld] decrypt imgPic %@", (long)[indexPath row], (imgPic ? @"successfully" : @"failed")); if (!imgPic) { imgPic = [UIImage leChangeImageNamed:DefaultCover_Png]; } } else { imgPic = [UIImage leChangeImageNamed:DefaultCover_Png]; NSLog(@"cell[%ld] default imgPic", (long)[indexPath row]); } UIImageView* imgPicView = [[UIImageView alloc] initWithFrame:CGRectMake(0, 0, (m_cellHeight)*16.0 / 9, m_cellHeight)]; [imgPicView setImage:imgPic]; [cell addSubview:imgPicView]; UIImageView* mImgBar = [[UIImageView alloc] initWithImage: [UIImage leChangeImageNamed:Toast_Png]]; mImgBar.frame = CGRectMake(-50, m_cellHeight - m_separatorHeight - 30, m_cellWidth + 100, 30); [mImgBar setContentMode:UIViewContentModeScaleAspectFill]; mImgBar.clipsToBounds = YES; [cell addSubview:mImgBar]; UILabel* dateLab = [[UILabel alloc] initWithFrame:CGRectMake(10, m_cellHeight - m_separatorHeight - 30, m_cellWidth - 10 - 2 * 30, 30)]; dateLab.text = [NSString stringWithFormat:@"%@—%@", [self timeTransformFormatter:beginTime], [self timeTransformFormatter:endTime]]; dateLab.backgroundColor = [UIColor clearColor]; dateLab.textColor = [UIColor whiteColor]; [dateLab setFont:[UIFont systemFontOfSize:13.0f]]; [cell addSubview:dateLab]; UIView* additionalSeparator = [[UIView alloc] initWithFrame:CGRectMake(0, m_cellHeight - m_separatorHeight, m_cellWidth, m_separatorHeight)]; additionalSeparator.backgroundColor = [UIColor whiteColor]; [cell addSubview:additionalSeparator]; if (m_totalDataSize[[indexPath row]] != 0) { double rate = 1.0 * m_receiveDataSize[[indexPath row]] / m_totalDataSize[[indexPath row]]; rate = rate > 1.0 ? 1.0 : rate; UILabel* label = [[UILabel alloc] initWithFrame:CGRectMake(m_cellWidth - 60, m_cellHeight - m_separatorHeight - 30 + 2.5, rate * 2 * (30 - 5), 30 - 5)]; label.backgroundColor = [UIColor greenColor]; [cell addSubview:label]; } UIButton* downloadBtn = [[UIButton alloc] initWithFrame:CGRectMake(m_cellWidth - 60, m_cellHeight - m_separatorHeight - 30 + 2.5, 2 * (30 - 5), 30 - 5)]; if (m_isCloudDownload[[indexPath row]]) { [downloadBtn setBackgroundImage:[UIImage leChangeImageNamed:Video_Download_Cancel_Png] forState:UIControlStateNormal]; } else { [downloadBtn setBackgroundImage:[UIImage leChangeImageNamed:Video_Download_Png] forState:UIControlStateNormal]; } downloadBtn.tag = [indexPath row]; [downloadBtn addTarget:self action:@selector(onDownload:) forControlEvents:UIControlEventTouchUpInside]; [cell addSubview:downloadBtn]; [cell bringSubviewToFront:downloadBtn]; return cell; } - (void)tableView:(UITableView*)tableView didSelectRowAtIndexPath:(NSIndexPath*)indexPath { [m_recInfoLock lock]; if ([indexPath row] >= m_recInfo.count) { NSLog(@"tableView indexPath[%ld],m_recInfo[%lu]", (long)[indexPath row], (unsigned long)m_recInfo.count); [m_recInfoLock unlock]; return; } if (m_recordType == DeviceRecord) { m_strRecSelected = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->name; } else if (m_recordType == CloudRecord) { /** Ch:处于下载状态,不允许播放云录像 En:It is in the downloading state, and cloud recording is not allowed. */ if (-1 != m_index) { [m_recInfoLock unlock]; [self showDownloadToast:DOWNLOADING]; return; } m_strRecSelected = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->recId; } m_strRecRegSelected = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->recRegId; m_beginTimeSelected = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->beginTime; m_endTimeSelected = ((RecordInfo*)[m_recInfo objectAtIndex:[indexPath row]])->endTime; m_imgPicSelected = [UIImage imageWithData:m_downloadPicture[[indexPath row]].picData]; [m_recInfoLock unlock]; UIStoryboard* currentBoard = [UIStoryboard storyboardWithName:@"Main" bundle:nil]; RecordPlayViewController* recordPlayView = [currentBoard instantiateViewControllerWithIdentifier:@"RecordPlay"]; [recordPlayView setInfo:m_accessToken PlayToken:m_playToken Dev:m_strDevSelected Key:m_encryptKey Chn:m_devChnSelected Type:m_recordType accessType:m_accessType]; [recordPlayView setRecInfo:m_strRecSelected RecReg:m_strRecRegSelected Begin:m_beginTimeSelected End:m_endTimeSelected Img:m_imgPicSelected]; [self.navigationController pushViewController:recordPlayView animated:NO]; } - (void)initWindow { m_separatorHeight = 5; m_cellWidth = [UIScreen mainScreen].bounds.size.width; m_cellHeight = m_cellWidth * 9 / 16 + m_separatorHeight; self.m_viewDateBar.hidden = YES; m_isStarting = NO; } - (void)initDatePicker { self.m_datePicker.locale = [NSLocale localeWithLocaleIdentifier:NSLocalizedString(LANGUAGE_TXT, nil)]; self.m_datePicker.datePickerMode = UIDatePickerModeDate; [self.m_datePicker addTarget:self action:@selector(valueChange:) forControlEvents:UIControlEventValueChanged]; } - (void)valueChange:(UIDatePicker*)datePicker { NSDateFormatter* fmt = [[NSDateFormatter alloc] init]; fmt.dateFormat = @"yyyy-MM-dd"; NSString* dateStr = [fmt stringFromDate:datePicker.date]; m_dateSelected = dateStr; } - (void)cancelBtn:(id)sender { self.m_viewDateBar.hidden = YES; } - (void)inquireBtn:(id)sender { for (NSString* obj in m_downloadSet) { NSInteger index = [obj intValue]; [m_download stopDownload:index]; m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; m_index = -1; } [m_downStatusLock lock]; for (int i = 0; i < RECORD_NUM_MAX; i++) { [m_downloadPicture[i] clearData]; } m_iPos = 0; m_downloadingPos = -1; m_conn = nil; [m_downStatusLock unlock]; self.m_viewDateBar.hidden = YES; [m_listViewLock lock]; m_listView.hidden = YES; self.m_ImgRecordNull.hidden = YES; [m_listViewLock unlock]; [self getRecords]; } - (void)onSearch { self.m_viewDateBar.hidden = NO; } - (void)onDownload:(UIButton*)sender { NSLog(@"RecordPlayViewController onDownload"); /** * 管理标志符(En:Management identifier) * m_index == -1, 下载任务未开始(En:Download task did not start) * m_index != -1, 下载任务已开启,不再开启下载任务(En:Download task has been opened, download task is no longer open) */ if (m_index != -1 && m_index != sender.tag) { [self showDownloadToast:DOWNLOADING]; return; } m_index = sender.tag; if (m_index < 0) { NSLog(@"RecordPlayViewController onDownload[%ld] Wrong!", (long)m_index); m_index = -1; return; } /** Ch:取消下载任务 En:Cancel download task */ if (m_isCloudDownload[m_index]) { [m_download stopDownload:m_index]; m_isCloudDownload[m_index] = NO; m_receiveDataSize[m_index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:m_index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)m_index]]; [self showDownloadToast:NONE]; m_index = -1; return; } /** Ch:开始下载任务 En:Start download task */ m_isCloudDownload[m_index] = YES; [m_downloadSet addObject:[NSString stringWithFormat:@"%ld", (long)m_index]]; NSString *recId = nil; NSString *recordRegionId = nil; NSString *recName = nil; if (m_recordType == CloudRecord) { recId = ((RecordInfo*)[m_recInfo objectAtIndex:m_index])->recId; recordRegionId = ((RecordInfo*)[m_recInfo objectAtIndex:m_index])->recRegId; } else { recName = ((RecordInfo*)[m_recInfo objectAtIndex:m_index])->name; } NSString* beginTime = ((RecordInfo*)[m_recInfo objectAtIndex:m_index])->beginTime; NSString* time; NSString* regex = @"[1-9]\\d{3}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}"; //正常字符范围 NSPredicate* pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; //比较处理 if ([pred evaluateWithObject:beginTime]) { NSArray* array = [beginTime componentsSeparatedByString:@" "]; NSArray* arrayDate = [array[0] componentsSeparatedByString:@"-"]; NSArray* arrayTime = [array[1] componentsSeparatedByString:@":"]; time = [arrayDate[0] stringByAppendingFormat:@"%@%@%@%@%@", arrayDate[1], arrayDate[2], arrayTime[0], arrayTime[1], arrayTime[2]]; } NSArray* paths = NSSearchPathForDirectoriesInDomains(NSLibraryDirectory, NSUserDomainMask, YES); NSString* libraryDirectory = [paths objectAtIndex:0]; NSString* myDirectory = [libraryDirectory stringByAppendingPathComponent:@"lechange"]; NSString* downloadDirectory = [myDirectory stringByAppendingPathComponent:@"download"]; NSString* infoPath = [downloadDirectory stringByAppendingPathComponent:[NSString stringWithFormat:@"%@_download_%@", time, (m_recordType == CloudRecord) ? @"cloud_record" : @"device_record"]]; m_downloadPath = [infoPath stringByAppendingString:@".mp4"]; NSFileManager* fileManage = [NSFileManager defaultManager]; NSError* pErr; BOOL isDir; if (NO == [fileManage fileExistsAtPath:myDirectory isDirectory:&isDir]) { [fileManage createDirectoryAtPath:myDirectory withIntermediateDirectories:YES attributes:nil error:&pErr]; } if (NO == [fileManage fileExistsAtPath:downloadDirectory isDirectory:&isDir]) { [fileManage createDirectoryAtPath:downloadDirectory withIntermediateDirectories:YES attributes:nil error:&pErr]; } NSLog(@"RecordPlayViewController[m_downloadPath] = %@", m_downloadPath); [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:m_index]; [m_listViewLock unlock]; if (m_recordType == CloudRecord) { [m_download startDownload:m_index filepath:m_downloadPath token:m_accessToken devID:m_strDevSelected channelID:m_devChnSelected psk:m_encryptKey recordRegionId:recordRegionId Type:1000 Timeout:10]; } else { [m_download startDownload:m_index filepath:m_downloadPath token:m_accessToken devID:m_strDevSelected decryptKey:m_encryptKey fileID:recName speed:16]; } } - (void)onDownloadReceiveData:(NSInteger)index datalen:(NSInteger)datalen { dispatch_async(dispatch_get_main_queue(), ^{ if (index < 0 || index >= RECORD_NUM_MAX) { NSLog(@"RecordViewController, index Wrong!"); return; } m_receiveDataSize[index] = m_receiveDataSize[index] + datalen; }); } - (void)onDownloadState:(NSInteger)index code:(NSString*)code type:(NSInteger)type { NSLog(@"RecordPlayViewController onDownloadState[index, code, type] = [%ld, %@, %ld]", (long)index, code, (long)type); if (99 == type) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"openapi network interaction timeout"); m_isCloudDownload[index] = NO; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } else if (1 == type) { if ([HLS_Result_String(HLS_DOWNLOAD_FAILD) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_DOWNLOAD_FAILD"); m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } else if ([HLS_Result_String(HLS_DOWNLOAD_BEGIN) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_DOWNLOAD_BEGIN"); }); } else if ([HLS_Result_String(HLS_DOWNLOAD_END) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; m_index = -1; }); NSURL *dowmloadRUL = [NSURL fileURLWithPath:m_downloadPath]; [PHAsset deleteFormCameraRoll:dowmloadRUL success:^{ } failure:^(NSError *error) { NSLog(@"Failed to delete:%@", error.description); }]; [PHAsset saveVideoAtURL:dowmloadRUL success:^(void) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Saved successfully"); [self alertToPlayLocalFile:m_downloadPath]; }); } failure:^(NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Save failed:%@", error.description); [self showDownloadToast:SAVE_FAILED]; }); }]; } else if ([HLS_Result_String(HLS_SEEK_SUCCESS) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_SEEK_SUCCESS"); }); } else if ([HLS_Result_String(HLS_SEEK_FAILD) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_SEEK_FAILD"); }); } else if ([HLS_Result_String(HLS_ABORT_DONE) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_ABORT_DONE"); m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } else if ([HLS_Result_String(HLS_DOWNLOAD_TIMEOUT) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_DOWNLOAS_TIMEOUT"); m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } else if([HLS_Result_String(HLS_KEY_ERROR) isEqualToString:code]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"HLS_KEY_ERROR"); m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } } else if (0 == type) { if ([code isEqualToString:@"1"]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"RTSP_DOWNLOAD_FAILD"); [m_download stopDownload:m_index]; m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } else if ([code isEqualToString:@"4"]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"RTSP_DOWNLOAD_BEGIN"); }); } else if ([code isEqualToString:@"5"]) { dispatch_async(dispatch_get_main_queue(), ^{ [m_download stopDownload:m_index]; m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; m_index = -1; }); NSURL *dowmloadRUL = [NSURL fileURLWithPath:m_downloadPath]; [PHAsset deleteFormCameraRoll:dowmloadRUL success:^{ } failure:^(NSError *error) { NSLog(@"Failed to delete:%@", error.description); }]; [PHAsset saveVideoAtURL:dowmloadRUL success:^(void) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Saved successfully"); [self alertToPlayLocalFile:m_downloadPath]; }); } failure:^(NSError *error) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"Save failed:%@", error.description); [self showDownloadToast:SAVE_FAILED]; }); }]; } else if ([code isEqualToString:@"7"]) { dispatch_async(dispatch_get_main_queue(), ^{ NSLog(@"RTSP_KEY_ERROR"); [m_download stopDownload:m_index]; m_isCloudDownload[index] = NO; m_receiveDataSize[index] = 0; [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:index]; [m_listViewLock unlock]; [m_downloadSet removeObject:[NSString stringWithFormat:@"%ld", (long)index]]; [self showDownloadToast:DOWNLOAD_FAILED]; m_index = -1; }); } } } - (void)onSmsTimer:(NSInteger)index { for (NSString* obj in m_downloadSet) { [m_listViewLock lock]; [self reloadCell:m_listView Section:0 Row:[obj intValue]]; [m_listViewLock unlock]; } } - (void)onBack { for (NSString* obj in m_downloadSet) { [m_download stopDownload:[obj intValue]]; } [m_timer invalidate]; [self destroyThread]; [self dismissViewControllerAnimated:YES completion:nil]; [self.navigationController popViewControllerAnimated:YES]; } - (void)getRecords { m_right.enabled = NO; switch (m_recordType) { case DeviceRecord: [self getLocalRecords]; break; case CloudRecord: [self getCloudRecords]; default: break; } } - (void)getLocalRecords { [self showLoading]; m_toastLab.hidden = YES; dispatch_queue_t get_local_records = dispatch_queue_create("get_local_records", nil); dispatch_async(get_local_records, ^{ NSInteger year, month, day; NSInteger hour, minute, second; NSString* sBeginTime; NSString* sEndTime; year = month = day = hour = minute = second = 0; if (m_dateSelected == nil) { [self getCurrentDate:&year month:&month day:&day hour:&hour minute:&minute second:&second]; } else { NSString* regex = @"[1-9]\\d{3}-\\d{2}-\\d{2}"; NSPredicate* pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; if ([pred evaluateWithObject:m_dateSelected]) { year = [[m_dateSelected substringWithRange:(NSRange){ 0, 4 }] intValue]; month = [[m_dateSelected substringWithRange:(NSRange){ 5, 2 }] intValue]; day = [[m_dateSelected substringWithRange:(NSRange){ 8, 2 }] intValue]; } } sBeginTime = [NSString stringWithFormat:@"%04ld-%02ld-%02ld 00:00:00", (long)year, (long)month, (long)day]; sEndTime = [NSString stringWithFormat:@"%04ld-%02ld-%02ld 23:59:59", (long)year, (long)month, (long)day]; if (YES == m_isStarting) { [m_recInfoLock lock]; } [self freeRecInfo]; //end. NSString* errMsg; NSInteger iNum; RestApiService* restApiService = [RestApiService shareMyInstance]; [restApiService getRecordNum:m_strDevSelected Chnl:m_devChnSelected Begin:sBeginTime End:sEndTime Num:&iNum Msg:&errMsg]; if (![errMsg isEqualToString:[MSG_SUCCESS mutableCopy]]) { if (YES == m_isStarting) { [m_recInfoLock unlock]; } dispatch_async(dispatch_get_main_queue(), ^{ [self hideLoading]; m_toastLab.text = errMsg; m_toastLab.hidden = NO; m_right.enabled = YES; }); return; } if (iNum > 0) { NSInteger beginIndex = iNum > 10 ? (iNum - 9) : 1; NSString* errMsg; [restApiService getRecords:m_strDevSelected Chnl:m_devChnSelected Begin:sBeginTime End:sEndTime IndexBegin:beginIndex IndexEnd:iNum InfoOut:m_recInfo Msg:&errMsg]; if (![errMsg isEqualToString:[MSG_SUCCESS mutableCopy]]) { if (YES == m_isStarting) { [m_recInfoLock unlock]; } dispatch_async(dispatch_get_main_queue(), ^{ [self hideLoading]; m_toastLab.text = errMsg; m_toastLab.hidden = NO; m_right.enabled = YES; }); return; } NSInteger count = m_recInfo.count; for (NSInteger i = 0; i <= count / 2 - 1; i++) { RecordInfo* t_record = [m_recInfo objectAtIndex:i]; m_recInfo[i] = m_recInfo[count - 1 - i]; m_recInfo[count - 1 - i] = t_record; } } for (NSInteger i = 0; i < m_recInfo.count; i++) { m_totalDataSize[i] = ((RecordInfo*)[m_recInfo objectAtIndex:i])->size; m_receiveDataSize[i] = 0; m_isCloudDownload[i] = NO; } if (YES == m_isStarting) { [m_recInfoLock unlock]; } m_isStarting = YES; dispatch_async(dispatch_get_main_queue(), ^{ [m_listViewLock lock]; m_listView.hidden = NO; [m_listView reloadData]; [m_listViewLock unlock]; [self hideLoading]; m_right.enabled = YES; }); }); } - (void)getCloudRecords { [self showLoading]; m_toastLab.hidden = YES; dispatch_queue_t get_cloud_records = dispatch_queue_create("get_cloud_records", nil); dispatch_async(get_cloud_records, ^{ NSInteger year, month, day; NSInteger hour, minute, second; NSString* sBeginTime; NSString* sEndTime; year = month = day = hour = minute = second = 0; // TODO if (m_dateSelected == nil) { [self getCurrentDate:&year month:&month day:&day hour:&hour minute:&minute second:&second]; } else { NSString* regex = @"[1-9]\\d{3}-\\d{2}-\\d{2}"; NSPredicate* pred = [NSPredicate predicateWithFormat:@"SELF MATCHES %@", regex]; if ([pred evaluateWithObject:m_dateSelected]) { year = [[m_dateSelected substringWithRange:(NSRange){ 0, 4 }] intValue]; month = [[m_dateSelected substringWithRange:(NSRange){ 5, 2 }] intValue]; day = [[m_dateSelected substringWithRange:(NSRange){ 8, 2 }] intValue]; } } sBeginTime = [NSString stringWithFormat:@"%04ld-%02ld-%02ld 00:00:00", (long)year, (long)month, (long)day]; sEndTime = [NSString stringWithFormat:@"%04ld-%02ld-%02ld 23:59:59", (long)year, (long)month, (long)day]; if (YES == m_isStarting) { [m_recInfoLock lock]; } [self freeRecInfo]; NSString* errMsg; NSInteger iNum; RestApiService* restApiService = [RestApiService shareMyInstance]; [restApiService getCloudRecordNum:m_strDevSelected Chnl:m_devChnSelected Bengin:sBeginTime End:sEndTime Num:&iNum Msg:&errMsg]; if (![errMsg isEqualToString:[MSG_SUCCESS mutableCopy]]) { if (YES == m_isStarting) { [m_recInfoLock unlock]; } dispatch_async(dispatch_get_main_queue(), ^{ [self hideLoading]; m_toastLab.text = errMsg; m_toastLab.hidden = NO; m_right.enabled = YES; }); return; } if (iNum > 0) { dispatch_async(dispatch_get_main_queue(), ^{ m_toastLab.hidden = YES; }); NSString* errMsg; NSInteger beginIndex = iNum > 10 ? (iNum - 9) : 1; [restApiService getCloudRecords:m_strDevSelected Chnl:m_devChnSelected Begin:sBeginTime End:sEndTime IndexBegin:beginIndex IndexEnd:iNum InfoOut:m_recInfo Msg:&errMsg]; if (![errMsg isEqualToString:[MSG_SUCCESS mutableCopy]]){ if (YES == m_isStarting) { [m_recInfoLock unlock]; } dispatch_async(dispatch_get_main_queue(), ^{ [self hideLoading]; m_toastLab.text = errMsg; m_toastLab.hidden = NO; m_right.enabled = YES; }); return; } NSInteger count = m_recInfo.count; for (NSInteger i = 0; i <= count / 2 - 1; i++) { RecordInfo* t_record = [m_recInfo objectAtIndex:i]; m_recInfo[i] = m_recInfo[count - 1 - i]; m_recInfo[count - 1 - i] = t_record; } } for (NSInteger i = 0; i < m_recInfo.count; i++) { m_totalDataSize[i] = ((RecordInfo*)[m_recInfo objectAtIndex:i])->size; m_receiveDataSize[i] = 0; m_isCloudDownload[i] = NO; } if (YES == m_isStarting) { [m_recInfoLock unlock]; } m_isStarting = YES; dispatch_async(dispatch_get_main_queue(), ^{ [self hideLoading]; [m_listViewLock lock]; m_listView.hidden = NO; [m_listView reloadData]; [m_listViewLock unlock]; m_right.enabled = YES; }); }); } - (void)getCurrentDate:(NSInteger*)year month:(NSInteger*)month day:(NSInteger*)day hour:(NSInteger*)hour minute:(NSInteger*)minute second:(NSInteger*)second { NSDate* now = [NSDate date]; NSCalendar* calendar = [NSCalendar currentCalendar]; NSUInteger unitFlags = NSCalendarUnitYear | NSCalendarUnitMonth | NSCalendarUnitDay | NSCalendarUnitHour | NSCalendarUnitMinute | NSCalendarUnitSecond; NSDateComponents* dateComponent = [calendar components:unitFlags fromDate:now]; *year = [dateComponent year]; *month = [dateComponent month]; *day = [dateComponent day]; *hour = [dateComponent hour]; *minute = [dateComponent minute]; *second = [dateComponent second]; } - (void)freeRecInfo { [m_recInfo removeAllObjects]; } - (void)reloadCell:(UITableView*)tableView Section:(NSInteger)section Row:(NSInteger)row { NSIndexPath* indexPath = [NSIndexPath indexPathForRow:row inSection:section]; if ([tableView numberOfRowsInSection:section] > row) { [UIView performWithoutAnimation:^{ CGPoint loc = tableView.contentOffset; [tableView reloadRowsAtIndexPaths:@[indexPath] withRowAnimation:UITableViewRowAnimationNone]; tableView.contentOffset = loc; }]; } } - (void)downloadThread { m_iPos = 0; m_downloadingPos = -1; int j; while (m_looping) { usleep(20 * 1000); BOOL bNeedDown = YES; NSString* picUrl; [m_recInfoLock lock]; [m_downStatusLock lock]; do { picUrl = nil; if (m_iPos < 0 || m_iPos >= m_recInfo.count) { bNeedDown = NO; m_iPos = (m_iPos + 1) % (RECORD_NUM_MAX); break; } for (j = 0; j < RECORD_NUM_MAX; j++) { if (DOWNLOADING == m_downloadPicture[j].downStatus) { break; } } if (j < RECORD_NUM_MAX) { bNeedDown = NO; break; } if (NONE != m_downloadPicture[m_iPos].downStatus) { bNeedDown = NO; m_iPos = (m_iPos + 1) % (RECORD_NUM_MAX); break; } picUrl = [((RecordInfo*)[m_recInfo objectAtIndex:m_iPos])->thumbUrl mutableCopy]; } while (0); [m_recInfoLock unlock]; if (!bNeedDown || !picUrl || 0 == picUrl.length) { [m_downStatusLock unlock]; continue; } //download m_httpUrl = [NSURL URLWithString:picUrl]; m_downloadPicture[m_iPos].downStatus = DOWNLOADING; m_downloadingPos = m_iPos; m_iPos = (m_iPos + 1) % (RECORD_NUM_MAX); NSURLRequest* request = [NSMutableURLRequest requestWithURL:m_httpUrl cachePolicy:NSURLRequestReloadIgnoringCacheData timeoutInterval:10.0]; NSHTTPURLResponse* response = nil; NSData* data = [NSURLConnection sendSynchronousRequest:request returningResponse:&response error:NULL]; if (m_downloadingPos < 0) { NSLog(@"connectionDidFinishLoading m_downloadingPos[%ld]", (long)m_downloadingPos); return; } if (response == nil) { NSLog(@"download failed"); m_downloadPicture[m_downloadingPos].downStatus = DOWNLOAD_FAILED; } else { NSLog(@"connectionDidFinishLoading m_downloadingPos[%ld]", (long)m_downloadingPos); m_downloadPicture[m_downloadingPos].picData = data; NSData* dataOut = [[NSData alloc] init]; NSInteger iret = [m_util decryptPic:m_downloadPicture[m_downloadingPos].picData deviceID:m_strDevSelected key:m_encryptKey token:m_accessToken bufOut:&dataOut]; NSLog(@"decrypt iret[%ld]", (long)iret); if (0 == iret) { [m_downloadPicture[m_downloadingPos] setData:[NSData dataWithBytes:[dataOut bytes] length:[dataOut length]] status:DOWNLOAD_FINISHED]; dispatch_async(dispatch_get_main_queue(), ^{ [m_listViewLock lock]; [m_listView reloadData]; [m_listViewLock unlock]; }); } else { [m_downloadPicture[m_downloadingPos] setData:nil status:DOWNLOAD_FAILED]; } } [m_downStatusLock unlock]; } } - (void)destroyThread { m_looping = NO; } - (void)showDownloadToast:(DownStatus)status { switch (status) { case DOWNLOAD_SUCCESS: m_toastLab.text = NSLocalizedString(DOWNLOAD_SUCCESS_TXT, nil); m_toastLab.hidden = NO; [self performSelector:@selector(downloadToastDelay) withObject:nil afterDelay:2.0f]; break; case DOWNLOAD_FAILED: m_toastLab.text = NSLocalizedString(DOWNLOAD_FAILED_TXT, nil); m_toastLab.hidden = NO; [self performSelector:@selector(downloadToastDelay) withObject:nil afterDelay:2.0f]; break; case DOWNLOADING: m_toastLab.text = NSLocalizedString(DOWNLOADING_TXT, nil); m_toastLab.hidden = NO; [self performSelector:@selector(downloadToastDelay) withObject:nil afterDelay:2.0f]; break; case NONE: m_toastLab.text = NSLocalizedString(CANCEL_DOWNLOAD_TXT, nil); m_toastLab.hidden = NO; [self performSelector:@selector(downloadToastDelay) withObject:nil afterDelay:2.0f]; break; case SAVE_FAILED: m_toastLab.text = NSLocalizedString(RECORD_SAVE_FAILED, nil); m_toastLab.hidden = NO; [self performSelector:@selector(downloadToastDelay) withObject:nil afterDelay:2.0f]; break; default: break; } } - (void)alertToPlayLocalFile:(NSString *)filePath { UIAlertController* alert = [UIAlertController alertControllerWithTitle:NSLocalizedString(PLAY_LOCAL_FILE, nil) message:nil preferredStyle:UIAlertControllerStyleAlert]; UIAlertAction* confirmAction = [UIAlertAction actionWithTitle:@"OK" style:UIAlertActionStyleDefault handler:^(UIAlertAction* _Nonnull action){ LocalPlayViewController *localPlayViewController = [LocalPlayViewController new]; localPlayViewController.filepath = filePath; [self.navigationController pushViewController:localPlayViewController animated:NO]; }]; UIAlertAction* cancelAction = [UIAlertAction actionWithTitle:@"NO" style:UIAlertActionStyleDefault handler:nil]; [alert addAction:confirmAction]; [alert addAction:cancelAction]; [self presentViewController:alert animated:YES completion:nil]; } - (void)downloadToastDelay { m_toastLab.hidden = YES; } - (void)showLoading { [m_progressInd startAnimating]; } - (void)hideLoading { if ([m_progressInd isAnimating]) { [m_progressInd stopAnimating]; } } - (void)dealloc { NSLog(@"RecordViewController, dealloc"); } @end