iOS相機開發的踩坑篇
相機的設置,這個demo用GPUImageview為基準,做了一個基礎的demo,處理了供底層OpenGL的方向處理,其他功能參考 最后的參考鏈接可以實現。
ps:2016年整年基本上都是做avfoundation的開發,自我感覺對蘋果這套庫應該算是蠻了解了,網上的例子也很多,但是深入了解后發現很多其實坑很多,這篇分享主要是和大家介紹一下坑和難點,基本的用法可以看一下參考鏈接和下面的圖。
一. 整體架構
這里有一個很大的問題,就是屏幕旋轉。現在大部分視頻或者直播軟件我觀察了一下基本上是不支持轉動手機方向的。這個的選擇會影響整套架構。相應難度也會降低很多。很悲催地我們一開始就要求四個方向。
錄制架構,之前我使用的都是AVFoundation的AVWritter自己寫的,后來發現有一個很大的問題。就是做美顏的時候,錄制又會有問題。后來干脆用了GPUMovieWritter去錄制。這里自帶了音頻錄制。
GPUImageVideoCamera這個大家用的時候建議是繼承一個自己寫,最起碼要看看源碼,這個定制的化的東西太多了。并且之后設置慢動作等問題不方便。所以這個我沒有用。用了AVFoundation自己的褲,然后模仿這里面的旋轉等做了一下openGL的處理。
根據上訴所說,我們來整理一下流程:
二. 視頻錄制
1. 視頻參數設置
這里是很核心的配置參數,要配合 StreamEye 以及相機捕捉去看自己的錄制和系統錄制的區別,主要是qa,清晰度等。
碼率的觀看可以用蘋果自帶的相機軟件,然后用Alt+I快捷鍵彈出一個信息看碼率。
千萬不要用airdrop傳文件到電腦,會導致重新編碼。用蘋果應用程序里面的相機捕捉工具就可以很好看的去看了。
以上幾點都是無數實踐的踩坑。大家一定要注意,相應參數的設置錯誤,會導致如果同樣是4k的錄制,那么你錄制的達不到30fps,或者要比系統的錄制大小占用空間大很多。下面我提供了一個參考設置,都是經過和系統對比還有實踐出來的一些參數。如果有錯誤,請大家在評論下方告知我,或者加入qq群237305299,不甚感激。
NSDictionary *videoCompressionProps;
NSDictionary *videoSettings;
switch (cameraModel.videoResolution) {
case AVCaptureSessionPreset3840x2160:
videoCompressionProps = @{
AVVideoAverageBitRateKey:@(50*1024.0*1024),
AVVideoH264EntropyModeKey:AVVideoH264EntropyModeCABAC,
AVVideoMaxKeyFrameIntervalKey:@(30),
AVVideoAllowFrameReorderingKey:@NO,
AVVideoExpectedSourceFrameRateKey:@30,
};
break;
case AVCaptureSessionPreset1920x1080:
videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:18*1024.0*1024], AVVideoAverageBitRateKey,
AVVideoH264EntropyModeCABAC,AVVideoH264EntropyModeKey,
nil];
break;
case AVCaptureSessionPreset1280x720:
videoCompressionProps = [NSDictionary dictionaryWithObjectsAndKeys:
[NSNumber numberWithDouble:8*1024.0*1024], AVVideoAverageBitRateKey,
AVVideoH264EntropyModeCABAC,AVVideoH264EntropyModeKey,
nil ];
break;
default:
break;
}
videoSettings = [NSDictionary dictionaryWithObjectsAndKeys:
AVVideoCodecH264,AVVideoCodecKey,
videoCompressionProps, AVVideoCompressionPropertiesKey,
AVVideoScalingModeResizeAspectFill,AVVideoScalingModeKey,
[NSNumber numberWithInteger:videoSize.width],AVVideoWidthKey,
[NSNumber numberWithInteger:videoSize.height],AVVideoHeightKey,
nil];
self.writerInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:videoSettings];
if(cameraModel.devicePosition == DJIIPhone_DevicePositionFront){
self.writerInput.transform = [OSMOMediaUtils getAngleTransformFromScreenOritationFront];
}else{
self.writerInput.transform = [OSMOMediaUtils getAngleTransformFromScreenOritationBack];
}
self.writerInput.expectsMediaDataInRealTime = YES;
2. 錄制方向
給AVWritter設置一個初始化的Transform,從攝像頭過來的CMSampleBuffer直接進入錄制流,不要去做屏幕流程。因為不這樣的化會出現一個問題。
你點擊錄制視頻,這過程中去旋轉屏幕,當你支持四個方向的時候,旋轉的時候就會出現閃爍。具體可以用蘋果自己的相機試一下就一清二楚了。
四. GPU美顏處理后用CVPixBuffer編碼直播
- GPU美顏處理
錯誤處理方法:
CGSize outputSize = {720, 1280};
GPUImageRawDataOutput *rawDataOutput = [[GPUImageRawDataOutput alloc] initWithImageSize:CGSizeMake(outputSize.width, outputSize.height) resultsInBGRAFormat:YES];
[self.beautifyFilter addTarget:rawDataOutput];
將rawDataoutput作為Target加入,然后獲取pixbuffer給videotoolbox處理
__weak GPUImageRawDataOutput *weakOutput = rawDataOutput;
__weak typeof(self) weakSelf = self;
[rawDataOutput setNewFrameAvailableBlock:^{
__strong GPUImageRawDataOutput *strongOutput = weakOutput;
[strongOutput lockFramebufferForReading];
// 這里就可以獲取到添加濾鏡的數據了
GLubyte *outputBytes = [strongOutput rawBytesForImage];
NSInteger bytesPerRow = [strongOutput bytesPerRowInOutput];
CVPixelBufferRef pixelBuffer = NULL;
CVPixelBufferCreateWithBytes(kCFAllocatorDefault, outputSize.width, outputSize.height, kCVPixelFormatType_32BGRA, outputBytes, bytesPerRow, nil, nil, nil, &pixelBuffer);
// 之后可以利用VideoToolBox進行硬編碼再結合rtmp協議傳輸視頻流了
[weakSelf encodeWithCVPixelBufferRef:pixelBuffer];
[strongOutput unlockFramebufferAfterReading];
CFRelease(pixelBuffer);
}];
```
大家可以看一下為什么我不推薦這種方法,CVPixelBufferCreateWithBytes這里是很耗時的,要重新創建。
**正確處理方法:**
正確的方法建議大家看一下GPUFrameBuffer,里面有一個renderTarget,加一個類別去獲取renderTarget(CVPixBuffer),我們取出來的時候lock一下,用完unlock一下就好了。
## 五. 慢動作
[慢動作設置](//https://developer.apple.com/library/mac/documentation/AVFoundation/Reference/AVCaptureDevice_Class/index.html),這里的技術原理實則以指定超過60fps去執行一個錄制,比如240fps,然后將240fps按照30fps去寫入數據填充時間段,所以就有了慢動作效果。下面的代碼是設置最大速度。
```objc
-(void)configureCameraForHighestFrameRate:(AVCaptureDevice*) device
{
AVCaptureDeviceFormat *bestFormat = nil;
AVFrameRateRange *bestFrameRateRange = nil;
for(AVCaptureDeviceFormat *format in [device formats] ) {
for ( AVFrameRateRange *range in format.videoSupportedFrameRateRanges ) {
if ( range.maxFrameRate > bestFrameRateRange.maxFrameRate ) {
bestFormat = format;
bestFrameRateRange = range;
}
}
}
if ( bestFormat ) {
if ( [device lockForConfiguration:NULL] == YES ) {
device.activeFormat = bestFormat;
device.activeVideoMinFrameDuration = bestFrameRateRange.minFrameDuration;
device.activeVideoMaxFrameDuration = bestFrameRateRange.minFrameDuration;
[device unlockForConfiguration];
}
}
}
六. 延時攝影
由于系統是每秒回調30次,那么現在我們自己定時器每秒取一張圖,然后利用 AVAssetWriterInputPixelBufferAdaptor 和 AVAssetWriterInput ,還有 AVAssetWriter 去用圖片組幀視頻。
七. 星軌拍攝
利用GPUBlenderFilter的雙輸入通道即可,疊加加上。生成照片之前記得把濾鏡useNextCapture.
六. 參考鏈接
-
用來拍照和錄像的官方demo https://developer.apple.com/library/prerelease/content/samplecode/AVCam/Introduction/Intro.html
-
蘋果官方的關于拍照錄像的一個綜合性的demo,我也是參照這個做的 https://developer.apple.com/library/prerelease/content/samplecode/AVCamManual/Introduction/Intro.html
-
GPU直播 iOS中為直播APP集成美顏功能
-
錄制視頻,分段錄制 github地址
-
擴展GPU支持視頻錄制暫停和恢復.支持閃關燈開啟和關閉. GPUImageExtend
-
使用 AVAssetWriter 錄制小視頻,聲音的錄制也在里面 使用 AVAssetWriter 錄制小視頻,
來自:http://www.iosxxx.com/blog/2017-01-15-iOS相機開發的踩坑篇.html