前言

苹果手机录制的视频在非Safari浏览器和安卓机器上面都无法直接播放,原因是因为直接录制的视频默认是mov格式,这是需要转换一下格式来处理
其中包含多种转码方式
[KJVideoFileTypeMov] = @".mov",
[KJVideoFileTypeMp4] = @".mp4",
[KJVideoFileTypeWav] = @".wav",
[KJVideoFileTypeM4v] = @".m4v",
[KJVideoFileTypeM4a] = @".m4a",
[KJVideoFileTypeCaf] = @".caf",
[KJVideoFileTypeAif] = @".aif",
[KJVideoFileTypeMp3] = @".mp3",

这里提供一套视频转码的工具

简单调用

/// 视频格式转换处理
+ (void)kj_videoConvertEncodeInfo:(KJVideoEncodeInfo*(^)(KJVideoEncodeInfo*info))infoblock Block:(kVideoEncodeBlock)block;

KJVideoEncodeInfo传入相对应的参数即可

简单直接上代码

#import <Foundation/Foundation.h>
#import <Photos/Photos.h>
typedef NS_ENUM(NSInteger, KJExportPresetQualityType) {KJExportPresetQualityTypeLowQuality = 0, //低质量 可以通过移动网络分享KJExportPresetQualityTypeMediumQuality,  //中等质量 可以通过WIFI网络分享KJExportPresetQualityTypeHighestQuality, //高等质量KJExportPresetQualityType640x480,KJExportPresetQualityType960x540,KJExportPresetQualityType1280x720,KJExportPresetQualityType1920x1080,KJExportPresetQualityType3840x2160,
};
typedef NS_ENUM(NSInteger, KJVideoFileType) {KJVideoFileTypeMov = 0, /// .movKJVideoFileTypeMp4, /// .mp4KJVideoFileTypeWav,KJVideoFileTypeM4v,KJVideoFileTypeM4a,KJVideoFileTypeCaf,KJVideoFileTypeAif,KJVideoFileTypeMp3,
};
static NSString * const _Nonnull KJVideoFileTypeStringMap[] = {[KJVideoFileTypeMov] = @".mov",[KJVideoFileTypeMp4] = @".mp4",[KJVideoFileTypeWav] = @".wav",[KJVideoFileTypeM4v] = @".m4v",[KJVideoFileTypeM4a] = @".m4a",[KJVideoFileTypeCaf] = @".caf",[KJVideoFileTypeAif] = @".aif",[KJVideoFileTypeMp3] = @".mp3",
};
typedef void(^kVideoEncodeBlock)(NSURL * _Nullable mp4URL, NSError * _Nullable error);
NS_ASSUME_NONNULL_BEGIN
@interface KJVideoEncodeInfo : NSObject
@property(nonatomic,strong)NSString *videoName;
@property(nonatomic,strong)NSString *videoPath;
@property(nonatomic,assign)KJExportPresetQualityType qualityType;
@property(nonatomic,assign)KJVideoFileType videoType; /// 视频转换格式,默认.mp4
/// URL、PHAsset、AVURLAsset互斥三者选其一
@property(nonatomic,strong)PHAsset *PHAsset;
@property(nonatomic,strong)NSURL *URL;
@property(nonatomic,strong)AVURLAsset *AVURLAsset;
/// 获取导出质量
+ (NSString * const)getAVAssetExportPresetQuality:(KJExportPresetQualityType)qualityType;
/// 获取导出格式
+ (NSString * const)getVideoFileType:(KJVideoFileType)videoType;
@end
@interface KJVideoEncodeTool : NSObject
/// 视频格式转换处理
+ (void)kj_videoConvertEncodeInfo:(KJVideoEncodeInfo*(^)(KJVideoEncodeInfo*info))infoblock Block:(kVideoEncodeBlock)block;
@endNS_ASSUME_NONNULL_END
#import "KJVideoEncodeTool.h"
@implementation KJVideoEncodeInfo
- (instancetype)init{if (self==[super init]) {self.qualityType = KJExportPresetQualityTypeHighestQuality;self.videoType = KJVideoFileTypeMp4;}return self;
}
/// 获取导出质量
+ (NSString * const)getAVAssetExportPresetQuality:(KJExportPresetQualityType)qualityType{switch (qualityType) {case KJExportPresetQualityTypeLowQuality:return AVAssetExportPresetLowQuality;case KJExportPresetQualityTypeMediumQuality:return AVAssetExportPresetMediumQuality;case KJExportPresetQualityTypeHighestQuality:return AVAssetExportPresetHighestQuality;case KJExportPresetQualityType640x480:return AVAssetExportPreset640x480;case KJExportPresetQualityType960x540:return AVAssetExportPreset960x540;case KJExportPresetQualityType1280x720:return AVAssetExportPreset1280x720;case KJExportPresetQualityType1920x1080:return AVAssetExportPreset1920x1080;case KJExportPresetQualityType3840x2160:return AVAssetExportPreset3840x2160;}
}
/// 获取导出格式
+ (NSString * const)getVideoFileType:(KJVideoFileType)videoType{switch (videoType) {case KJVideoFileTypeMov:return AVFileTypeQuickTimeMovie;case KJVideoFileTypeMp4:return AVFileTypeMPEG4;case KJVideoFileTypeWav:return AVFileTypeWAVE;case KJVideoFileTypeM4v:return AVFileTypeAppleM4V;case KJVideoFileTypeM4a:return AVFileTypeAppleM4A;case KJVideoFileTypeCaf:return AVFileTypeCoreAudioFormat;case KJVideoFileTypeAif:return AVFileTypeAIFF;case KJVideoFileTypeMp3:return AVFileTypeMPEGLayer3;}
}
@end
@implementation KJVideoEncodeTool
+ (void)kj_videoConvertEncodeInfo:(KJVideoEncodeInfo*(^)(KJVideoEncodeInfo*))infoblock Block:(kVideoEncodeBlock)block{KJVideoEncodeInfo *info = [KJVideoEncodeInfo new];if (infoblock) info = infoblock(info);__block NSString *presetName = [KJVideoEncodeInfo getAVAssetExportPresetQuality:info.qualityType];__block NSString *videoType  = [KJVideoEncodeInfo getVideoFileType:info.videoType];NSString *suffix = KJVideoFileTypeStringMap[info.videoType];if (![info.videoName hasSuffix:suffix]) {info.videoName = [info.videoName stringByAppendingString:suffix];}if (info.URL == nil && info.PHAsset == nil && info.AVURLAsset == nil) {NSError *error = [self kj_setErrorCode:10008 DescriptionKey:@"Lack of material"];block(nil, error);}else if (info.URL) {AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:info.URL options:nil];[self convertAVURLAsset:avAsset Name:info.videoName Path:info.videoPath FileType:videoType PresetName:presetName Block:block];}else if (info.AVURLAsset) {[self convertAVURLAsset:info.AVURLAsset Name:info.videoName Path:info.videoPath FileType:videoType PresetName:presetName Block:block];}else if (info.PHAsset) {__block NSString *name = info.videoName;__block NSString *path = info.videoPath;PHVideoRequestOptions *options = [[PHVideoRequestOptions alloc] init];options.version = PHImageRequestOptionsVersionCurrent;options.deliveryMode = PHVideoRequestOptionsDeliveryModeAutomatic;options.networkAccessAllowed = true;PHImageManager *manager = [PHImageManager defaultManager];[manager requestAVAssetForVideo:info.PHAsset options:options resultHandler:^(AVAsset *asset, AVAudioMix *audioMix, NSDictionary *info) {if ([asset isKindOfClass:[AVURLAsset class]]) {[self convertAVURLAsset:(AVURLAsset*)asset Name:name Path:path FileType:videoType PresetName:presetName Block:block];}else{NSError *error = [self kj_setErrorCode:10008 DescriptionKey:@"PHAsset error"];block(nil, error);}}];}
}
#pragma mark - MOV转码MP4
+ (void)convertAVURLAsset:(AVURLAsset*)asset Name:(NSString*)name Path:(NSString*)path FileType:(NSString*)fileType PresetName:(NSString*)presetName Block:(kVideoEncodeBlock)block{AVURLAsset *avAsset = [AVURLAsset URLAssetWithURL:asset.URL options:nil];NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];if ([compatiblePresets containsObject:presetName]) {NSFileManager *fileManager = [NSFileManager defaultManager];BOOL isDirectory = FALSE;BOOL isDirExist  = [fileManager fileExistsAtPath:path isDirectory:&isDirectory];if(!(isDirExist && isDirectory)) [fileManager createDirectoryAtPath:path withIntermediateDirectories:YES attributes:nil error:nil];NSString *resultPath = path;if (![path hasSuffix:name]) resultPath = [path stringByAppendingFormat:@"/%@",name];AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:presetName];exportSession.outputURL = [NSURL fileURLWithPath:resultPath];exportSession.outputFileType = fileType;exportSession.shouldOptimizeForNetworkUse = YES;[exportSession exportAsynchronouslyWithCompletionHandler:^(void) {switch (exportSession.status) {case AVAssetExportSessionStatusUnknown:case AVAssetExportSessionStatusWaiting:case AVAssetExportSessionStatusExporting:case AVAssetExportSessionStatusFailed:case AVAssetExportSessionStatusCancelled:{NSString *key  = [self kj_getDescriptionKey:exportSession.status];NSError *error = [self kj_setErrorCode:exportSession.status+10001 DescriptionKey:key];block(nil,error);}break;case AVAssetExportSessionStatusCompleted:block(exportSession.outputURL,nil);break;}}];}else{NSError *error = [self kj_setErrorCode:10007 DescriptionKey:@"AVAssetExportSessionStatusNoPreset"];block(nil, error);}
}
+ (NSString*)kj_getDescriptionKey:(AVAssetExportSessionStatus)status{switch (status) {case AVAssetExportSessionStatusUnknown:return @"AVAssetExportSessionStatusUnknown";case AVAssetExportSessionStatusWaiting:return @"AVAssetExportSessionStatusWaiting";case AVAssetExportSessionStatusExporting:return @"AVAssetExportSessionStatusExporting";case AVAssetExportSessionStatusCompleted:return @"AVAssetExportSessionStatusCompleted";case AVAssetExportSessionStatusFailed:return @"AVAssetExportSessionStatusFailed";case AVAssetExportSessionStatusCancelled:return @"AVAssetExportSessionStatusCancelled";}
}
+ (NSError*)kj_setErrorCode:(NSInteger)code DescriptionKey:(NSString*)key{return [NSError errorWithDomain:@"ConvertErrorDomain" code:code userInfo:@{NSLocalizedDescriptionKey:key}];
}
+ (NSDictionary*)getVideoInfo:(PHAsset*)asset{PHAssetResource * resource = [[PHAssetResource assetResourcesForAsset: asset] firstObject];NSMutableArray *resourceArray = nil;if (@available(iOS 13.0, *)) {NSString *string1 = [resource.description stringByReplacingOccurrencesOfString:@" - " withString:@" "];NSString *string2 = [string1 stringByReplacingOccurrencesOfString:@": " withString:@"="];NSString *string3 = [string2 stringByReplacingOccurrencesOfString:@"{" withString:@""];NSString *string4 = [string3 stringByReplacingOccurrencesOfString:@"}" withString:@""];NSString *string5 = [string4 stringByReplacingOccurrencesOfString:@", " withString:@" "];resourceArray = [NSMutableArray arrayWithArray:[string5 componentsSeparatedByString:@" "]];[resourceArray removeObjectAtIndex:0];[resourceArray removeObjectAtIndex:0];}else {NSString *string1 = [resource.description stringByReplacingOccurrencesOfString:@"{" withString:@""];NSString *string2 = [string1 stringByReplacingOccurrencesOfString:@"}" withString:@""];NSString *string3 = [string2 stringByReplacingOccurrencesOfString:@", " withString:@","];resourceArray = [NSMutableArray arrayWithArray:[string3 componentsSeparatedByString:@" "]];[resourceArray removeObjectAtIndex:0];[resourceArray removeObjectAtIndex:0];}NSMutableDictionary *videoInfo = [[NSMutableDictionary alloc] init];for (NSString *string in resourceArray) {NSArray *array = [string componentsSeparatedByString:@"="];videoInfo[array[0]] = array[1];}videoInfo[@"duration"] = @(asset.duration).description;return videoInfo;
}@end

使用示例

#import "KJVideoEncodeVC.h"
#import <AssetsLibrary/AssetsLibrary.h>
#import <MobileCoreServices/MobileCoreServices.h>
#import <AVFoundation/AVFoundation.h>
#import "KJVideoEncodeTool.h"
@interface KJVideoEncodeVC ()<UIImagePickerControllerDelegate,UINavigationControllerDelegate>@end@implementation KJVideoEncodeVC- (void)viewDidLoad {[super viewDidLoad];// Do any additional setup after loading the view._weakself;UIButton *button = [UIButton buttonWithType:(UIButtonTypeCustom)];[button setTitle:@"拍摄视频" forState:(UIControlStateNormal)];[button setTitleColor:UIColor.blueColor forState:(UIControlStateNormal)];button.frame = CGRectMake(0, 0, 100, 30);[self.view addSubview:button];button.center = self.view.center;[button kj_addAction:^(UIButton * _Nonnull kButton) {UIImagePickerController *pickerCon = [[UIImagePickerController alloc]init];pickerCon.sourceType = UIImagePickerControllerSourceTypeCamera;pickerCon.mediaTypes = @[(NSString*)kUTTypeMovie];//设定相机为视频pickerCon.cameraDevice = UIImagePickerControllerCameraDeviceRear;//设置相机后摄像头pickerCon.videoMaximumDuration = 5;//最长拍摄时间pickerCon.videoQuality = UIImagePickerControllerQualityTypeIFrame1280x720;//拍摄质量pickerCon.allowsEditing = NO;//是否可编辑pickerCon.delegate = weakself;[weakself presentViewController:pickerCon animated:YES completion:nil];}];UIButton *button2 = [UIButton buttonWithType:(UIButtonTypeCustom)];[button2 setTitle:@"转换视频" forState:(UIControlStateNormal)];[button2 setTitleColor:UIColor.blueColor forState:(UIControlStateNormal)];button2.frame = CGRectMake(0, 0, 100, 30);[self.view addSubview:button2];button2.center = self.view.center;button2.centerY += 50;[button2 kj_addAction:^(UIButton * _Nonnull kButton) {UIImagePickerController *pickerController = [[UIImagePickerController alloc]init];pickerController.sourceType = UIImagePickerControllerSourceTypePhotoLibrary;pickerController.mediaTypes = @[(NSString*)kUTTypeMovie];pickerController.allowsEditing = NO;pickerController.delegate = weakself;[weakself presentViewController:pickerController animated:YES completion:nil];}];
}- (void)imagePickerController:(UIImagePickerController *)picker didFinishPickingMediaWithInfo:(NSDictionary<NSString *,id> *)info{UIImage *image = [info objectForKey:UIImagePickerControllerOriginalImage];[picker dismissViewControllerAnimated:YES completion:nil];NSString *mediaType = info[UIImagePickerControllerMediaType];if ([mediaType isEqualToString:(NSString*)kUTTypeImage]) {if (image!=nil) {NSURL *imageURL = [info objectForKey:UIImagePickerControllerReferenceURL];NSLog(@"URL:%@",imageURL);NSData * imageData = UIImageJPEGRepresentation(image,0.1);NSLog(@"压缩到0.1的图片大小:%lu",[imageData length]);}}else if([mediaType isEqualToString:(NSString*)kUTTypeMovie]){NSLog(@"进入视频环节!!!");NSURL *URL = info[UIImagePickerControllerMediaURL];NSData *file = [NSData dataWithContentsOfURL:URL];NSLog(@"输出视频的大小:%lu",(unsigned long)[file length]);NSString *path = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES)lastObject] stringByAppendingPathComponent:@"Cache/VideoData"];NSTimeInterval now = [[NSDate date] timeIntervalSince1970];NSDateFormatter * formatter = [[NSDateFormatter alloc] init];[formatter setDateFormat:@"yyyyMMddHHmmssSSS"];NSDate * NowDate = [NSDate dateWithTimeIntervalSince1970:now];NSString * timeStr = [formatter stringFromDate:NowDate];[KJVideoEncodeTool kj_videoConvertEncodeInfo:^KJVideoEncodeInfo * _Nonnull(KJVideoEncodeInfo * _Nonnull info) {info.URL = URL;info.videoName = timeStr;info.videoPath = path;return info;} Block:^(NSURL * _Nullable mp4URL, NSError * _Nullable error) {NSLog(@"--%@",mp4URL);ALAssetsLibrary *assetLibrary = [[ALAssetsLibrary alloc] init];[assetLibrary writeVideoAtPathToSavedPhotosAlbum:mp4URL completionBlock:^(NSURL *assetURL, NSError *error){}];}];}
}- (void)imagePickerControllerDidCancel:(UIImagePickerController*)picker {[picker dismissViewControllerAnimated:YES completion:^{}];NSLog(@"视频录制取消了...");
}@end
备注:本文用到的部分函数方法和Demo,均来自三方库**KJExtensionHandler**,如有需要的朋友可自行pod 'KJExtensionHandler'引入即可

视频转码处理介绍就到此完毕,后面有相关再补充,写文章不容易,还请点个**小星星**传送门

iOS 视频转码处理相关推荐

  1. 最简单的基于FFmpeg的移动端样例:IOS 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端样例系列文章列表: 最简单的基于FFmpeg的移动端样例:A ...

  2. 最简单的基于FFmpeg的移动端例子:IOS 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  3. 最简单的基于FFmpeg的移动端例子:IOS 视频解码器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  4. 最简单的基于FFmpeg的移动端例子:Android 视频转码器

    ===================================================== 最简单的基于FFmpeg的移动端例子系列文章列表: 最简单的基于FFmpeg的移动端例子:A ...

  5. 一对一直播软件源码开发,iOS视频采集的实现过程

    在一对一直播软件源码日益火热的发展形势下,音视频开发(采集.编解码.传输.播放.美颜)等技术也随之成为开发者们关注的重点,本系列文章就音视频开发过程中所运用到的技术和原理进行梳理和总结. 认识 AVC ...

  6. 国际合作越来越多,如何国际化短视频源码(ios篇)

    PayPal支付是一款常见的国际贸易支付工具,因此,接入paypal成为实现短视频app国际化的重要一步,之前写过安卓系统接入该支付功能的实现方法,今天讲讲IOS端短视频源码开发paypal支付功能的 ...

  7. iOS短视频源码音频采集过程中的音效实现

    在移动短视频直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在短视频源码采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演 ...

  8. iOS短视频源码音频采集过程中的音效实现 1

    在移动短视频直播中, 声音是主播和观众互动的重要途径之一, 为了丰富直播的内容,大家都会想要在声音上做一些文章, 在短视频源码采集录音的基础上玩一些花样. 比如演唱类的直播间中, 主播伴随着背景音乐演 ...

  9. 仿抖音APP短视频源码PHP安卓IOS

    随着短视频市场的不断发展,越来越多的人开始关注短视频APP的开发和推广. 仿抖音APP短视频源码主要介绍: 系统语言:APP是原生安卓和IOS, 后端和接口是PHP(tp框架).数据库mysql+re ...

最新文章

  1. 深度学习原来还可以这么学!
  2. 《Linux命令行与shell脚本编程大全 第3版》Shell脚本编程基础---02
  3. 如何在Linux(ubuntu21.04)下安装chrome浏览器
  4. jquery源码--merge grep type trim
  5. sudo dpkg 找不到命令_【干货】Linux中实用但很小众的11个炫酷终端命令
  6. python oracle连接池_【Python + Oracle】Python Oracle连接池—改进版
  7. php sem acquire,PHP | 关于php中sem_get failed for key no space left on device问题的解决方案...
  8. 游戏大魔王少不了王者荣耀壁纸图片
  9. yolov3前向传播(三)-- 坐标转换,iou计算,权重加载,图片显示
  10. 北京大学生物信息学(8)
  11. onhashchange事件--司徒正美
  12. Java期末复习基础知识整理(有点长)
  13. 找出m到n水仙花数c语言程序设计,《C语言课程设计输出水仙花数》.doc
  14. 【qq机器人】王者英雄问题查询
  15. 电信网通证实台湾地震影响内地访问国际网站(12月27日)
  16. 从前后端分离到前后端整合的“退步”(一)项目结构
  17. 如何根据SIM卡背面的10位序列号判断运营商,国家,地区,卡商
  18. Verilog中任务task的使用
  19. android gridview日历,Android使用GridView实现日历的方法
  20. IBM MQ通道接收端绑定步骤

热门文章

  1. VMware桌面云之旅
  2. 前端分享之tinymce编辑器设置默认字体
  3. 健康——基本运动的卡路里计算公式
  4. Uni-App 云打包使用自有证书的步骤
  5. idea格式化代码快捷键 快捷键: Ctrl+Shift+Alt+L
  6. 网络爬虫与信息提取--正则表达式---淘宝商品比价定向爬虫
  7. 12.14 Daily Scrum
  8. 灵活填充健康和可持续食品
  9. 【紫光同创国产FPGA教程】【第十七章】AD实验之AD9238波形显示
  10. ATmega8 定时器 中断 外部中断 程序