AVAssetWriter视频数据编码
AVAssetWriter介绍
可以通过AVAssetWriter来对媒体样本重新做编码。
针对一个视频文件,只可以使用一个AVAssetWriter来写入,所以每一个文件都需要对应一个新的AVAssetWriter实例。
AVAssetWriter初始化
使用一个视频文件路径对AVAssetReader进行初始化,并指定文件类型。
NSError * error;
_mAssetWriter = [[AVAssetWriter alloc] initWithURL:videoUrl fileType:AVFileTypeAppleM4V error:&error];
AVAssetWriter设置Input
在写入之前,需要设置Input,与AVAssetReader的Output一样,也可以设置AVAssetWriterInput输入的类型为AVMediaTypeAudio或者AVMediaTypeVideo,以下设置以AVMediaTypeVideo为例。
在设置Input时可以指定output设置,这个设置里主要包含视频参数。
AVVideoCompressionPropertiesKey对应的属性值是编码相关的,比如一下参数:
- AVVideoAverageBitRateKey:视频尺寸*比率,10.1相当于AVCaptureSessionPresetHigh,数值越大,显示越精细(只支持H.264)。
- AVVideoMaxKeyFrameIntervalKey:关键帧最大间隔,若设置1每帧都是关键帧,数值越大压缩率越高(只支持H.264)。
- AVVideoProfileLevelKey:画质级别,与设备相关。
- P-Baseline Profile:基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;
- EP-Extended profile:进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC;
- MP-Main profile:主流画质。提供I/P/B 帧,支持无交错(Progressive)和交(Interlaced),也支持CAVLC 和CABAC 的支持;
- HP-High profile:高级画质。在main Profile 的基础上增加了8×8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;
AVVideoCodecKey:视频的编码方式,这里设置为H.264.
AVVideoWidthKey, AVVideoHeightKey:视频的宽高。
更多的设置可以参考文档:Video Settings | Apple Developer Documentation
NSDictionary *codec_settings = @{AVVideoAverageBitRateKey: @(_bitRate)};
NSDictionary *video_settings = @{AVVideoCodecKey: AVVideoCodecH264,
AVVideoCompressionPropertiesKey: codec_settings,
AVVideoWidthKey: @(1920),
AVVideoHeightKey: @(1080)};
_mAssetWriterInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:video_settings];
针对AVAssetWriterInput还可以设置相应的AVAssetWriterInputPixelBufferAdaptor来接收CVPixelBuffer。
AVAssetWriterInputPixelBufferAdaptor提供了一个CVPixelBufferPoolRef,您可以使用它来分配用于写入输出文件的像素缓冲区。文档中写到使用提供的像素缓冲池进行缓冲区分配通常比附加使用单独池分配的像素缓冲区更有效。
初始化的时候可以设置相关的参数,比如CVPixelBuffer的颜色格式,CPU和GPU的内存共享方式等。
CVPixelBuffer可以由AVAssetWriterInputPixelBufferAdaptor提供的缓冲池创建。
CVOpenGLESTextureCacheRef创建一块专门用于存放纹理的缓冲区,这样每次传递纹理像素数据给GPU时,直接使用这个缓冲区中的内存,避免了重复创建,提高了效率。
NSMutableDictionary * attributes = [NSMutableDictionary dictionary];
attributes[(NSString *) kCVPixelBufferPixelFormatTypeKey] = @(kCVPixelFormatType_32BGRA);
NSDictionary *IOSurface_properties = @{@"IOSurfaceOpenGLESFBOCompatibility": @YES, @"IOSurfaceOpenGLESTextureCompatibility": @YES};
attributes[(NSString *) kCVPixelBufferIOSurfacePropertiesKey] = IOSurface_properties;
_mAssetWriterPixelBufferInput = [AVAssetWriterInputPixelBufferAdaptor assetWriterInputPixelBufferAdaptorWithAssetWriterInput:_mAssetWriterInput
sourcePixelBufferAttributes:attributes];
CVPixelBufferRef renderTarget;
CVOpenGLESTextureCacheRef videoTextureCache;
CVReturn err;
if (videoTextureCache == NULL) {
err = CVOpenGLESTextureCacheCreate(kCFAllocatorDefault, NULL, [EAGLContext currentContext], NULL, & videoTextureCache);
if (err) {
//错误处理
}
}
err = CVPixelBufferPoolCreatePixelBuffer (NULL, [_mAssetWriterPixelBufferInput pixelBufferPool], &renderTarget);
if (err) {
//错误处理
}
//对CVPixelBuffer添加附加信息,做颜色格式的转化
CVBufferSetAttachment(renderTarget,
kCVImageBufferColorPrimariesKey,
kCVImageBufferColorPrimaries_ITU_R_709_2,
kCVAttachmentMode_ShouldPropagate);
CVBufferSetAttachment(renderTarget,
kCVImageBufferYCbCrMatrixKey,
kCVImageBufferYCbCrMatrix_ITU_R_601_4,
kCVAttachmentMode_ShouldPropagate);
CVBufferSetAttachment(renderTarget,
kCVImageBufferTransferFunctionKey,
kCVImageBufferTransferFunction_ITU_R_709_2,
kCVAttachmentMode_ShouldPropagate);
从CVPixelBuffer创建OpenGL的texture,会将renderTarget中的像素数据传输给OpenGL,可以在该texture上的绘制再编码进文件中。
CVOpenGLESTextureRef renderTexture;
err = CVOpenGLESTextureCacheCreateTextureFromImage (kCFAllocatorDefault,
videoTextureCache,
renderTarget,
NULL,
GL_TEXTURE_2D,
GL_RGBA,
[1920],
[1080],
GL_BGRA,
GL_UNSIGNED_BYTE,
0,
& renderTexture);
在写入之前设置好Input,之后调用startWriting方法。
if ([_mAssetWriter canAddInput:_mAssetWriterInput]){
[_mAssetWriter addInput:_mAssetWriterInput];
}
[_mAssetWriter startWriting];
[_mAssetWriter startSessionAtSourceTime:kCMTimeZero];
数据写入
以AVAssetReader读取的sampleBuffer作为输入源来做数据写入,需要处理的异常情况也比较多,注意writer的状态处理。
代码示例
//判断input是否准备好接受新的数据
while (_mAssetWriterInput.isReadyForMoreMediaData)
{
CMSampleBufferRef sampleBuffer = [output copyNextSampleBuffer];
if (sampleBuffer)
{
BOOL error = NO;
if (_reader.status != AVAssetReaderStatusReading || _writer.status != AVAssetWriterStatusWriting)
{
error = YES;
}
if (_videoOutput == output)
{
// update the video progress
_lastSamplePresentationTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
CVPixelBufferRef pixelBuffer = (CVPixelBufferRef)CMSampleBufferGetImageBuffer(sampleBuffer);
if (![_mAssetWriterPixelBufferInput appendPixelBuffer:pixelBuffer withPresentationTime:_lastSamplePresentationTime])
{
error = YES;
}
dispatch_async(dispatch_get_main_queue(), ^{
_progress(CMTimeGetSeconds(_lastSamplePresentationTime) / _duration * 0.8);
});
}
if (error){
return NO;
}
}
else
{
//数据写入完成,标记Input结束
[_mAssetWriterInput markAsFinished];
return NO;
}
}
AVAssetWriter视频数据编码的更多相关文章
- 海思HI35XX之----视频处理单元各通道间的关系
最近在折腾HI3518C的芯片,应用到IPCamera上,最终获取多路不同分辨率的视频流供不同需求的预览切换.此处简单记录一下视频前处理元VPSS(Video Process Sub-System)的 ...
- 用EasyClient开源项目采集Windows摄像头/麦克风的音视频进行RTSP直播
EasyClient是EasyDarwin开源流媒体团队开发的一款功能丰富的开源PC客户端项目,目前支持Windows.Android版本,后续将支持ios版本,其中Windows版本的EasyCli ...
- 音视频开发-FFmpeg
音视频开发是个非常复杂的,庞大的开发话题,初涉其中,先看一下结合 OEIP(开源项目) 新增例子. 可以打开flv,mp4类型文件,以及rtmp协议音视频数据,声音的播放使用SDL. 把采集的麦/声卡 ...
- FFMpeg写MP4文件例子分析
http://blog.csdn.net/eightdegree/article/details/7425811 这段时间看了FFMpeg提供的例子muxing.c,我略微修改了下源代码,使其生成一个 ...
- PS流的格式和解析总结
对于PS流,最近因为工作需要,所以MPEG2中的PS流格式和解包过程进行了学习. 首先我们需要知道PS包流格式是怎么样的: (来自http://blog.csdn.net/chen495810242/ ...
- PS 流格式解析(转)
对于PS流,最近因为工作需要,所以MPEG2中的PS流格式和解包过程进行了学习. 首先我们需要知道PS包流格式是怎么样的: 针对H264 做如下PS 封装:每个IDR NALU 前一般都会包含SPS. ...
- 新手学习FFmpeg - 调用API完成录屏并进行H.264编码
Screen Record H.264 目前在网络传输视频/音频流都一般会采用H.264进行编码,所以尝试调用FFMPEG API完成Mac录屏功能,同时编码为H.264格式. 在上一篇文章中,通过调 ...
- Android NDK 直播推流与引流
本篇介绍一下直播技术中推流与引流的简单实现. 1.流媒体服务器测试 首先利用快直播 app (其他支持 RTMP 推流与引流的 app 亦可)和 ffplay.exe 对流媒体服务器进行测试. 快直播 ...
- FFmpeg开发实战(六):使用 FFmpeg 将YUV数据编码为视频文件
本文中实现的一个小功能是把一个YUV原始视频数据(时间序列图像)经过h264编码为视频码流,然后在使用mp4封装格式封装. 编码&封装的流程图如下: 使用ffmpeg编码流程: 1.首先使用a ...
随机推荐
- vmware vpshere 安装完的必备工作
1:例如:vCenter计算机地址为:192.168.0.200, 访问地址:https://192.168.0.200,安装证书: 参考教程:https://blog.csdn.net/cooljs ...
- Nebula Graph 的 Ansible 实践
本文首发于 Nebula Graph 公众号 NebulaGraphCommunity,Follow & 看大厂图数据库技术实践 背景 在 Nebula-Graph 的日常测试中,我们会经常在 ...
- 爬虫:HTTP请求与HTML解析(爬取某乎网站)
1. 发送web请求 1.1 requests 用requests库的get()方法发送get请求,常常会添加请求头"user-agent",以及登录"cookie&q ...
- .NET平台系列9 .NET Core 3.0 / .NET Core 3.1 详解
系列目录 [已更新最新开发文章,点击查看详细] .NET Core 3.0 于 2019年9月23日发布,重点是增加对同时支持使用 Windwos Forms.WPF 和 Entity Frm ...
- 对spring创建对象时为何要使用接口
对spring创建对象时为何要使用接口,而使用接口的实现类会报错 接上一篇问题的解答:Spring AOP获取不了增强类(额外方法)和无法通过getBean()获取对象 此问题发生在动态代理时,比如对 ...
- [项目] 淘淘商城 Part.1
电商 市场 2013:79万笔/分钟 2014:13.4万亿,双11支付宝交易峰值285万笔/分钟 2015:50万亿 技术特点 一个Tomcat:500并发 分布式:上万并发 高并发.集群.负载均衡 ...
- IDEA 打包和导入 Jar 包
Jar 包介绍 Jar 包 ( Java Archive,Java 归档文件) 是与平台无关的压缩文件格式,它允许将多个 Java 源文件编译生成的 class 文件(即字节码文件)打包成一个压缩文件 ...
- Lua中的元表(metatable)、元方法(metamethod)详解
在第一次看见这两样东西的时候,可能会觉得它很深奥,但其实很好理解,虽然实际上它可能真的很深奥.(小若:停!滚粗.) 1.知道为什么1 + 1 = 2吗? 为什么在Lua中,1+1会等于2呢?(小若:难 ...
- 【Java】Jackson解析xml的坑
为了获取xml数据,在spring mvc中针对 @ResponseBody配置了jackson. 刚用的时候内心是狂喜的,终于不用自己解析了---- but----------还是有坑的-- 坑一 ...
- 手机POS机
资质查询 http://www.pbc.gov.cn/zhengwugongkai/127924/128041/2951606/1923625/1923629/d6d180ae/index4.html ...