這里我們要研究直播技術首先需要對AVFoundation熟悉掌握
AVFoundation拍照和錄制視頻
AVFoundation中提供了很多現成的播放器和錄音機,但是事實上它還有更加底層的內容可以供開發者使用。因為AVFoundation中抽了很多和底層輸入、輸出設備打交道的類,依靠這些類開發人員面對的不再是封裝好的音頻播放器AVAudioPlayer、錄音機(AVAudioRecorder)、視頻(包括音頻)播放器AVPlayer,而是輸入設備(例如麥克風、攝像頭)、輸出設備(圖片、視頻)等。首先了解一下使用AVFoundation做拍照和視頻錄制開發用到的相關類:
AVCaptureSession:媒體(音、視頻)捕獲會話,負責把捕獲的音視頻數據輸出到輸出設備中。一個AVCaptureSession可以有多個輸入輸出:
AVCaptureDevice:輸入設備,包括麥克風、攝像頭,通過該對象可以設置物理設備的一些屬性(例如相機聚焦、白平衡等)。
AVCaptureDeviceInput:設備輸入數據管理對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,該對象將會被添加到AVCaptureSession中管理。
AVCaptureOutput:輸出數據管理對象,用于接收各類輸出數據,通常使用對應的子類AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,該對象將會被添加到AVCaptureSession中管理。注意:前面幾個對象的輸出數據都是NSData類型,而AVCaptureFileOutput代表數據以文件形式輸出,類似的,AVCcaptureFileOutput也不會直接創建使用,通常會使用其子類:AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。當把一個輸入或者輸出添加到AVCaptureSession之后AVCaptureSession就會在所有相符的輸入、輸出設備之間建立連接(AVCaptionConnection):
AVCaptureVideoPreviewLayer:相機拍攝預覽圖層,是CALayer的子類,使用該對象可以實時查看拍照或視頻錄制效果,創建該對象需要指定對應的AVCaptureSession對象。
使用AVFoundation拍照和錄制視頻的一般步驟如下:
創建AVCaptureSession對象。
使用AVCaptureDevice的靜態方法獲得需要使用的設備,例如拍照和錄像就需要獲得攝像頭設備,錄音就要獲得麥克風設備。
利用輸入設備AVCaptureDevice初始化AVCaptureDeviceInput對象。
初始化輸出數據管理對象,如果要拍照就初始化AVCaptureStillImageOutput對象;如果拍攝視頻就初始化AVCaptureMovieFileOutput對象。
將數據輸入對象AVCaptureDeviceInput、數據輸出對象AVCaptureOutput添加到媒體會話管理對象AVCaptureSession中。
創建視頻預覽圖層AVCaptureVideoPreviewLayer并指定媒體會話,添加圖層到顯示容器中,調用AVCaptureSession的startRuning方法開始捕獲。
將捕獲的音頻或視頻數據輸出到指定文件。
#import"ViewController.h"
#define WIDTH [UIScreen mainScreen].bounds.size.width
#define HEIGHT [UIScreen mainScreen].bounds.size.height
@interfaceViewController()
@property(nonatomic,strong)AVCaptureSession *session;
@property(nonatomic,strong)AVCaptureVideoPreviewLayer *preViewLayer;
@end
@implementationViewController{
AVCaptureConnection *_videoConnection;//輸入輸出建立連接
AVCaptureConnection *_audioConnection;
}
- (void)viewDidLoad {? ?
?[superviewDidLoad];? ?
?[selfinitView];
// Do any additional setup after loading the view, typically from a nib.
}
-(void)initView{
//初始化會話
NSError* error =nil;
self.session= [[AVCaptureSession alloc] init];//? ? ???
self.session.sessionPreset= AVCaptureSessionPresetMedium;
//設置攝像頭
AVCaptureDevice * device = [selfcameraWithPosition:AVCaptureDevicePositionFront];
//獲取輸入設備
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if(error) {
NSLog(@"%@",error);? ??
}
//添加輸入設備
if([_session canAddInput:input]) {? ? ? ??
[self.sessionaddInput:input];? ?
?}
//獲取輸出設備
AVCaptureVideoDataOutput * output = [[AVCaptureVideoDataOutput alloc] init];
dispatch_queue_tqueue = dispatch_queue_create("myQueue",NULL);? ?
?[output setSampleBufferDelegate:selfqueue:queue];? ??
output.videoSettings= [NSDictionarydictionaryWithObject:[NSNumbernumberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarFullRange] forKey:(NSString*)kCVPixelBufferPixelFormatTypeKey];? ?
?output.alwaysDiscardsLateVideoFrames=YES; ??
[selfstartRuning];
//添加輸出設備
if([self.sessioncanAddOutput:output]) {? ? ? ?
?[self.sessionaddOutput:output];? ?
?}
//創建瀏覽層,用于展示
self.preViewLayer= [[AVCaptureVideoPreviewLayer alloc] initWithSession:self.session];
self.preViewLayer.frame= CGRectMake(0,0, WIDTH,500);
self.preViewLayer.videoGravity= AVLayerVideoGravityResizeAspectFill;
//填充模式
[self.view.layeraddSublayer:self.preViewLayer];
//_videoConnection = [output connectionWithMediaType:AVMediaTypeVideo];
}
-(void)startRuning{? ?
?[self.sessionstartRunning];
}
// 選擇是前攝像頭還是后攝像頭
- (AVCaptureDevice *)cameraWithPosition:(AVCaptureDevicePosition) position {
NSArray*devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
for(AVCaptureDevice *device in devices) {
if([device position] == position) {returndevice;? ? ? ?
?}? ??
}return?nil;
}
// 關鍵方法,捕獲攝像頭每一幀的畫面并編碼
-(void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
if(connection == _videoConnection) {//? ? ? ??
[_manager264 encoderToH264:sampleBuffer];
}
if(connection == _audioConnection) {NSLog(@"yy");? ??
}
}
@end