• 需求

    公司混合开发,uni端拍小视频不是很理想,为达到仿微信效果,原生插件走起

  • 思路

    第1步:1个AVCaptureSession, 1块AVCaptureVideoPreviewLayer[考虑兼容替换成AVPreView]

    第2步:视频录制需video & audio, 需要对应的AVCaptureDeviceInput,同理对应的AVCaptureVideoDataOutput与AVCaptureAudioDataOutput

    第3步:代理中设置output区分video与audio, 并将对应的CMSampleBufferRef写入到视频文件中

    第4步:写入视频文件中,用到AVAssetWriter, 对应video & audio 需两个AVAssetWriterInput, 加入AVAssetWriter

    第5步:CMSampleBufferRef不断过来,AssetWriter不断写入,直到停止

  • 上菜

    第一步的初始化就不写了,没事可以翻看本人前面的博客

    第2步:两个AVCaptureDeviceInput 两个Output, 且设置Output的代理

    self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error];
    if (error) {
    NSLog(@"取得设备摄入videoInput对象时出错, 错误原因: %@", error);
    return;
    } // 设备添加到会话中
    if ([self.session canAddInput:self.videoInput]) {
    [self.session addInput:self.videoInput];
    } [self.videoOutput setSampleBufferDelegate:self queue:self.videoQueue];
    if ([self.session canAddOutput:self.videoOutput]) {
    [self.session addOutput:self.videoOutput];
    } // 音频相关
    AVCaptureDevice *adevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
    self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:adevice error:&error]; if ([self.session canAddInput:self.audioInput]) {
    [self.session addInput:self.audioInput];
    } [self.audioOutput setSampleBufferDelegate:self queue:self.videoQueue];
    if ([self.session canAddOutput:self.audioOutput]) {
    [self.session addOutput:self.audioOutput];
    } // 视频输出
    - (AVCaptureVideoDataOutput *)videoOutput {
    if (!_videoOutput) {
    _videoOutput = [[AVCaptureVideoDataOutput alloc] init];
    _videoOutput.alwaysDiscardsLateVideoFrames = YES;
    }
    return _videoOutput;
    } // 音频输出
    - (AVCaptureAudioDataOutput *)audioOutput {
    if (!_audioOutput) {
    _audioOutput = [[AVCaptureAudioDataOutput alloc] init];
    }
    return _audioOutput;
    }

    第3步:启动Session,代理里面操作CMSampleBufferRef

    #pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate & AVCaptureAudioDataOutputSampleBufferDelegate
    - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
    @autoreleasepool {
    // 视频
    if (connection == [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]) {
    if (!self.manager.outputVideoFormatDescription) {
    @synchronized(self) {
    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
    self.manager.outputVideoFormatDescription = formatDescription;
    }
    } else {
    @synchronized(self) {
    if (self.manager.state == StateRecording) {
    [self.manager appendBuffer:sampleBuffer type:AVMediaTypeVideo];
    }
    }
    }
    } //音频
    if (connection == [self.audioOutput connectionWithMediaType:AVMediaTypeAudio]) {
    if (!self.manager.outputAudioFormatDescription) {
    @synchronized(self) {
    CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer);
    self.manager.outputAudioFormatDescription = formatDescription;
    }
    }
    @synchronized(self) {
    if (self.manager.state == StateRecording) {
    [self.manager appendBuffer:sampleBuffer type:AVMediaTypeAudio];
    }
    }
    }
    }
    }

    第4步:AVAssetWriter以及对应的Input

    // writer初始化
    self.writer = [AVAssetWriter assetWriterWithURL:_videoUrl fileType:AVFileTypeMPEG4 error:nil]; _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:_videoSettings];
    //expectsMediaDataInRealTime 必须设为yes,需要从capture session 实时获取数据
    _videoInput.expectsMediaDataInRealTime = YES; _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:_audioSettings];
    _audioInput.expectsMediaDataInRealTime = YES; if ([_writer canAddInput:_videoInput]) {
    [_writer addInput:_videoInput];
    }
    if ([_writer canAddInput:_audioInput]) {
    [_writer addInput:_audioInput];
    }

    第5步:第3步的CMSampleBufferRef通过AVAssetWriter写入到视频文件中

    - (void)appendBuffer:(CMSampleBufferRef)buffer type:(NSString *)mediaType {
    if (buffer == NULL) {
    NSLog(@"empty sampleBuffer");
    return;
    } @synchronized (self) {
    if (self.state < StateRecording) {
    NSLog(@"not ready yet");
    return;
    }
    } CFRetain(buffer);
    dispatch_async(self.queue, ^{
    @autoreleasepool {
    @synchronized (self) {
    if (self.state > StateFinish) {
    CFRelease(buffer);
    return;
    }
    } if (!self.canWrite && mediaType == AVMediaTypeVideo) {
    [self.writer startWriting];
    [self.writer startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(buffer)];
    self.canWrite = YES;
    } if(!self.timer) {
    dispatch_async(dispatch_get_main_queue(), ^{
    self.timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(updateProgress) userInfo:nil repeats:YES];
    [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode];
    });
    } // 写入视频数据
    if (mediaType == AVMediaTypeVideo) {
    if (self.videoInput.readyForMoreMediaData) {
    BOOL success = [self.videoInput appendSampleBuffer:buffer];
    if (!success) {
    @synchronized (self) {
    [self stop:^{}];
    [self destroy];
    }
    }
    }
    } // 写入音频数据
    if (mediaType == AVMediaTypeAudio) {
    if (self.audioInput.readyForMoreMediaData) {
    BOOL success = [self.audioInput appendSampleBuffer:buffer];
    if (!success) {
    @synchronized (self) {
    [self stop:^{}];
    [self destroy];
    }
    }
    }
    }
    CFRelease(buffer);
    }
    });
    }
  • 写在末尾:

    1. AVAssetWriterInput设置视频属性时,按照自己的需要设计,其中码率与帧率的设置会影响到拍摄后视频的质量与大小,具体看各自项目的要求

    2. 如果视频视角存在问题,可以从三个方向入手调整

      1.layer的connect设置下videoOrientation

      2.AVCaptureOutput的connect设置下videoOrientation

      3.AVAssetWriterInput针对video是设置下transform,比如Rotation M_PI/2 角度

iOS拍个小视频的更多相关文章

  1. IOS版微信小视频导出方法

    1.在电脑上连接手机,打开iTools 选择 应用-应用-文件共享. 2.依次打开/Library/WechatPrivate/6e2809aac61608de6a6cc55d9570d25b/Sig ...

  2. [iOS]手把手教你实现微信小视频

    本文个人原创,转载请注明出处,谢谢. 前段时间项目要求需要在聊天模块中加入类似微信的小视频功能,这边博客主要是为了总结遇到的问题和解决方法,希望能够对有同样需求的朋友有所帮助. 效果预览: 这里先罗列 ...

  3. ios设备突破微信小视频6S限制的方法

    刷微信朋友圈只发文字和图片怎能意犹未竟,微信小视频是一个很好的补充,音视频到位,流行流行最流行.但小视频时长不能超过6S,没有滤镜等是很大的遗憾.but有人突破限制玩出了花样,用ios设备在朋友圈晒出 ...

  4. Android 仿微信朋友圈拍小视频上传到服务器

    这个接上一个写的实现拍小视频和传到服务器的  界面是这个样子滴. 我也知不知道怎么给图片搞小一点o(╯□╰)o 布局文件是这样的[认真脸] <?xml version="1.0&quo ...

  5. iOS微信小视频优化心得

    小视频是微信6.0版本重大功能之一,在开发过程中遇到不少问题.本文先叙述小视频的产品需求,介绍了几个实现方案,分析每个方案的优缺点,最后总结出最优的解决方案. 小视频播放需求 可以同时播放多个视频 用 ...

  6. iOS燃烧动画、3D视图框架、天气动画、立体相册、微信朋友圈小视频等源码

    iOS精选源码 iOS天气动画,包括太阳,云,雨,雷暴,雪动画. 较为美观的多级展开列表 3D立体相册,可以旋转的立方体 一个仪表盘Demo YGDashboardView 一个基于UIScrollV ...

  7. 如何保存微信的小视频 How to keep WeChat 'Sights'

    微信小视频非常方便,但很难将其下载到本地电脑长期保存.网上有介绍方法,如百度经验上办法,但目前看来它可能只适用安卓系统,而且或已失效(可能由于版本更新).对Windows Phone无效,而对于更加封 ...

  8. 利用ffmpeg给小视频结尾增加logo水印

    背景 1.app有类似微信拍摄小视频功能,时长上限8s,视频文件保存在第三方云存储,app直接上传,后端数据库只记录视频的存放地址. 2.最近一次功能迭代,增加了小视频下载功能,小视频有可能在别的社交 ...

  9. 微信小视频复制到手机本地Android APP 分享

    因为需要将拍的宝宝的微信小视频上传到亲宝宝软件,每次去手动找文件比较麻烦,所以做了个微信视频复制到手机本地的APP,做工虽然粗糙,但是绝对实用, 下载地址 http://pan.baidu.com/s ...

随机推荐

  1. idea使用maven的打包工具package不会打上主类解决方法

  2. Educational Codeforces Round 41

    Educational Codeforces Round 41  D. Pair Of Lines 考虑先把凸包找出来,如果凸包上的点数大于\(4\)显然不存在解,小于等于\(2\)必然存在解 否则枚 ...

  3. Codeforces301D. Yaroslav and Divisors

    题意:2e5的全排列 每次询问一个区间有多少对数 满足一个数是另一个数的倍数 题解:考虑离线来做 看到有个说法说 在处理有两种约束的问题时 一般用数据结构边插入边询问的方式 这个题正是如此 我们用su ...

  4. BZOJ2555 SubString【SAM + Link Cut Tree】

    BZOJ2555. SubString 要求在线询问一个串在原串中出现的次数,并且可以在原串末尾添加字符串 如果没有修改的话,考虑建出\(parent\)树之后统计每个\(endpos\)节点的\(r ...

  5. 矩阵树定理(Kirchhoff || Laplace)初探——Part 1(无向图计数)

    必备知识: 高斯消元,图论基本知识(好像就这...(雾)) 这里是无向图部分,请不要走错场... 定义 我们将邻接矩阵定义为矩阵\(A(u,v)\),我想邻接矩阵就不用再多说了: 我们将每个点的度数矩 ...

  6. gym100923C. Por Costel and Bujor (高斯消元)

    题意:简化一下 就是解N个 系数矩阵一样 等式右边列矩阵不一样的方程组 题解:系数矩阵一样 为什么我却毫无办法???? 其实只要把等式右边的矩阵都排在后面就好了啊 就变成解一个N x 2N的方程组了 ...

  7. 【poj 1284】Primitive Roots(数论--欧拉函数 求原根个数){费马小定理、欧拉定理}

    题意:求奇质数 P 的原根个数.若 x 是 P 的原根,那么 x^k (k=1~p-1) 模 P 为1~p-1,且互不相同. (3≤ P<65536) 解法:有费马小定理:若 p 是质数,x^( ...

  8. 迪杰斯特拉+拆点 Deliver the Cake - HDU 6805

    题意: t组输入,给你n个点m条边.你需要输出从s点到t点的最短距离,然后是m条边,每条边输入信息为: a,b,c 表示从a点到b点的一个无向边长度为c 每一个点会有一个属性L.R或M 如果a和b一个 ...

  9. Codeforces Round #582 (Div. 3) F. Unstable String Sort

    传送门 题意: 你需要输出一个长度为n的字符序列(由小写字母组成),且这个字符串中至少包含k个不同的字符.另外题目还有要求:给你两个长度为p和q的序列,设字符序列存在s中 那么就会有s[Pi]< ...

  10. 记录一些Python中不常用但非常好用的函数

    zfill(): 方法返回指定长度的字符串,原字符串右对齐,前面填充0. print('Helloworld'.zfill(50))0000000000000000000000000000000000 ...