我正在使用AVFoundation并从中获取样本缓冲区AVCaptureVideoDataOutput,我可以使用以下命令将其直接写入videoWriter:
- (void)writeBufferFrame:(CMSampleBufferRef)sampleBuffer {
CMTime lastSampleTime = CMSampleBufferGetPresentationTimeStamp(sampleBuffer);
if(self.videoWriter.status != AVAssetWriterStatusWriting)
{
[self.videoWriter startWriting];
[self.videoWriter startSessionAtSourceTime:lastSampleTime];
}
[self.videoWriterInput appendSampleBuffer:sampleBuffer];
}
Run Code Online (Sandbox Code Playgroud)
我现在要做的是在CMSampleBufferRef中裁剪和缩放图像,而不将其转换为UIImage或CGImageRef,因为这会降低性能.
这是Apple的代码(来自Technical Q&A QA1702),用于从视频缓冲区获取UIImage.不幸的是,返回的图像旋转了90度.如何编辑它以使返回的图像正确定向?
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(imageBuffer, 0);
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
size_t width = CVPixelBufferGetWidth(imageBuffer);
size_t height = CVPixelBufferGetHeight(imageBuffer);
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
CGImageRef quartzImage = CGBitmapContextCreateImage(context);
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
UIImage *image = [UIImage imageWithCGImage:quartzImage];
CGImageRelease(quartzImage);
return (image);
}
Run Code Online (Sandbox Code Playgroud) typedef unsigned char Byte;
...
void ReverseBytes( void *start, int size )
{
Byte *buffer = (Byte *)(start);
for( int i = 0; i < size / 2; i++ ) {
std::swap( buffer[i], buffer[size - i - 1] );
}
}
Run Code Online (Sandbox Code Playgroud)
这个方法现在做的是它在内存中反转字节.我想知道的是,有没有更好的方法来达到同样的效果?整个"尺寸/ 2"部分似乎是一件坏事,但我不确定.
编辑:我刚刚意识到我为这个问题提出的标题有多糟糕,所以我[希望]修复它.
我正在使用PBJVision来实现点击录制视频功能.图书馆不支持方向,所以我正在尝试设计它.从我看到的,旋转视频有三种方法 - 我需要帮助决定最佳前进方式以及如何实现它.请注意,可以在点击到记录段之间进行轮换.因此,在录制会话中,方向被锁定为用户点击按钮时的方向.下次用户点击按钮进行录制时,应将方向重新设置为设备的方向(因此生成的视频显示为正面朝上).
方法1
旋转AVCaptureConnection使用setVideoOrientation:- 这会导致视频预览在每次切换时闪烁,因为这会切换实际的硬件.不酷,不可接受.
方法2transform在AVAssetWriterInput用于编写视频的对象上
设置属性.问题是,一旦资产编写者开始编写,该transform属性就无法更改,因此这仅适用于视频的第一部分.
方法3使用以下内容
旋转附加的图像缓冲区:如何直接在IOS 4中旋转CVImageBuffer图像而不转换为UIImage?但它一直在崩溃,我甚至不确定我是不是正在吠叫正确的树.有一个异常被抛出,我无法真正追溯到比我vImageRotate90_ARGB8888错误地使用该函数的事实.
关于我上面链接的GitHub问题页面的解释稍微详细一些.任何建议都会受到欢迎 - 说实话,我在AVFoundation上并不是很有经验,所以我希望有一些神奇的方法可以做到这一点,我甚至不知道!
我正在制作一个快速的视频应用程序。
在我的应用程序中,我需要裁剪和水平翻转 CVPixelBuffer 并返回类型也是 CVPixelBuffer 的结果。
我尝试了几件事。
首先,我使用了“CVPixelBufferCreateWithBytes”
func resizePixelBuffer(_ pixelBuffer: CVPixelBuffer, destSize: CGSize)
-> CVPixelBuffer?
{
CVPixelBufferLockAddress(pixelBuffer, CVPixelBufferLockFlags(rawValue: O))
let baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer)
let bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer)
let pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer)
let width = CVPixelBufferGetWidth(pixelBuffer)
let height = CVPixelBufferGetHeight(pixelBuffer)
var destPixelBuffer: CVPixelBuffer?
let topMargin = (height - destsize.height) / 2
let leftMargin = (width - destsize.width) / 2 * 4 // bytesPerPixel
let offset = topMargin * bytesPerRow + leftMargin
CVPixelBufferCreateWithBytes(kCFAllocatorDefault,
destSize.width,
destSize.height,
pixelFormat,
baseAddress.advanced(by: offset),
bytesPerRow,
nil, nil, …Run Code Online (Sandbox Code Playgroud) 我目前正在尝试通过首先将其转换为 CVPixelBuffer 然后使用 vImageRotate90_ARGB8888 来转换缓冲区来更改 CMSampleBuffer 的方向。我的代码的问题是当 vImageRotate90_ARGB8888 执行时,它立即崩溃。我知道有答案(比如这个或这个),但是所有这些解决方案在我的情况下都不起作用,我真的找不到任何类型的错误,或者想不出任何会导致这种行为的东西。我当前的代码如下:
- (CVPixelBufferRef)rotateBuffer:(CMSampleBufferRef)sampleBuffer {
CVPixelBufferRef pixelBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
CVPixelBufferLockBaseAddress(pixelBuffer, 0);
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(pixelBuffer);
size_t width = CVPixelBufferGetWidth(pixelBuffer);
size_t height = CVPixelBufferGetHeight(pixelBuffer);
size_t currSize = bytesPerRow * height * sizeof(unsigned char);
size_t bytesPerRowOut = 4 * height * sizeof(unsigned char);
OSType pixelFormat = CVPixelBufferGetPixelFormatType(pixelBuffer);
void *baseAddress = CVPixelBufferGetBaseAddress(pixelBuffer);
unsigned char *outPixelData = (unsigned char *)malloc(currSize);
vImage_Buffer sourceBuffer = {baseAddress, height, width, bytesPerRow};
vImage_Buffer destinationBuffer = {outPixelData, width, height, …Run Code Online (Sandbox Code Playgroud) objective-c ios accelerate-framework cmsamplebuffer cvpixelbuffer