在看這篇之前,如果您還不了解直播原理,請查看這篇文章如何快速的開發一個完整的iOS直播app(原理篇)
開發一款直播app,首先需要采集主播的視頻和音頻,然后傳入流媒體服務器,本篇主要講解如何采集主播的視頻和音頻,當前可以切換前置后置攝像頭和焦點光標,但是美顏功能還沒做,可以看見素顏的你,后續還會有直播的其他功能文章陸續發布。
如果喜歡我的文章,可以關注我微博:袁崢Seemygo,也可以來小碼哥,了解下我們的iOS培訓課程。后續還會更新更多內容,有任何問題,歡迎簡書留言袁崢Seemygo。。。
為了采集效果圖,我也是豁出去了,請忽略人物,關注技術。
忽略本人.pngAVFoundation: 音視頻數據采集需要用AVFoundation框架.
AVCaptureDevice:硬件設備,包括麥克風、攝像頭,通過該對象可以設置物理設備的一些屬性(例如相機聚焦、白平衡等)
AVCaptureDeviceInput:硬件輸入對象,可以根據AVCaptureDevice創建對應的AVCaptureDeviceInput對象,用于管理硬件輸入數據。AVCaptureOutput:硬件輸出對象,用于接收各類輸出數據,通常使用對應的子類AVCaptureAudioDataOutput(聲音數據輸出對象)、AVCaptureVideoDataOutput(視頻數據輸出對象)AVCaptionConnection:當把一個輸入和輸出添加到AVCapturesession之后,AVCaptureSession就會在輸入、輸出設備之間建立連接,而且通過AVCaptureOutput可以獲取這個連接對象。AVCaptureVideoPReviewLayer:相機拍攝預覽圖層,能實時查看拍照或視頻錄制效果,創建該對象需要指定對應的AVCaptureSession對象,因為AVCaptureSession包含視頻輸入數據,有視頻數據才能展示。AVCaptureSession: 協調輸入與輸出之間傳輸數據系統作用:可以操作硬件設備工作原理:讓App與系統之間產生一個捕獲會話,相當于App與硬件設備有聯系了, 我們只需要把硬件輸入對象和輸出對象添加到會話中,會話就會自動把硬件輸入對象和輸出產生連接,這樣硬件輸入與輸出設備就能傳輸音視頻數據。現實生活場景:租客(輸入錢),中介(會話),房東(輸出房),租客和房東都在中介登記,中介就會讓租客與房東之間產生聯系,以后租客就能直接和房東聯系了。// 捕獲音視頻- (void)setupCaputureVideo{ // 1.創建捕獲會話,必須要強引用,否則會被釋放 AVCaptureSession *captureSession = [[AVCaptureSession alloc] init]; _captureSession = captureSession; // 2.獲取攝像頭設備,默認是后置攝像頭 AVCaptureDevice *videoDevice = [self getVideoDevice:AVCaptureDevicePositionFront]; // 3.獲取聲音設備 AVCaptureDevice *audioDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; // 4.創建對應視頻設備輸入對象 AVCaptureDeviceInput *videoDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:nil]; _currentVideoDeviceInput = videoDeviceInput; // 5.創建對應音頻設備輸入對象 AVCaptureDeviceInput *audioDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:audioDevice error:nil]; // 6.添加到會話中 // 注意“最好要判斷是否能添加輸入,會話不能添加空的 // 6.1 添加視頻 if ([captureSession canAddInput:videoDeviceInput]) { [captureSession addInput:videoDeviceInput]; } // 6.2 添加音頻 if ([captureSession canAddInput:audioDeviceInput]) { [captureSession addInput:audioDeviceInput]; } // 7.獲取視頻數據輸出設備 AVCaptureVideoDataOutput *videoOutput = [[AVCaptureVideoDataOutput alloc] init]; // 7.1 設置代理,捕獲視頻樣品數據 // 注意:隊列必須是串行隊列,才能獲取到數據,而且不能為空 dispatch_queue_t videoQueue = dispatch_queue_create("Video Capture Queue", DISPATCH_QUEUE_SERIAL); [videoOutput setSampleBufferDelegate:self queue:videoQueue]; if ([captureSession canAddOutput:videoOutput]) { [captureSession addOutput:videoOutput]; } // 8.獲取音頻數據輸出設備 AVCaptureAudioDataOutput *audioOutput = [[AVCaptureAudioDataOutput alloc] init]; // 8.2 設置代理,捕獲視頻樣品數據 // 注意:隊列必須是串行隊列,才能獲取到數據,而且不能為空 dispatch_queue_t audioQueue = dispatch_queue_create("Audio Capture Queue", DISPATCH_QUEUE_SERIAL); [audioOutput setSampleBufferDelegate:self queue:audioQueue]; if ([captureSession canAddOutput:audioOutput]) { [captureSession addOutput:audioOutput]; } // 9.獲取視頻輸入與輸出連接,用于分辨音視頻數據 _videoConnection = [videoOutput connectionWithMediaType:AVMediaTypeVideo]; // 10.添加視頻預覽圖層 AVCaptureVideoPreviewLayer *previedLayer = [AVCaptureVideoPreviewLayer layerWithSession:captureSession]; previedLayer.frame = [UIScreen mainScreen].bounds; [self.view.layer insertSublayer:previedLayer atIndex:0]; _previedLayer = previedLayer; // 11.啟動會話 [captureSession startRunning];}// 指定攝像頭方向獲取攝像頭- (AVCaptureDevice *)getVideoDevice:(AVCaptureDevicePosition)position{ NSArray *devices = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo]; for (AVCaptureDevice *device in devices) { if (device.position == position) { return device; } } return nil;}#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate// 獲取輸入設備數據,有可能是音頻有可能是視頻- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection{ if (_videoConnection == connection) { NSLog(@"采集到視頻數據"); } else { NSLog(@"采集到音頻數據"); }}視頻采集額外功能一(切換攝像頭)
切換攝像頭步驟1.獲取當前視頻設備輸入對象2.判斷當前視頻設備是前置還是后置3.確定切換攝像頭的方向4.根據攝像頭方向獲取對應的攝像頭設備5.創建對應的攝像頭輸入對象6.從會話中移除之前的視頻輸入對象7.添加新的視頻輸入對象到會話中// 切換攝像頭- (IBAction)toggleCapture:(id)sender { // 獲取當前設備方向 AVCaptureDevicePosition curPosition = _currentVideoDeviceInput.device.position; // 獲取需要改變的方向 AVCaptureDevicePosition togglePosition = curPosition == AVCaptureDevicePositionFront?AVCaptureDevicePositionBack:AVCaptureDevicePositionFront; // 獲取改變的攝像頭設備 AVCaptureDevice *toggleDevice = [self getVideoDevice:togglePosition]; // 獲取改變的攝像頭輸入設備 AVCaptureDeviceInput *toggleDeviceInput = [AVCaptureDeviceInput deviceInputWithDevice:toggleDevice error:nil]; // 移除之前攝像頭輸入設備 [_captureSession removeInput:_currentVideoDeviceInput]; // 添加新的攝像頭輸入設備 [_captureSession addInput:toggleDeviceInput]; // 記錄當前攝像頭輸入設備 _currentVideoDeviceInput = toggleDeviceInput;}視頻采集額外功能二(聚焦光標)
聚焦光標步驟1.監聽屏幕的點擊2.獲取點擊的點位置,轉換為攝像頭上的點,必須通過視頻預覽圖層(AVCaptureVideoPreviewLayer)轉3.設置聚焦光標圖片的位置,并做動畫4.設置攝像頭設備聚焦模式和曝光模式(注意:這里設置一定要鎖定配置lockForConfiguration,否則報錯)// 點擊屏幕,出現聚焦視圖- (void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{ // 獲取點擊位置 UITouch *touch = [touches anyObject]; CGPoint point = [touch locationInView:self.view]; // 把當前位置轉換為攝像頭點上的位置 CGPoint cameraPoint = [_previedLayer captureDevicePointOfInterestForPoint:point]; // 設置聚焦點光標位置 [self setFocusCursorWithPoint:point]; // 設置聚焦 [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];}/** * 設置聚焦光標位置 * * @param point 光標位置 */-(void)setFocusCursorWithPoint:(CGPoint)point{ self.focusCursorImageView.center=point; self.focusCursorImageView.transform=CGAffineTransformMakeScale(1.5, 1.5); self.focusCursorImageView.alpha=1.0; [UIView animateWithDuration:1.0 animations:^{ self.focusCursorImageView.transform=CGAffineTransformIdentity; } completion:^(BOOL finished) { self.focusCursorImageView.alpha=0; }];}/** * 設置聚焦 */-(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{ AVCaptureDevice *captureDevice = _currentVideoDeviceInput.device; // 鎖定配置 [captureDevice lockForConfiguration:nil]; // 設置聚焦 if ([captureDevice isFocusModeSupported:AVCaptureFocusModeAutoFocus]) { [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus]; } if ([captureDevice isFocusPointOfInterestSupported]) { [captureDevice setFocusPointOfInterest:point]; } // 設置曝光 if ([captureDevice isExposureModeSupported:AVCaptureExposureModeAutoExpose]) { [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose]; } if ([captureDevice isExposurePointOfInterestSupported]) { [captureDevice setExposurePointOfInterest:point]; } // 解鎖配置 [captureDevice unlockForConfiguration];}結束語
后續還會更新更多有關直播的資料,希望做到教會每一個朋友從零開始做一款直播app,并且Demo也會慢慢完善.Demo點擊下載
由于FFMPEG庫比較大,大概100M。本來想自己上傳所有代碼了,上傳了1個小時,還沒成功,就放棄了。提供另外一種方案,需要你們自己導入IJKPlayer庫具體步驟:
下載Demo后,打開YZLiveApp.xcworkspace問題
打開YZLiveApp.xcworkspace問題pod install就能解決
Snip20160830_12.png下載jkplayer庫,點擊下載把jkplayer直接拖入到與Classes同一級目錄下,直接運行程序,就能成功了
拖入ijkplayer到與Classes同一級目錄下.png注意不需要打開工程,把jkplayer拖入到工程中,而是直接把jkplayer庫拷貝到與Classes同一級目錄下就可以了。錯誤示范:不要向下面這樣操作
原文地址:http://www.jianshu.com/p/c71bfda055fa
|
新聞熱點
疑難解答