調(diào)用攝像頭來獲取 視頻流每一幀數(shù)據(jù)

為了完成實時的捕獲,首先初始化一個AVCaputureSession對象用于創(chuàng)建一個捕獲會話(session)酥泛,我們可以使用AVCaptureSession對象將AV輸入設(shè)備的數(shù)據(jù)流以另一種形式轉(zhuǎn)換到輸出柔袁。

然后,我們初始化一個AVCaptureDeviceInput對象插掂,以創(chuàng)建一個輸入數(shù)據(jù)源腥例,該數(shù)據(jù)源為捕獲會話(session)提供視頻數(shù)據(jù),再調(diào)用addInput方法將創(chuàng)建的輸入添加到AVCaptureSession對象璃弄。

接著初始化一個AVCaptureVideoDataOuput對象底瓣,以創(chuàng)建一個輸出目標(biāo),然后調(diào)用addOutput方法將該對象添加到捕獲會話中拨扶。

AVCaptureVideoDataOutput可用于處理從視頻中捕獲的未經(jīng)壓縮的幀茁肠。一個AVCaptureVideoDataOutput實例能處理許多其他多媒體API能處理的視頻幀,你可以通過captureOutput:didOutputSampleBuffer:fromConnection:這個委托方法獲取幀匹颤,使用setSampleBufferDelegate:queue:設(shè)置抽樣緩存委托和將應(yīng)用回調(diào)的隊列。AVCaptureVideoDataOutputSampleBuffer對象的委托必須采用AVCaptureVideoDataOutputSampleBufferDelegate協(xié)議辽慕,使用sessionPreset協(xié)議來制定輸出品質(zhì)溅蛉。

我們可以通過調(diào)用捕獲會話的startRunning方法啟動從輸入到輸出的數(shù)據(jù)流,通過stopRunning方法來停止數(shù)據(jù)流船侧。

列表1給出了一個例子镜撩。setupCaptureSession創(chuàng)建了一個捕獲會話袁梗,添加了一個視頻輸入提供提視頻幀,一個輸出目標(biāo)獲取捕獲的幀围段,然后啟動從輸入到輸出的數(shù)據(jù)流投放。當(dāng)捕獲會話正在運行時灸芳,使用captureOut:didOutputSampleBuffer:fromConnection方法將被捕獲的視頻抽樣幀發(fā)送給抽樣緩存委托拜姿,然后每個抽樣緩存(CMSampleBufferRef)被轉(zhuǎn)換成imageFromSampleBuffer中的一個UIImage對象蕊肥。

列表1:使用AV Foundation設(shè)置一個捕獲設(shè)備錄制視頻并將是視頻幀保存為UIImage對象壁却。
// 創(chuàng)建并配置一個捕獲會話并且啟用它
- (void)setupCaptureSession
{
NSError *error = nil;
// 創(chuàng)建session
AVCaptureSession *session = [[AVCaptureSession alloc] init];
// 可以配置session以產(chǎn)生解析度較低的視頻幀,如果你的處理算法能夠應(yīng)付(這種低解析度)赔硫。
// 我們將選擇的設(shè)備指定為中等質(zhì)量盐肃。
session.sessionPreset = AVCaptureSessionPresetMedium;
// 找到一個合適的AVCaptureDevice
AVCaptureDevice *device = [AVCaptureDevice
defaultDeviceWithMediaType:AVMediaTypeVideo];
// 用device對象創(chuàng)建一個設(shè)備對象input,并將其添加到session
AVCaptureDeviceInput *input = [AVCaptureDeviceInput deviceInputWithDevice:device
error:&error];
if (!input) {
// 處理相應(yīng)的錯誤
}
[session addInput:input];
// 創(chuàng)建一個VideoDataOutput對象峦阁,將其添加到session
AVCaptureVideoDataOutput *output = [[[AVCaptureVideoDataOutput alloc] init] autorelease];
[session addOutput:output];
// 配置output對象
dispatch_queue_t queue = dispatch_queue_create("myQueue", NULL);
[output setSampleBufferDelegate:self queue:queue];
dispatch_release(queue);
// 指定像素格式
output.videoSettings =
[NSDictionary dictionaryWithObject:
[NSNumber numberWithInt:kCVPixelFormatType_32BGRA]
forKey:(id)kCVPixelBufferPixelFormatTypeKey];
// 如果你想將視頻的幀數(shù)指定一個頂值, 例如15ps
// 可以設(shè)置minFrameDuration(該屬性在iOS 5.0中棄用)
output.minFrameDuration = CMTimeMake(1, 15);
// 啟動session以啟動數(shù)據(jù)流
[session startRunning];
// 將session附給[實例變量](https://www.baidu.com/s?wd=%E5%AE%9E%E4%BE%8B%E5%8F%98%E9%87%8F&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)
[self setSession:session];
}
// 抽樣緩存寫入時所調(diào)用的委托程序
- (void)captureOutput:(AVCaptureOutput *)captureOutput
didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer
fromConnection:(AVCaptureConnection *)connection
{
// 通過抽樣緩存數(shù)據(jù)創(chuàng)建一個UIImage對象
UIImage *image = [self imageFromSampleBuffer:sampleBuffer];
< 此處添加使用該image對象的代碼 >
}
// 通過抽樣緩存數(shù)據(jù)創(chuàng)建一個UIImage對象
- (UIImage *) imageFromSampleBuffer:(CMSampleBufferRef) sampleBuffer
{
// 為媒體數(shù)據(jù)設(shè)置一個CMSampleBuffer的Core Video圖像緩存對象
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
// 鎖定pixel buffer的基地址
CVPixelBufferLockBaseAddress(imageBuffer, 0);
// 得到pixel buffer的基地址
void *baseAddress = CVPixelBufferGetBaseAddress(imageBuffer);
// 得到pixel buffer的行字節(jié)數(shù)
[size_t](https://www.baidu.com/s?wd=size_t&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
// 得到pixel buffer的寬和高
[size_t](https://www.baidu.com/s?wd=size_t&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)width = CVPixelBufferGetWidth(imageBuffer);
[size_t](https://www.baidu.com/s?wd=size_t&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)height = CVPixelBufferGetHeight(imageBuffer);
// 創(chuàng)建一個依賴于設(shè)備的RGB[顏色空間](https://www.baidu.com/s?wd=%E9%A2%9C%E8%89%B2%E7%A9%BA%E9%97%B4&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
// 用抽樣緩存的數(shù)據(jù)創(chuàng)建一個位圖格式的圖形上下文(graphics context)對象
CGContextRef context = CGBitmapContextCreate(baseAddress, width, height, 8,
bytesPerRow, colorSpace, kCGBitmapByteOrder32Little | kCGImageAlphaPremultipliedFirst);
// 根據(jù)這個位圖context中的像素數(shù)據(jù)創(chuàng)建一個Quartz image對象
CGImageRef quartzImage = CGBitmapContextCreateImage(context);
// 解鎖pixel buffer
CVPixelBufferUnlockBaseAddress(imageBuffer,0);
// 釋放context和[顏色空間](https://www.baidu.com/s?wd=%E9%A2%9C%E8%89%B2%E7%A9%BA%E9%97%B4&tn=44039180_cpr&fenlei=mv6quAkxTZn0IZRqIHckPjm4nH00T1YkP10znvmvnWPWuADvmyw90ZwV5Hcvrjm3rH6sPfKWUMw85HfYnjn4nH6sgvPsT6KdThsqpZwYTjCEQLGCpyw9Uz4Bmy-bIi4WUvYETgN-TLwGUv3EnH64PHTsrHb4PHRvn1TkPjDYn0)
CGContextRelease(context);
CGColorSpaceRelease(colorSpace);
// 用Quartz image創(chuàng)建一個UIImage對象image
UIImage *image = [UIImage imageWithCGImage:quartzImage];
// 釋放Quartz image對象
CGImageRelease(quartzImage);
return (image);
}```
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末凿跳,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子茧彤,更是在濱河造成了極大的恐慌曾掂,老刑警劉巖壁顶,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異许蓖,居然都是意外死亡膊爪,警方通過查閱死者的電腦和手機嚎莉,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門趋箩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人跳芳,你說我怎么就攤上這事启妹。” “怎么了桨啃?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵照瘾,是天一觀的道長。 經(jīng)常有香客問我主卫,道長簇搅,這世上最難降的妖魔是什么软吐? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任瘩将,我火速辦了婚禮,結(jié)果婚禮上凹耙,老公的妹妹穿的比我還像新娘姿现。我一直安慰自己,他們只是感情好肖抱,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布备典。 她就那樣靜靜地躺著,像睡著了一般意述。 火紅的嫁衣襯著肌膚如雪提佣。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天欲险,我揣著相機與錄音镐依,去河邊找鬼匹涮。 笑死天试,一個胖子當(dāng)著我的面吹牛喜每,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播刚照,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼啊楚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了颜价?” 一聲冷哼從身側(cè)響起周伦,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤狈蚤,失蹤者是張志新(化名)和其女友劉穎脆侮,沒想到半個月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體幻捏,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡醋奠,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年沛善,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片漠秋。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖搂抒,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情芳杏,我是刑警寧澤爵赵,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站秕铛,受9級特大地震影響,放射性物質(zhì)發(fā)生泄漏谨湘。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一赤拒、第九天 我趴在偏房一處隱蔽的房頂上張望这敬。 院中可真熱鬧,春花似錦冷蚂、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春恬涧,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背提揍。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工刨仑, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留杉武,地道東北人飞涂。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓夭问,卻偏偏與公主長得像缰趋,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子仔涩,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容