多媒体编程ios摄像头图像抓取工具类
转载自 http://www.it165.net/pro/html/201408/19449.html
-
工具类提供预览图像画面,自动处理旋转,并且以主动方式抓取图像(这样帧率可以无限大)
系统的接口多是异步接收图像,像我这种强迫症怎么受得了,必须吧被动接收图像的方式改成主动抓取。
头文件
01.
#
import
<Foundation/Foundation.h>
02.
#
import
<AVFoundation/AVFoundation.h>
03.
04.
//这些比例都是4:3的比例。
05.
typedef
enum
TKVideoFrameSize
06.
{
07.
tkVideoFrame480x360 =
480
<<
16
|
360
,
08.
tkVideoFrame720x540 =
720
<<
16
|
540
,
//用这个分辨率,效率会快很多。
09.
}TKVideoFrameSize;
10.
11.
12.
13.
@interface
TKVideoCapture : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>
14.
15.
- (bool) create:(UIView*)preview frame:(TKVideoFrameSize)type ;
16.
- (bool) destory;
17.
18.
- (bool) start ;
19.
- (bool) stop ;
20.
21.
//返回 字节顺序 BGRA BGRA 的图像数据。
22.
- (uint8_t*) get_image_rgb32:(uint32_t*)length ;
23.
24.
@end
001.
#
import
"TKVideoCapture.h"
002.
#
import
<UIKit/UIKit.h>
003.
#
import
<CoreGraphics/CoreGraphics.h>
004.
#
import
<CoreVideo/CoreVideo.h>
005.
#
import
<CoreMedia/CoreMedia.h>
006.
#
import
"TKLock.h"
007.
008.
@interface
TKVideoCapture ()
009.
{
010.
TKVideoFrameSize _frametype ;
011.
UIView* _preview ;
012.
AVCaptureSession* _captureSession ;
013.
AVCaptureVideoPreviewLayer* _capturePreview ;
014.
AVCaptureVideoDataOutput * _captureOutput ;
015.
AVCaptureDevice* _captureDevice ;
016.
AVCaptureDeviceInput* _captureInput ;
017.
018.
uint8_t* _buffer_temp ;
//每一帧数据都存储到这个缓存中
019.
uint8_t* _buffer_obox ;
//需要使用时,从tempbuf 拷贝过来。
020.
CGRect _subImageRect ;
//子图片的位置。
021.
022.
TKLock* _buffer_lock ;
023.
}
024.
025.
@end
026.
027.
028.
@implementation
TKVideoCapture
029.
030.
- (
void
) do_create
031.
{
032.
self->_captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] ;
033.
self->_captureInput = [AVCaptureDeviceInput deviceInputWithDevice:self->_captureDevice error:nil];
034.
self->_captureOutput = [[AVCaptureVideoDataOutput alloc] init];
035.
036.
if
(self->_captureOutput)
037.
[self->_captureOutput setAlwaysDiscardsLateVideoFrames:
true
];
038.
039.
dispatch_queue_t queue = dispatch_queue_create(
"cameraQueue"
, NULL);
040.
[self->_captureOutput setSampleBufferDelegate:self queue:queue];
041.
042.
dispatch_release(queue);
043.
044.
045.
NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
046.
NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
047.
048.
NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];
049.
050.
[self->_captureOutput setVideoSettings:videoSettings];
051.
self->_captureSession = [[AVCaptureSession alloc] init];
052.
053.
uint16_t width = (uint16_t)(((uint32_t)_frametype) >>
16
) ;
054.
uint16_t height = (uint16_t)(((uint32_t)_frametype) &
0xFFFF
) ;
055.
056.
_buffer_temp = (uint8_t*)malloc(width * height *
4
);
057.
_buffer_obox = (uint8_t*)malloc(width * height *
4
);
058.
059.
//0.75是预定比例
060.
switch
(_frametype) {
061.
case
tkVideoFrame480x360:
062.
{
063.
_captureSession.sessionPreset = AVCaptureSessionPreset640x480 ;
064.
_subImageRect = CGRectMake((
640
-
360
)/
2
,
0
,
360
,
480
);
065.
break
;
066.
}
067.
case
tkVideoFrame720x540:
068.
{
069.
_captureSession.sessionPreset = AVCaptureSessionPresetiFrame1280x720 ;
070.
_subImageRect = CGRectMake((
1280
-
540
)/
2
,
0
,
540
,
720
);
071.
break
;
072.
}
073.
default
:
074.
break
;
075.
}
076.
077.
if
(self->_captureInput != nil)
078.
[self->_captureSession addInput:self->_captureInput];
079.
080.
[self->_captureSession addOutput:self->_captureOutput];
081.
082.
self->_capturePreview = [AVCaptureVideoPreviewLayer layerWithSession: self->_captureSession];
083.
self->_capturePreview.frame = self->_preview.bounds;
//CGRectMake(100, 0, 100, 100);
084.
self->_capturePreview.videoGravity = AVLayerVideoGravityResizeAspectFill;
085.
self->_capturePreview.connection.videoOrientation = [self getOrientation] ;
086.
087.
[self->_preview.layer addSublayer: self->_capturePreview];
088.
089.
_buffer_lock = [[TKLock alloc] init];
090.
[_buffer_lock open];
091.
}
092.
093.
- (bool) create:(UIView*)preview frame:(TKVideoFrameSize)type
094.
{
095.
self->_frametype = type ;
096.
self->_preview = preview ;
097.
098.
[self performSelectorOnMainThread:
@selector
(do_create) withObject:self waitUntilDone:
true
];
099.
100.
return
true
;
101.
}
102.
103.
- (AVCaptureVideoOrientation) getOrientation
104.
{
105.
UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation ;
106.
switch
(orientation)
107.
{
108.
case
UIInterfaceOrientationPortrait:
return
AVCaptureVideoOrientationPortrait;
109.
case
UIInterfaceOrientationPortraitUpsideDown:
return
AVCaptureVideoOrientationPortraitUpsideDown;
110.
case
UIInterfaceOrientationLandscapeLeft:
return
AVCaptureVideoOrientationLandscapeLeft;
111.
case
UIInterfaceOrientationLandscapeRight:
return
AVCaptureVideoOrientationLandscapeRight;
112.
}
113.
return
AVCaptureVideoOrientationLandscapeLeft ;
114.
}
115.
116.
- (
void
) do_destory
117.
{
118.
[_buffer_lock close];
119.
[_buffer_lock release];
120.
_buffer_lock = nil ;
121.
122.
free(_buffer_temp);
123.
free(_buffer_obox);
124.
_buffer_temp = NULL ;
125.
_buffer_obox = NULL ;
126.
127.
[self->_captureSession stopRunning];
128.
[self->_capturePreview removeFromSuperlayer];
129.
[self->_captureOutput release];
130.
[self->_captureSession release];
131.
self->_captureSession = nil ;
132.
self->_capturePreview = nil ;
133.
self->_captureOutput = nil ;
134.
self->_captureDevice = nil ;
135.
self->_captureInput = nil ;
136.
self->_preview = nil ;
137.
}
138.
139.
- (bool) destory
140.
{
141.
[self performSelectorOnMainThread:
@selector
(do_destory) withObject:self waitUntilDone:
true
];
142.
return
true
;
143.
}
144.
145.
- (
void
)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
146.
{
147.
CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
148.
CVPixelBufferLockBaseAddress(imageBuffer,
0
);
149.
uint8_t* baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);
150.
151.
size_t width = CVPixelBufferGetWidth(imageBuffer);
152.
size_t height = CVPixelBufferGetHeight(imageBuffer);
153.
size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);
154.
155.
CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
156.
CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bytesPerRow * height, NULL);
157.
158.
CGImageRef imageRef = CGImageCreate(width, height,
8
,
32
, bytesPerRow, colorSpace,
159.
kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst,
160.
provider, NULL,
false
, kCGRenderingIntentDefault);
161.
162.
CGImageRef subImageRef = CGImageCreateWithImageInRect(imageRef, _subImageRect);
163.
164.
size_t subWidth = _subImageRect.size.height ;
165.
size_t subHeight = _subImageRect.size.width ;
166.
167.
CGContextRef context = CGBitmapContextCreate(NULL, subWidth, subHeight,
168.
CGImageGetBitsPerComponent(subImageRef),
0
,
169.
CGImageGetColorSpace(subImageRef),
170.
CGImageGetBitmapInfo(subImageRef));
171.
172.
173.
CGContextTranslateCTM(context,
0
, subHeight);
174.
CGContextRotateCTM(context, -M_PI/
2
);
175.
176.
CGContextDrawImage(context, CGRectMake(
0
,
0
, subHeight, subWidth), subImageRef);
177.
178.
uint8_t* data = (uint8_t*)CGBitmapContextGetData(context);
179.
180.
[_buffer_lock lock];
181.
memcpy(_buffer_temp, data, subWidth * subHeight *
4
);
182.
[_buffer_lock unlock];
183.
184.
CGContextRelease(context);
185.
CGImageRelease(imageRef);
186.
CGImageRelease(subImageRef);
187.
CGDataProviderRelease(provider);
188.
CGColorSpaceRelease(colorSpace);
189.
CVPixelBufferUnlockBaseAddress(imageBuffer,
0
);
190.
}
191.
192.
- (
void
) do_start
193.
{
194.
[self->_captureSession startRunning];
195.
}
196.
197.
- (
void
) do_stop
198.
{
199.
[self->_captureSession stopRunning];
200.
}
201.
202.
- (bool) start
203.
{
204.
[self performSelectorOnMainThread:
@selector
(do_start) withObject:self waitUntilDone:
true
];
205.
return
true
;
206.
}
207.
- (bool) stop
208.
{
209.
[self performSelectorOnMainThread:
@selector
(do_stop) withObject:self waitUntilDone:
true
];
210.
return
true
;
211.
}
212.
213.
- (uint8_t*) get_image_rgb32:(uint32_t*)length
214.
{
215.
uint16_t width = (uint16_t)(((uint32_t)_frametype) >>
16
) ;
216.
uint16_t height = (uint16_t)(((uint32_t)_frametype) &
0xFFFF
) ;
217.
218.
//从摄像头输出数据采集数据
219.
[_buffer_lock lock];
220.
memcpy(_buffer_obox, _buffer_temp, width * height *
4
);
221.
[_buffer_lock unlock];
222.
223.
if
(length)
224.
*length = width * height *
4
;
225.
226.
return
_buffer_obox ;
227.
}
228.
229.
230.
@end