-
需求
公司混合開發(fā)但汞,uni端拍小視頻不是很理想,為達(dá)到仿微信效果凛辣,原生插件走起
-
思路
第1步:1個(gè)AVCaptureSession, 1塊AVCaptureVideoPreviewLayer[考慮兼容替換成AVPreView]
第2步:視頻錄制需video & audio, 需要對(duì)應(yīng)的AVCaptureDeviceInput,同理對(duì)應(yīng)的AVCaptureVideoDataOutput與AVCaptureAudioDataOutput
第3步:代理中設(shè)置output區(qū)分video與audio, 并將對(duì)應(yīng)的CMSampleBufferRef寫入到視頻文件中
第4步:寫入視頻文件中,用到AVAssetWriter, 對(duì)應(yīng)video & audio 需兩個(gè)AVAssetWriterInput, 加入AVAssetWriter
第5步:CMSampleBufferRef不斷過來框弛,AssetWriter不斷寫入,直到停止
-
上菜
第一步的初始化就不寫了捕捂,沒事可以翻看本人前面的博客
第2步:兩個(gè)AVCaptureDeviceInput 兩個(gè)Output, 且設(shè)置Output的代理
self.videoInput = [[AVCaptureDeviceInput alloc] initWithDevice:device error:&error]; if (error) { NSLog(@"取得設(shè)備攝入videoInput對(duì)象時(shí)出錯(cuò), 錯(cuò)誤原因: %@", error); return; } // 設(shè)備添加到會(huì)話中 if ([self.session canAddInput:self.videoInput]) { [self.session addInput:self.videoInput]; } [self.videoOutput setSampleBufferDelegate:self queue:self.videoQueue]; if ([self.session canAddOutput:self.videoOutput]) { [self.session addOutput:self.videoOutput]; } // 音頻相關(guān) AVCaptureDevice *adevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio]; self.audioInput = [[AVCaptureDeviceInput alloc] initWithDevice:adevice error:&error]; if ([self.session canAddInput:self.audioInput]) { [self.session addInput:self.audioInput]; } [self.audioOutput setSampleBufferDelegate:self queue:self.videoQueue]; if ([self.session canAddOutput:self.audioOutput]) { [self.session addOutput:self.audioOutput]; } // 視頻輸出 - (AVCaptureVideoDataOutput *)videoOutput { if (!_videoOutput) { _videoOutput = [[AVCaptureVideoDataOutput alloc] init]; _videoOutput.alwaysDiscardsLateVideoFrames = YES; } return _videoOutput; } // 音頻輸出 - (AVCaptureAudioDataOutput *)audioOutput { if (!_audioOutput) { _audioOutput = [[AVCaptureAudioDataOutput alloc] init]; } return _audioOutput; }
第3步:?jiǎn)?dòng)Session功咒,代理里面操作CMSampleBufferRef
#pragma mark - AVCaptureVideoDataOutputSampleBufferDelegate & AVCaptureAudioDataOutputSampleBufferDelegate - (void)captureOutput:(AVCaptureOutput *)output didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection { @autoreleasepool { // 視頻 if (connection == [self.videoOutput connectionWithMediaType:AVMediaTypeVideo]) { if (!self.manager.outputVideoFormatDescription) { @synchronized(self) { CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer); self.manager.outputVideoFormatDescription = formatDescription; } } else { @synchronized(self) { if (self.manager.state == StateRecording) { [self.manager appendBuffer:sampleBuffer type:AVMediaTypeVideo]; } } } } //音頻 if (connection == [self.audioOutput connectionWithMediaType:AVMediaTypeAudio]) { if (!self.manager.outputAudioFormatDescription) { @synchronized(self) { CMFormatDescriptionRef formatDescription = CMSampleBufferGetFormatDescription(sampleBuffer); self.manager.outputAudioFormatDescription = formatDescription; } } @synchronized(self) { if (self.manager.state == StateRecording) { [self.manager appendBuffer:sampleBuffer type:AVMediaTypeAudio]; } } } } }
第4步:AVAssetWriter以及對(duì)應(yīng)的Input
// writer初始化 self.writer = [AVAssetWriter assetWriterWithURL:_videoUrl fileType:AVFileTypeMPEG4 error:nil]; _videoInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeVideo outputSettings:_videoSettings]; //expectsMediaDataInRealTime 必須設(shè)為yes愉阎,需要從capture session 實(shí)時(shí)獲取數(shù)據(jù) _videoInput.expectsMediaDataInRealTime = YES; _audioInput = [AVAssetWriterInput assetWriterInputWithMediaType:AVMediaTypeAudio outputSettings:_audioSettings]; _audioInput.expectsMediaDataInRealTime = YES; if ([_writer canAddInput:_videoInput]) { [_writer addInput:_videoInput]; } if ([_writer canAddInput:_audioInput]) { [_writer addInput:_audioInput]; }
第5步:第3步的CMSampleBufferRef通過AVAssetWriter寫入到視頻文件中
- (void)appendBuffer:(CMSampleBufferRef)buffer type:(NSString *)mediaType { if (buffer == NULL) { NSLog(@"empty sampleBuffer"); return; } @synchronized (self) { if (self.state < StateRecording) { NSLog(@"not ready yet"); return; } } CFRetain(buffer); dispatch_async(self.queue, ^{ @autoreleasepool { @synchronized (self) { if (self.state > StateFinish) { CFRelease(buffer); return; } } if (!self.canWrite && mediaType == AVMediaTypeVideo) { [self.writer startWriting]; [self.writer startSessionAtSourceTime:CMSampleBufferGetPresentationTimeStamp(buffer)]; self.canWrite = YES; } if(!self.timer) { dispatch_async(dispatch_get_main_queue(), ^{ self.timer = [NSTimer scheduledTimerWithTimeInterval:TIMER_INTERVAL target:self selector:@selector(updateProgress) userInfo:nil repeats:YES]; [[NSRunLoop currentRunLoop] addTimer:self.timer forMode:NSDefaultRunLoopMode]; }); } // 寫入視頻數(shù)據(jù) if (mediaType == AVMediaTypeVideo) { if (self.videoInput.readyForMoreMediaData) { BOOL success = [self.videoInput appendSampleBuffer:buffer]; if (!success) { @synchronized (self) { [self stop:^{}]; [self destroy]; } } } } // 寫入音頻數(shù)據(jù) if (mediaType == AVMediaTypeAudio) { if (self.audioInput.readyForMoreMediaData) { BOOL success = [self.audioInput appendSampleBuffer:buffer]; if (!success) { @synchronized (self) { [self stop:^{}]; [self destroy]; } } } } CFRelease(buffer); } }); }
-
寫在末尾:
AVAssetWriterInput設(shè)置視頻屬性時(shí),按照自己的需要設(shè)計(jì)力奋,其中碼率與幀率的設(shè)置會(huì)影響到拍攝后視頻的質(zhì)量與大小榜旦,具體看各自項(xiàng)目的要求
-
如果視頻視角存在問題,可以從三個(gè)方向入手調(diào)整
1.layer的connect設(shè)置下videoOrientation
2.AVCaptureOutput的connect設(shè)置下videoOrientation
3.AVAssetWriterInput針對(duì)video是設(shè)置下transform景殷,比如Rotation M_PI/2 角度
iOS拍個(gè)小視頻
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
- 文/潘曉璐 我一進(jìn)店門伊约,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人孕蝉,你說我怎么就攤上這事屡律。” “怎么了降淮?”我有些...
- 文/不壞的土叔 我叫張陵超埋,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我佳鳖,道長(zhǎng)霍殴,這世上最難降的妖魔是什么? 我笑而不...
- 正文 為了忘掉前任系吩,我火速辦了婚禮繁成,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘淑玫。我一直安慰自己巾腕,他們只是感情好,可當(dāng)我...
- 文/花漫 我一把揭開白布絮蒿。 她就那樣靜靜地躺著尊搬,像睡著了一般。 火紅的嫁衣襯著肌膚如雪土涝。 梳的紋絲不亂的頭發(fā)上佛寿,一...
- 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼肢专!你這毒婦竟也來了舞肆?” 一聲冷哼從身側(cè)響起,我...
- 序言:老撾萬榮一對(duì)情侶失蹤博杖,失蹤者是張志新(化名)和其女友劉穎椿胯,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體剃根,經(jīng)...
- 正文 獨(dú)居荒郊野嶺守林人離奇死亡哩盲,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
- 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了狈醉。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片廉油。...
- 正文 年R本政府宣布,位于F島的核電站趣竣,受9級(jí)特大地震影響摇庙,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜遥缕,卻給世界環(huán)境...
- 文/蒙蒙 一卫袒、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧单匣,春花似錦夕凝、人聲如沸。這莊子的主人今日做“春日...
- 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至鸡号,卻和暖如春转砖,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背鲸伴。 一陣腳步聲響...
- 正文 我出身青樓姓赤,卻偏偏與公主長(zhǎng)得像赡译,于是被迫代替她去往敵國和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子模捂,可洞房花燭夜當(dāng)晚...
推薦閱讀更多精彩內(nèi)容
- 推流捶朵,就是將采集到的音頻,視頻數(shù)據(jù)通過流媒體協(xié)議發(fā)送到流媒體服務(wù)器狂男。 推流前的工作:采集综看,處理,編碼壓縮 推流中做...
- 概述 GPUImage是一個(gè)著名的圖像處理開源庫岖食,它讓你能夠在圖片红碑、視頻、相機(jī)上使用GPU加速的濾鏡和其它特效泡垃。與...
- 目錄相機(jī)基本實(shí)現(xiàn)步驟捕捉會(huì)話——AVCaptureSession捕捉輸入——AVCaptureDeviceInpu...
- 一直在忙, 也沒寫過幾次博客! 但一直熱衷于直播開發(fā)技術(shù), 公司又不是直播方向的, 所以就年前忙里偷閑研究了一下直...
- UIImagePickerController 目前析珊,將視頻捕獲集成到你的應(yīng)用中的最簡(jiǎn)單的方法是使用 UIImag...