对于如何使用AVAssetWriter快速整理视频?感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解avistreamwrite,并且为您提供关于asp.net-mvc-2–在MVC2中使用
对于如何使用AVAssetWriter快速整理视频?感兴趣的读者,本文将提供您所需要的所有信息,我们将详细讲解avistreamwrite,并且为您提供关于asp.net-mvc-2 – 在MVC 2中使用自定义TextWriter时,“BinaryWrite异常”OutputStream不可用ASP.NET 4、AVAssetWriter AVVideoExpectedSourceFrameRateKey(帧频)已忽略、AVAssetWriter在iOS 14上的压缩过程中创建工件、AVAssetWriter视频数据编码的宝贵知识。
本文目录一览:- 如何使用AVAssetWriter快速整理视频?(avistreamwrite)
- asp.net-mvc-2 – 在MVC 2中使用自定义TextWriter时,“BinaryWrite异常”OutputStream不可用ASP.NET 4
- AVAssetWriter AVVideoExpectedSourceFrameRateKey(帧频)已忽略
- AVAssetWriter在iOS 14上的压缩过程中创建工件
- AVAssetWriter视频数据编码
如何使用AVAssetWriter快速整理视频?(avistreamwrite)
我目前正在制作一个小型应用程序,该程序可以使Mac上的网络摄像头延时播放,将捕获的帧保存为png,并且正在考虑将捕获的帧导出为单个视频。
我使用CGImage处理原始图像,并将它们设置在数组中,但是我不确定从那里开始。根据我自己的研究,我不得不以某种方式使用AVAssetWriter和AVAssetWriterInput。
我在这里浏览了一下,阅读了苹果文档并搜索了谷歌。但是所有指南等都在obj-c中,而不是快捷的,这使得它真的很难理解(因为我没有Obj-C的经验)。
任何帮助将不胜感激。
非常感谢,卢克。
答案1
小编典典我在Swift中解决了同样的问题。从UIImage数组开始,尝试一下(有点长:-),但是可以):
var choosenPhotos: [UIImage] = [] *** your array of UIImages ***var outputSize = CGSizeMake(1280, 720)func build(outputSize outputSize: CGSize) { let fileManager = NSFileManager.defaultManager() let urls = fileManager.URLsForDirectory(.DocumentDirectory, inDomains: .UserDomainMask) guard let documentDirectory: NSURL = urls.first else { fatalError("documentDir Error") } let videoOutputURL = documentDirectory.URLByAppendingPathComponent("OutputVideo.mp4") if NSFileManager.defaultManager().fileExistsAtPath(videoOutputURL.path!) { do { try NSFileManager.defaultManager().removeItemAtPath(videoOutputURL.path!) } catch { fatalError("Unable to delete file: \(error) : \(__FUNCTION__).") } } guard let videoWriter = try? AVAssetWriter(URL: videoOutputURL, fileType: AVFileTypeMPEG4) else { fatalError("AVAssetWriter error") } let outputSettings = [AVVideoCodecKey : AVVideoCodecH264, AVVideoWidthKey : NSNumber(float: Float(outputSize.width)), AVVideoHeightKey : NSNumber(float: Float(outputSize.height))] guard videoWriter.canApplyOutputSettings(outputSettings, forMediaType: AVMediaTypeVideo) else { fatalError("Negative : Can''t apply the Output settings...") } let videoWriterInput = AVAssetWriterInput(mediaType: AVMediaTypeVideo, outputSettings: outputSettings) let sourcePixelBufferAttributesDictionary = [kCVPixelBufferPixelFormatTypeKey as String : NSNumber(unsignedInt: kCVPixelFormatType_32ARGB), kCVPixelBufferWidthKey as String: NSNumber(float: Float(outputSize.width)), kCVPixelBufferHeightKey as String: NSNumber(float: Float(outputSize.height))] let pixelBufferAdaptor = AVAssetWriterInputPixelBufferAdaptor(assetWriterInput: videoWriterInput, sourcePixelBufferAttributes: sourcePixelBufferAttributesDictionary) if videoWriter.canAddInput(videoWriterInput) { videoWriter.addInput(videoWriterInput) } if videoWriter.startWriting() { videoWriter.startSessionAtSourceTime(kCMTimeZero) assert(pixelBufferAdaptor.pixelBufferPool != nil) let media_queue = dispatch_queue_create("mediaInputQueue", nil) videoWriterInput.requestMediaDataWhenReadyOnQueue(media_queue, usingBlock: { () -> Void in let fps: Int32 = 1 let frameDuration = CMTimeMake(1, fps) var frameCount: Int64 = 0 var appendSucceeded = true while (!self.choosenPhotos.isEmpty) { if (videoWriterInput.readyForMoreMediaData) { let nextPhoto = self.choosenPhotos.removeAtIndex(0) let lastFrameTime = CMTimeMake(frameCount, fps) let presentationTime = frameCount == 0 ? lastFrameTime : CMTimeAdd(lastFrameTime, frameDuration) var pixelBuffer: CVPixelBuffer? = nil let status: CVReturn = CVPixelBufferPoolCreatePixelBuffer(kCFAllocatorDefault, pixelBufferAdaptor.pixelBufferPool!, &pixelBuffer) if let pixelBuffer = pixelBuffer where status == 0 { let managedPixelBuffer = pixelBuffer CVPixelBufferLockBaseAddress(managedPixelBuffer, 0) let data = CVPixelBufferGetBaseAddress(managedPixelBuffer) let rgbColorSpace = CGColorSpaceCreateDeviceRGB() let context = CGBitmapContextCreate(data, Int(self.outputSize.width), Int(self.outputSize.height), 8, CVPixelBufferGetBytesPerRow(managedPixelBuffer), rgbColorSpace, CGImageAlphaInfo.PremultipliedFirst.rawValue) CGContextClearRect(context, CGRectMake(0, 0, CGFloat(self.outputSize.width), CGFloat(self.outputSize.height))) let horizontalRatio = CGFloat(self.outputSize.width) / nextPhoto.size.width let verticalRatio = CGFloat(self.outputSize.height) / nextPhoto.size.height //aspectRatio = max(horizontalRatio, verticalRatio) // ScaleAspectFill let aspectRatio = min(horizontalRatio, verticalRatio) // ScaleAspectFit let newSize:CGSize = CGSizeMake(nextPhoto.size.width * aspectRatio, nextPhoto.size.height * aspectRatio) let x = newSize.width < self.outputSize.width ? (self.outputSize.width - newSize.width) / 2 : 0 let y = newSize.height < self.outputSize.height ? (self.outputSize.height - newSize.height) / 2 : 0 CGContextDrawImage(context, CGRectMake(x, y, newSize.width, newSize.height), nextPhoto.CGImage) CVPixelBufferUnlockBaseAddress(managedPixelBuffer, 0) appendSucceeded = pixelBufferAdaptor.appendPixelBuffer(pixelBuffer, withPresentationTime: presentationTime) } else { print("Failed to allocate pixel buffer") appendSucceeded = false } } if !appendSucceeded { break } frameCount++ } videoWriterInput.markAsFinished() videoWriter.finishWritingWithCompletionHandler { () -> Void in print("FINISHED!!!!!") } }) }}
asp.net-mvc-2 – 在MVC 2中使用自定义TextWriter时,“BinaryWrite异常”OutputStream不可用ASP.NET 4
“HttpException”,“OutputStream is not
available when a custom TextWriter is
used.”
<%@ Page Title="" Language="C#" Inherits="System.Web.Mvc.ViewPage" %> <%@ Import Namespace="System.IO" %> <script runat="server"> protected void Page_Load(object sender,EventArgs e) { if (ViewData["Error"] == null) { Response.Buffer = true; Response.Clear(); Response.ContentType = ViewData["DocType"] as string; response.addheader("content-disposition",ViewData["disposition"] as string); Response.CacheControl = "No-cache"; MemoryStream stream = ViewData["DocAsstream"] as MemoryStream; Response.BinaryWrite(stream.ToArray()); Response.Flush(); Response.Close(); } } </script> </script>
视图是从客户端重定向生成的(jquery替换前一页中的位置调用,使用Url.Action帮助程序渲染链接当然).这一切都在一个iframe中.
任何人都有一个想法为什么会发生这种情况?
@H_301_14@解决方法
在您的情况下,您应该创建一个新的ActionResult派生类,其ExecuteResult方法将逻辑封装在Page_Load方法中.您的操作方法应返回您的自定义类的实例,并且调用者将在适当的时候运行ExecuteResult方法.这完全绕过视图引擎,这样可以防止您正在运行的错误,并提供轻微的性能提升.
@H_301_14@ @H_301_14@总结
以上是小编为你收集整理的asp.net-mvc-2 – 在MVC 2中使用自定义TextWriter时,“BinaryWrite异常”OutputStream不可用ASP.NET 4全部内容。
如果觉得小编网站内容还不错,欢迎将小编网站推荐给好友。
AVAssetWriter AVVideoExpectedSourceFrameRateKey(帧频)已忽略
我和我的团队正在尝试通过更改视频帧频来对视频文件进行重新编码,以使其更具“格调”感。我们将以下属性用于AVAssetWriterInput
:
let videoSettings:[String:Any] = [ AVVideoCodecKey: AVVideoCodecH264, AVVideoHeightKey: videoTrack.naturalSize.height, AVVideoWidthKey: videoTrack.naturalSize.width, AVVideoCompressionPropertiesKey: [AVVideoExpectedSourceFrameRateKey: NSNumber(value: 12)] ]
但是输出视频仍以正常帧频播放(使用播放AVPlayer
)。
降低视频帧速率的正确方法是什么? (例如12)。
朝着正确方向的任何帮助都将受到高度重视。 我们卡住了。此致Roi
答案1
小编典典您可以控制附加到每个样品的时间AVAssetWriterInput
直接CMSampleBufferCreateCopyWithNewTiming
。
您需要在CMSampleTimingInfo
提供的时间中调整时间。使用CMSampleBufferGetOutputSampleTimingInfoArray
和检索当前的时间信息,然后遍历每个样本的持续时间,并计算正确的持续时间以每秒获取12帧,并调整演示和解码时间戳以匹配此新的持续时间。然后,您制作副本并将其提供给作者的输入。
假设您有existingSampleBuffer
:
CMSampleBufferRef sampleBufferToWrite = NULL;CMSampleTimingInfo sampleTimingInfo = {0};CMSampleBufferGetSampleTimingInfo(existingSampleBuffer, 0, &sampleTimingInfo);// modify duration & presentationTimeStampsampleTimingInfo.duration = CMTimeMake(1, 12) // or whatever frame rate you desiresampleTimingInfo.presentationTimeStamp = CMTimeAdd(previousPresentationTimeStamp, sampleTimingInfo.duration);previousPresentationTimeStamp = sampleTimingInfo.presentationTimeStamp; // should be initialised before passing here the first timeOSStatus status = CMSampleBufferCreateCopyWithNewTiming(kCFAllocatorDefault, existingSampleBuffer, 1, &sampleTimingInfo, &sampleBufferToWrite);if (status == noErr) { // you can write sampleBufferToWrite}
我在这段代码中做一些假设:
- SampleBuffer仅包含一个样本
- SampleBuffer包含未压缩的视频(否则,您还需要处理decodeTimeStamp)
AVAssetWriter在iOS 14上的压缩过程中创建工件
如何解决AVAssetWriter在iOS 14上的压缩过程中创建工件?
在最新的iOS 14发行版中,我们开始看到 $var->MAX(SL);
实现(以前有效)来压缩mp4文件,开始生成意外的工件。使用相同比特率的完全相同的代码在iOS 13上也能正常工作。此外,我们仅在X系列的某些设备(主要是iPhone Xr和iPhone XS Max)上看到此问题。
有人遇到类似的问题吗?我们目前怀疑这是由于所使用的基础编码器发生更改或错误所致。
AVAssetWriter
解决方法
暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!
如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。
小编邮箱:dio#foxmail.com (将#修改为@)
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:画质级别,与设备相关。
a. P-Baseline Profile:基本画质。支持I/P 帧,只支持无交错(Progressive)和CAVLC;
b. EP-Extended profile:进阶画质。支持I/P/B/SP/SI 帧,只支持无交错(Progressive)和CAVLC;
c. MP-Main profile:主流画质。提供I/P/B 帧,支持无交错(Progressive)和交(Interlaced),也支持CAVLC 和CABAC 的支持;
d. HP-High profile:高级画质。在main Profile 的基础上增加了8×8内部预测、自定义量化、 无损视频编码和更多的YUV 格式;
AVVideoCodecKey:视频的编码方式,这里设置为H.264.
AVVideoWidthKey, AVVideoHeightKey:视频的宽高。
更多的设置可以参考文档:Video Settings | Apple Developer DocumentationNSDictionary *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快速整理视频?和avistreamwrite的分享已经结束,谢谢您的关注,如果想了解更多关于asp.net-mvc-2 – 在MVC 2中使用自定义TextWriter时,“BinaryWrite异常”OutputStream不可用ASP.NET 4、AVAssetWriter AVVideoExpectedSourceFrameRateKey(帧频)已忽略、AVAssetWriter在iOS 14上的压缩过程中创建工件、AVAssetWriter视频数据编码的相关知识,请在本站进行查询。
本文标签: