在游戏中,有时候需要将一些简单的图片组合成视频,然后让用户分享出去,当然仅仅是那种很简单的图片组合视频(这是我自己项目的需求,不需要录制UI等其他东西)。本来想找插件的,后面看到大部分插件都是通过摄像机去录屏,但是我们项目本来就一个对图片操作的游戏,因此没法用插件。

寻思着自己写一个,还好iOS方面的东西还是很齐全的,在查阅了很多资料和博客之后,终于被我弄出来的。

原理也简单,就是通过写iOS原生的视频生成代码,然后通过Unity去调用的方式去做的,Unity本身并不能生成视频!

这里说明下,我写的代码都是在我原来博客写的一个类里面添加的,可以先看看我之前的类:原生分享

添加一个将图片合成视频的方法(这个方法是我在网上找的,自己并不会oc - -!)

- (void) combineImageToVideo2:(NSString*)mainPath byName:(NSString*)videoName imageCount:(int)count
{NSLog(@"path = %@, video name = %@", mainPath, videoName);imageArray = [[NSMutableArray alloc]init];for(int i=0;i<count;i++){NSString* _pathImage = [mainPath stringByAppendingPathComponent:[NSString stringWithFormat:@"%dtv.png", i]];NSData* data = [NSData dataWithContentsOfFile:_pathImage];UIImage* image = [UIImage imageWithData:data];[imageArray addObject:image];}NSString* moviePath = [mainPath stringByAppendingPathComponent:videoName];//@"outputVideo.mov"self.theMainPath = moviePath;self.theVideoName = videoName;//定义视频的大小 256 256 倍数CGSize size = CGSizeMake(256, 256);NSError *error = nil;//    转成UTF-8编码unlink([moviePath UTF8String]);//     iphone提供了AVFoundation库来方便的操作多媒体设备,AVAssetWriter这个类可以方便的将图像和音频写成一个完整的视频文件AVAssetWriter *videoWriter = [[AVAssetWriter alloc] initWithURL:[NSURL fileURLWithPath:moviePath] fileType:AVFileTypeQuickTimeMovie error:&error];NSParameterAssert(videoWriter);if (error){NSLog(@"error = %@", [error localizedDescription]);UnitySendMessage("GJCNativeShare", "OnCreateVideoFailed", [GJC_DataConvertor NSStringToChar:@"error: videoWriter error"]);}//mov的格式设置 编码格式 宽度 高度NSDictionary *videoSettings =[NSDictionary dictionaryWithObjectsAndKeys:AVVideoCodecH264,AVVideoCodecKey,[NSNumber numberWithInt:size.width],AVVideoWidthKey,[NSNumber numberWithInt:size.height],AVVideoHeightKey,nil];AVAssetWriterInput *writerInput =[AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];NSDictionary*sourcePixelBufferAttributesDictionary =[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithInt:kCVPixelFormatType_32ARGB],kCVPixelBufferPixelFormatTypeKey,nil];//    AVAssetWriterInputPixelBufferAdaptor提供CVPixelBufferPool实例,//    可以使用分配像素缓冲区写入输出文件。使用提供的像素为缓冲池分配通常//    是更有效的比添加像素缓冲区分配使用一个单独的池AVAssetWriterInputPixelBufferAdaptor *adaptor =[AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:writerInput sourcePixelBufferAttributes:sourcePixelBufferAttributesDictionary];NSParameterAssert(writerInput);NSParameterAssert([videoWriter canAddInput:writerInput]);if ([videoWriter canAddInput:writerInput]){NSLog(@"can add input");
//        UnitySendMessage("GJCNativeShare", "OnCreateVideoWork", [GJC_DataConvertor NSStringToChar:@"write: videoWriter can add input"]);}else{NSLog(@"can not add input");UnitySendMessage("GJCNativeShare", "OnCreateVideoFailed", [GJC_DataConvertor NSStringToChar:@"error: videoWriter can not add input"]);}[videoWriter addInput:writerInput];[videoWriter startWriting];[videoWriter startSessionAtSourceTime:kCMTimeZero];//合成多张图片为一个视频文件dispatch_queue_t dispatchQueue =dispatch_queue_create("mediaInputQueue",NULL);int __block frame =0;[writerInput requestMediaDataWhenReadyOnQueue:dispatchQueue usingBlock:^{BOOL blnError = NO;while([writerInput isReadyForMoreMediaData]){if(++frame >= [imageArray count]){[writerInput markAsFinished];
//                [videoWriter finishWriting];
//                [videoWriter finishWritingWithCompletionHandler:nil];[videoWriter finishWritingWithCompletionHandler:^{NSLog(@"creat video finished!");}];if (blnError){UnitySendMessage("GJCNativeShare", "OnCreateVideoFailed", [GJC_DataConvertor NSStringToChar:@"Failed"]);}else{UnitySendMessage("GJCNativeShare", "OnCreateVideoSuccess", [GJC_DataConvertor NSStringToChar:@"Success"]);}break;}CVPixelBufferRef buffer = NULL;int idx = frame;NSLog(@"idx==%d",idx);buffer = (CVPixelBufferRef)[self pixelBufferFromCGImage:[[imageArray objectAtIndex:idx] CGImage] size:size];if (buffer){//设置每秒钟播放图片的个数if(![adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(frame, 12)]){NSLog(@"FAIL");
//                    UnitySendMessage("GJCNativeShare", "OnCreateVideoWork", [GJC_DataConvertor NSStringToChar:@"error: adaptor add error"]);blnError = YES;}else{
//                    NSLog(@"OK");
//                    UnitySendMessage("GJCNativeShare", "OnCreateVideoWork", [GJC_DataConvertor NSStringToChar:@"write: adaptor add ok."]);}CFRelease(buffer);}}}];
}- (CVPixelBufferRef)pixelBufferFromCGImage:(CGImageRef)image size:(CGSize)size
{NSDictionary *options =[NSDictionary dictionaryWithObjectsAndKeys:[NSNumber numberWithBool:YES],kCVPixelBufferCGImageCompatibilityKey,[NSNumber numberWithBool:YES],kCVPixelBufferCGBitmapContextCompatibilityKey,nil];CVPixelBufferRef pxbuffer =NULL;CVReturn status =CVPixelBufferCreate(kCFAllocatorDefault,size.width,size.height,kCVPixelFormatType_32ARGB,(__bridge CFDictionaryRef) options,&pxbuffer);NSParameterAssert(status ==kCVReturnSuccess && pxbuffer !=NULL);CVPixelBufferLockBaseAddress(pxbuffer,0);void *pxdata =CVPixelBufferGetBaseAddress(pxbuffer);NSParameterAssert(pxdata !=NULL);CGColorSpaceRef rgbColorSpace=CGColorSpaceCreateDeviceRGB();//    当你调用这个函数的时候,Quartz创建一个位图绘制环境,也就是位图上下文。当你向上下文中绘制信息时,Quartz把你要绘制的信息作为位图数据绘制到指定的内存块。一个新的位图上下文的像素格式由三个参数决定:每个组件的位数,颜色空间,alpha选项CGContextRef context =CGBitmapContextCreate(pxdata,size.width,size.height,8,4*size.width,rgbColorSpace,kCGImageAlphaPremultipliedFirst);NSParameterAssert(context);//使用CGContextDrawImage绘制图片  这里设置不正确的话 会导致视频颠倒//    当通过CGContextDrawImage绘制图片到一个context中时,如果传入的是UIImage的CGImageRef,因为UIKit和CG坐标系y轴相反,所以图片绘制将会上下颠倒CGContextDrawImage(context,CGRectMake(0,0,CGImageGetWidth(image),CGImageGetHeight(image)), image);// 释放色彩空间CGColorSpaceRelease(rgbColorSpace);// 释放contextCGContextRelease(context);// 解锁pixel bufferCVPixelBufferUnlockBaseAddress(pxbuffer,0);return pxbuffer;
}

再添加个C方法:

extern "C" {void _GJC_CombineImageToVideo(char* mainPath, char* videoName, int count) {NSString *savePath = [GJC_DataConvertor charToNSString:mainPath];NSString *saveName = [GJC_DataConvertor charToNSString:videoName];[[GJCSocialShare sharedInstance] combineImageToVideo2:savePath byName:saveName imageCount:count];}
}

Unity添加方法:

[DllImport ("__Internal")]private static extern void _GJC_CombineImageToVideo(string savePath, string videoName, int count);

封装的方法:

//视频图片临时存放位置public static string filePath{get{return Application.persistentDataPath + "/TempVideo";}}public static string videoPath{get{return GJCNativeShare.filePath + "/" + videoName;}}public static string videoName = "outputVideo.mov";/// <summary>/// 需要将图片保存在filePath文件夹下,然后命名为 i + tv.png,从序号0开始/// 图片的尺寸为 256x256/// 最终在文件目录下得到一个 outputVideo.mov 的文件,这个就是我们需要的视频文件了,可以将这个文件的地址分享出去/// 或者保存到相册中去/// </summary>/// <param name="count"></param>public void CombineImageToVideo(string videoname, int count){// Debug.Log("Native Combine Image to video");#if UNITY_IPHONE && !UNITY_EDITOR_GJC_CombineImageToVideo(filePath + "/", videoname, count);#endif}

添加回调:

private void OnCreateVideoFailed(string result){// Debug.Log("OnCreateVideoFailed: " + result);if (onCreateVideo != null){onCreateVideo("Failed");}}private void OnCreateVideoWork(string result){// Debug.Log("OnCreateVideoWork: " + result);if (onCreateVideo != null){onCreateVideo("Work");}}private void OnCreateVideoSuccess(string result){// Debug.Log("OnCreateVideoSuccess: " + result);if (onCreateVideo != null){onCreateVideo("Success");}}

外部调用:

/// <summary>/// 将固定路径下的图片,合成视频/// </summary>/// <param name="count">传递图片数量</param>/// <param name="cb">回调函数</param>public void CreateVideo(string videoName, int count, OnNativeCallback cb){createVideoCB = cb;if (Application.platform == RuntimePlatform.IPhonePlayer){GJCNativeShare.Instance.CombineImageToVideo(videoName, count);}else{OnCreateVideo("Success");}}

上面GJCNativeShare是我写的接入类,可以参考上面的链接。

我这个是设置的1秒12帧,具体需要多少,可以在代码里面找到这句话

[adaptor appendPixelBuffer:buffer withPresentationTime:CMTimeMake(frame, 12)]

如果需要在某一帧停留长一些,可以将这个图片重复生成一张,插在序列中,这样就能达到目的。我这里的实现方式,是在Unity端先把图片生成好,保存在一个路径下面,我是保存在 Application.persistentDataPath 的一个临时文件夹里面,图片的名字按照规定好的形式命名,然后将路径和图片的数量传递到iOS端,这边将图片文件的读取并且经过合成之后,返回结果(两边保存的视频的名字我这里也是写死的“outputVideo.mov”,可以根据需要,在传递参数到iOS的时候可以增加一个,我是觉得临时弄的,就没加了,看个人需求了)

之后在Unity这边就能拿到这个视频了,可以通过video play加载展现出来,也可以将这个本地视频分享出去。至于分享,如果是利用的原生弹框,只需要将这个视频的本地路径传递进去就好了。如果想分享到Instagram上,可以看我的另一个文章,可以直接分享到Instagram的编辑状态,很好用,传送:分享到Instagram

--------------底线-------------

Unity3D-iOS创建本地视频相关推荐

  1. iOS操作本地视频 - 获取,压缩,取第一帧

    文章目录 一.前言 二.通过PHAsset获取AVURLAsset 2.1 PhotoKit 简介 2.2 AVAsset的简单介绍 2.3 通过PHAsset 获取AVURLAsset 三. 视频压 ...

  2. iOS获取本地视频列表数据

    iOS本地的视频存在于三个地方: iTunes中影片中导入的视频文件 iTunes中通过共享文件导入的视频文件,即应用沙盒 摄像头拍摄的视频文件,可以相册找到 这三处获取视频列表方式不同. iTune ...

  3. ios微信本地视频上传到服务器,小程序 ios上传视频的问题

    微信小程序做了个视频上传的功能,上传视频到七牛云 安卓没有任何问题 ios就有问题了 ios下如果从相册选择视频上传之后提示上传成功了,但是跳转不了页面,但是如果直接拍摄的视频上传之后可以正常跳转页面 ...

  4. ios微信本地视频上传到服务器,ios本地视频wx.uploadFile上传

    //上传视频 uploadVideo:function(){ let _this = this; let list = ['camera', 'album']; wx.showActionSheet( ...

  5. iOS 获取本地相册图片或视频

    1.先判断iOS 相机相册的权限检测 相关链接 https://www.jianshu.com/p/8a944534e0ee 2.iOS 获取本地相册图片 iOS 获取本地相册图片一 iOS 获取本地 ...

  6. Android IOS WebRTC 音视频开发总结(八十七)-- WebRTC中丢包重传NACK实现分析

    Android IOS WebRTC 音视频开发总结(八十七)-- WebRTC中丢包重传NACK实现分析 本文主要介绍WebRTC中丢包重传NACK的实现,作者:weizhenwei ,文章最早发表 ...

  7. 基于声网 iOS SDK 实现视频直播应用

    视频互动直播是当前比较热门的玩法,我们经常见到有PK 连麦.直播答题.一起 KTV.电商直播.互动大班课.视频相亲等.本文将演示如何通过声网视频 SDK 在 iOS 端实现一个视频直播应用.话不多说, ...

  8. [iOS]仿微博视频边下边播之滑动 TableView 自动播放

    注意:框架已经迭代到2.0版本,我重新架构了整个框架,API 也得到了更好的设计,我为 2.0 版本的实现写了一篇文章 [iOS]如何重新架构 JPVideoPlayer ?.此文中的实现思路仍然是一 ...

  9. 基于 ZEGO SDK 实现 iOS 一对一音视频聊天应用

    1 准备环境 在开始集成 ZEGO Express SDK 前,请确保开发环境满足以下要求: Xcode 12.0 或以上版本. iOS 9.0 或以上版本且支持音视频的 iOS 设备. iOS 设备 ...

最新文章

  1. C语言运算符的优先级
  2. 阿里算法,浙大博士带你写项目经历!
  3. IBM 揭晓全球第一项 2纳米芯片技术,为半导体领域实现重大突破
  4. 网页设计上机考试原题_计算机二级考试即将到达战场,各单位准备!!!!
  5. oracle死锁解决常用方法(屡试不爽)
  6. Java 源程序与编译型运行区别
  7. 2013年11月份我国网络不良与垃圾短信息分析报告
  8. 剑指Offer - 面试题58 - II. 左旋转字符串
  9. STM32利用库函数驱动OLED
  10. 数据库每日一题 2020.05.08
  11. java备份mysql的单个表_MySQL 使用java备份某张表的操作
  12. SPF邮件伪造漏洞测试脚本
  13. 香港推广“绿色年宵” 呼吁商贩和市民惜物减废
  14. windos开启IIS管理器
  15. div半透明背景,文字不透明
  16. 什么是电脑pe系统?
  17. 使用AWS Comprehend进行情感分析
  18. python基础:模块的使用——time使用——时间记录器实现
  19. android 开发论坛资源URL
  20. HYS与七夕节大作战 vijos

热门文章

  1. ACM:nbsp;polya定理+hashnbsp;数论题nbsp;pojnbsp;3…
  2. 储种_定活两便_整存整取_and so on
  3. 比较好用的邮箱有哪些?收费邮箱主要哪家好呢?
  4. CS5266单芯片设计Type-C转HDMI+PD3.0+USB3.0 /3.1三合一拓展坞方案|type转HDMI带PD3.0/3.1拓展坞方案介绍
  5. # nest笔记四:文件的上传与下载
  6. 经典的Python爬虫和网络编程面试题
  7. 地球的半径为6400km,一长跑健将9.8s跑了100m,那么他以改速度绕赤道跑一圈,需要几天时间。
  8. 挖Linux中的古老缩略语
  9. Mat 读取数据 及效率对比
  10. UILabel的使用