這里我們要研究直播技術(shù)首先需要對AVFoundation熟悉掌握
AVFoundation拍照和錄制視頻
AVFoundation中提供了很多現(xiàn)成的播放器和錄音機,但是事實上它還有更加底層的內(nèi)容可以供開發(fā)者使用。因為AVFoundation中抽了很多和底層輸入、輸出設(shè)備打交道的類,依靠這些類開發(fā)人員面對的不再是封裝好的音頻播放器AVAudioPlayer、錄音機(AVAudioRecorder)、視頻(包括音頻)播放器AVPlayer,而是輸入設(shè)備(例如麥克風(fēng)、攝像頭)、輸出設(shè)備(圖片、視頻)等。首先了解一下使用AVFoundation做拍照和視頻錄制開發(fā)用到的相關(guān)類:
AVCaptureSession:媒體(音、視頻)捕獲會話,負(fù)責(zé)把捕獲的音視頻數(shù)據(jù)輸出到輸出設(shè)備中。一個AVCaptureSession可以有多個輸入輸出:

AVCaptureDevice:輸入設(shè)備,包括麥克風(fēng)、攝像頭,通過該對象可以設(shè)置物理設(shè)備的一些屬性(例如相機聚焦、白平衡等)。
AVCaptureDeviceInput:設(shè)備輸入數(shù)據(jù)管理對象,可以根據(jù)AVCaptureDevice創(chuàng)建對應(yīng)的AVCaptureDeviceInput對象,該對象將會被添加到AVCaptureSession中管理。
AVCaptureOutput:輸出數(shù)據(jù)管理對象,用于接收各類輸出數(shù)據(jù),通常使用對應(yīng)的子類AVCaptureAudioDataOutput、AVCaptureStillImageOutput、AVCaptureVideoDataOutput、AVCaptureFileOutput,該對象將會被添加到AVCaptureSession中管理。注意:前面幾個對象的輸出數(shù)據(jù)都是NSData類型,而AVCaptureFileOutput代表數(shù)據(jù)以文件形式輸出,類似的,AVCcaptureFileOutput也不會直接創(chuàng)建使用,通常會使用其子類:AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。當(dāng)把一個輸入或者輸出添加到AVCaptureSession之后AVCaptureSession就會在所有相符的輸入、輸出設(shè)備之間建立連接(AVCaptionConnection):

AVCaptureVideoPreviewLayer:相機拍攝預(yù)覽圖層,是CALayer的子類,使用該對象可以實時查看拍照或視頻錄制效果,創(chuàng)建該對象需要指定對應(yīng)的AVCaptureSession對象。
使用AVFoundation拍照和錄制視頻的一般步驟如下:
創(chuàng)建AVCaptureSession對象。
使用AVCaptureDevice的靜態(tài)方法獲得需要使用的設(shè)備,例如拍照和錄像就需要獲得攝像頭設(shè)備,錄音就要獲得麥克風(fēng)設(shè)備。
利用輸入設(shè)備AVCaptureDevice初始化AVCaptureDeviceInput對象。
初始化輸出數(shù)據(jù)管理對象,如果要拍照就初始化AVCaptureStillImageOutput對象;如果拍攝視頻就初始化AVCaptureMovieFileOutput對象。
將數(shù)據(jù)輸入對象AVCaptureDeviceInput、數(shù)據(jù)輸出對象AVCaptureOutput添加到媒體會話管理對象AVCaptureSession中。
創(chuàng)建視頻預(yù)覽圖層AVCaptureVideoPreviewLayer并指定媒體會話,添加圖層到顯示容器中,調(diào)用AVCaptureSession的startRuning方法開始捕獲。
將捕獲的音頻或視頻數(shù)據(jù)輸出到指定文件。
#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;
//設(shè)置攝像頭
AVCaptureDevice * device = [selfcameraWithPosition:AVCaptureDevicePositionFront];
//獲取輸入設(shè)備
AVCaptureDeviceInput * input = [AVCaptureDeviceInput deviceInputWithDevice:device error:&error];
if(error) {
NSLog(@"%@",error);? ??
}
//添加輸入設(shè)備
if([_session canAddInput:input]) {? ? ? ??
[self.sessionaddInput:input];? ?
?}
//獲取輸出設(shè)備
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];
//添加輸出設(shè)備
if([self.sessioncanAddOutput:output]) {? ? ? ?
?[self.sessionaddOutput:output];? ?
?}
//創(chuàng)建瀏覽層,用于展示
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;
}
// 關(guān)鍵方法,捕獲攝像頭每一幀的畫面并編碼
-(void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection {
if(connection == _videoConnection) {//? ? ? ??
[_manager264 encoderToH264:sampleBuffer];
}
if(connection == _audioConnection) {NSLog(@"yy");? ??
}
}
@end