多媒体编程——ios摄像头图像抓取工具类

工具类提供预览图像画面,自动处理旋转,并且以主动方式抓取图像(这样帧率可以无限大)

系统的接口多是异步接收图像,像我这种强迫症怎么受得了,必须吧被动接收图像的方式改成主动抓取。

头文件

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>

//这些比例都是4:3的比例。
typedef enum TKVideoFrameSize
{
    tkVideoFrame480x360     = 480  << 16 | 360,
    tkVideoFrame720x540     = 720  << 16 | 540, //用这个分辨率,效率会快很多。
}TKVideoFrameSize;

@interface TKVideoCapture : NSObject <AVCaptureVideoDataOutputSampleBufferDelegate>

- (bool) create:(UIView*)preview frame:(TKVideoFrameSize)type ;
- (bool) destory;

- (bool) start ;
- (bool) stop ;

//返回 字节顺序 BGRA BGRA 的图像数据。
- (uint8_t*) get_image_rgb32:(uint32_t*)length ;

@end

实现文件:(里面用到了那个Lock可以去上一篇文章找)

#import "TKVideoCapture.h"
#import <UIKit/UIKit.h>
#import <CoreGraphics/CoreGraphics.h>
#import <CoreVideo/CoreVideo.h>
#import <CoreMedia/CoreMedia.h>
#import "TKLock.h"

@interface TKVideoCapture ()
{
    TKVideoFrameSize            _frametype      ;
    UIView*                     _preview        ;
    AVCaptureSession*           _captureSession ;
    AVCaptureVideoPreviewLayer* _capturePreview ;
    AVCaptureVideoDataOutput *  _captureOutput  ;
    AVCaptureDevice*            _captureDevice  ;
    AVCaptureDeviceInput*       _captureInput   ;

    uint8_t*                    _buffer_temp    ; //每一帧数据都存储到这个缓存中
    uint8_t*                    _buffer_obox    ; //需要使用时,从tempbuf 拷贝过来。
    CGRect                      _subImageRect   ; //子图片的位置。

    TKLock*                     _buffer_lock    ;
}

@end

@implementation TKVideoCapture

- (void) do_create
{
    self->_captureDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] ;
    self->_captureInput  = [AVCaptureDeviceInput deviceInputWithDevice:self->_captureDevice  error:nil];
    self->_captureOutput = [[AVCaptureVideoDataOutput alloc] init];

    if(self->_captureOutput)
        [self->_captureOutput setAlwaysDiscardsLateVideoFrames:true];

    dispatch_queue_t queue = dispatch_queue_create("cameraQueue", NULL);
    [self->_captureOutput setSampleBufferDelegate:self queue:queue];

    dispatch_release(queue);

    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];

    NSDictionary* videoSettings = [NSDictionary dictionaryWithObject:value forKey:key];

    [self->_captureOutput setVideoSettings:videoSettings];
    self->_captureSession = [[AVCaptureSession alloc] init];

    uint16_t width  = (uint16_t)(((uint32_t)_frametype) >> 16) ;
    uint16_t height = (uint16_t)(((uint32_t)_frametype) & 0xFFFF) ;

    _buffer_temp = (uint8_t*)malloc(width * height * 4);
    _buffer_obox = (uint8_t*)malloc(width * height * 4);

    //0.75是预定比例
    switch (_frametype) {
        case tkVideoFrame480x360:
        {
            _captureSession.sessionPreset = AVCaptureSessionPreset640x480 ;
            _subImageRect = CGRectMake((640-360)/2, 0, 360, 480);
            break;
        }
        case tkVideoFrame720x540:
        {
            _captureSession.sessionPreset = AVCaptureSessionPresetiFrame1280x720 ;
            _subImageRect = CGRectMake((1280-540)/2, 0, 540, 720);
            break;
        }
        default:
            break;
    }

    if(self->_captureInput != nil)
        [self->_captureSession addInput:self->_captureInput];

    [self->_captureSession addOutput:self->_captureOutput];

    self->_capturePreview = [AVCaptureVideoPreviewLayer layerWithSession: self->_captureSession];
    self->_capturePreview.frame = self->_preview.bounds;//CGRectMake(100, 0, 100, 100);
    self->_capturePreview.videoGravity = AVLayerVideoGravityResizeAspectFill;
    self->_capturePreview.connection.videoOrientation = [self getOrientation] ;

    [self->_preview.layer addSublayer: self->_capturePreview];

    _buffer_lock = [[TKLock alloc] init];
    [_buffer_lock open];
}

- (bool) create:(UIView*)preview frame:(TKVideoFrameSize)type
{
    self->_frametype     = type ;
    self->_preview       = preview ;

    [self performSelectorOnMainThread:@selector(do_create) withObject:self waitUntilDone:true];

    return true ;
}

- (AVCaptureVideoOrientation) getOrientation
{
    UIInterfaceOrientation orientation = [UIApplication sharedApplication].statusBarOrientation ;
    switch(orientation)
    {
        case UIInterfaceOrientationPortrait: return AVCaptureVideoOrientationPortrait;
        case UIInterfaceOrientationPortraitUpsideDown: return AVCaptureVideoOrientationPortraitUpsideDown;
        case UIInterfaceOrientationLandscapeLeft: return AVCaptureVideoOrientationLandscapeLeft;
        case UIInterfaceOrientationLandscapeRight: return AVCaptureVideoOrientationLandscapeRight;
    }
    return AVCaptureVideoOrientationLandscapeLeft ;
}

- (void) do_destory
{
    [_buffer_lock close];
    [_buffer_lock release];
    _buffer_lock = nil ;

    free(_buffer_temp);
    free(_buffer_obox);
    _buffer_temp = NULL ;
    _buffer_obox = NULL ;

    [self->_captureSession stopRunning];
    [self->_capturePreview removeFromSuperlayer];
    [self->_captureOutput  release];
    [self->_captureSession release];
    self->_captureSession = nil ;
    self->_capturePreview = nil ;
    self->_captureOutput  = nil ;
    self->_captureDevice  = nil ;
    self->_captureInput   = nil ;
    self->_preview        = nil ;
}

- (bool) destory
{
    [self performSelectorOnMainThread:@selector(do_destory) withObject:self waitUntilDone:true];
    return true ;
}

- (void)captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection
{
    CVImageBufferRef imageBuffer = CMSampleBufferGetImageBuffer(sampleBuffer);
    CVPixelBufferLockBaseAddress(imageBuffer,0);
    uint8_t* baseAddress = (uint8_t *)CVPixelBufferGetBaseAddress(imageBuffer);

    size_t width  = CVPixelBufferGetWidth(imageBuffer);
    size_t height = CVPixelBufferGetHeight(imageBuffer);
    size_t bytesPerRow = CVPixelBufferGetBytesPerRow(imageBuffer);

    CGColorSpaceRef colorSpace = CGColorSpaceCreateDeviceRGB();
    CGDataProviderRef provider = CGDataProviderCreateWithData(NULL, baseAddress, bytesPerRow * height, NULL);

    CGImageRef imageRef = CGImageCreate(width, height, 8, 32, bytesPerRow, colorSpace,
                                        kCGBitmapByteOrder32Little|kCGImageAlphaPremultipliedFirst,
                                        provider, NULL, false, kCGRenderingIntentDefault);

    CGImageRef subImageRef = CGImageCreateWithImageInRect(imageRef, _subImageRect);

    size_t subWidth  = _subImageRect.size.height ;
    size_t subHeight = _subImageRect.size.width  ;

    CGContextRef context = CGBitmapContextCreate(NULL, subWidth, subHeight,
                                  CGImageGetBitsPerComponent(subImageRef), 0,
                                  CGImageGetColorSpace(subImageRef),
                                  CGImageGetBitmapInfo(subImageRef));

    CGContextTranslateCTM(context, 0, subHeight);
    CGContextRotateCTM(context, -M_PI/2);

    CGContextDrawImage(context, CGRectMake(0, 0, subHeight, subWidth), subImageRef);

    uint8_t* data = (uint8_t*)CGBitmapContextGetData(context);

    [_buffer_lock lock];
    memcpy(_buffer_temp, data, subWidth * subHeight * 4);
    [_buffer_lock unlock];

    CGContextRelease(context);
    CGImageRelease(imageRef);
    CGImageRelease(subImageRef);
    CGDataProviderRelease(provider);
    CGColorSpaceRelease(colorSpace);
    CVPixelBufferUnlockBaseAddress(imageBuffer,0);
}

- (void) do_start
{
    [self->_captureSession startRunning];
}

- (void) do_stop
{
    [self->_captureSession stopRunning];
}

- (bool) start
{
    [self performSelectorOnMainThread:@selector(do_start) withObject:self waitUntilDone:true];
    return true ;
}
- (bool) stop
{
    [self performSelectorOnMainThread:@selector(do_stop) withObject:self waitUntilDone:true];
    return true ;
}

- (uint8_t*) get_image_rgb32:(uint32_t*)length
{
    uint16_t width  = (uint16_t)(((uint32_t)_frametype) >> 16) ;
    uint16_t height = (uint16_t)(((uint32_t)_frametype) & 0xFFFF) ;

    //从摄像头输出数据采集数据
    [_buffer_lock lock];
    memcpy(_buffer_obox, _buffer_temp, width * height * 4);
    [_buffer_lock unlock];

    if(length)
        *length = width * height * 4 ;

    return _buffer_obox ;
}

@end

多媒体编程——ios摄像头图像抓取工具类

时间: 2024-08-10 02:03:33

多媒体编程——ios摄像头图像抓取工具类的相关文章

多媒体编程——ios视频图像绘制工具类。

IOS上视频级的图像绘制 ios上的图像绘制常规的是 UIView的drawRect函数,但是这个函数是异步触发,并且由主线程执行.虽然可以通过一定技巧达到主动绘制的效果: 1.传递图像给UIView缓存着. 2.然后调用UIView的setNeedDisplay 改写重绘标志. (以上两步是讲图像丢给UIView,让它自己进行绘制,但是绘制的时机不可控,有时候我们需要它马上绘制,甚至有时候我们需要知道它什么时候绘制完成了,就需要下面两步) 3.在播放线程中调用UIView的 perfromOn

【iOS】正则表达式抓取网页数据制作小词典

应用程序不一定要自己去提供数据,有现成的数据学会去用才好. 网络很大,各种搜索引擎每天到处爬.本文通过正则表达式抓取网站的数据来做一个小词典. 一.正则表达式的使用 1. 确定匹配方案,即pattern 2. 用pattern实例化NSRegularExpression 3. 用匹配方法开始匹配. 匹配一次:可以使用firstMatch方法 匹配多次:可以用matchs方法 正则表达式对照表:(在网上找到了一个很不错的表,正则表达式各个语言通用) http://www.jb51.net/shou

Hawk-数据抓取工具

Hawk-数据抓取工具:简明教程 Hawk: Advanced Crawler& ETL tool written in C#/WPF 1.软件介绍 HAWK是一种数据采集和清洗工具,依据GPL协议开源,能够灵活,有效地采集来自网页,数据库,文件, 并通过可视化地拖拽,快速地进行生成,过滤,转换等操作.其功能最适合的领域,是爬虫和数据清洗. Hawk的含义为“鹰”,能够高效,准确地捕杀猎物. HAWK使用C# 编写,其前端界面使用WPF开发,支持插件扩展.通过图形化操作,能够快速建立解决方案.

百度地图兴趣点抓取工具

抓取全国POI数据不是梦,百度抓取工具可实现按区域范围抓取范围内数据,数据坐标为火星坐标,无偏移,数据字段有:NAME,X,Y,ADDRESS,TEL,TYPE,CITY,PROVINCE,百度所有的类型数据都可轻松抓取,没有遗漏,没有错误,不重复,比市面上的工具更加准确,市面的工具是靠步长设置来抓取点位的,有抓取不完整的现象,本工具完全解决了点位遗漏问题,并启用都线程抓取,抓取速度快,全国2000多万兴趣点抓取轻松搞定不遗漏死角.本工具由微创业科技工作室独立完成,本工作室还有地图抓工具,可抓取

UiBot无法抓取Google Chrome元素和数据抓取工具无法使用的解决方案

UiBot RPA抓取Google Chrome元素建议使用Google Chrome原版浏览器,不建议使用 二次修改的浏览器版本,以确保兼容性最佳.操作流程符合本教程. 如果无法抓取 Google Chrome 浏览器元素,或数据抓取工具无法使用,可以先检查浏览器扩展程序中是否已经安装并启用 UiBot 扩展程序(下载),如果扩展程序已经安装并启用,则浏览器右上角会出现 UiBot 扩展程序的图标,如下图: 如果您的浏览器右上角没有出现这个图标,则可能 UiBot 扩展程序没有安装成功或已启用

基于opencv的摄像头脸部识别抓取及格式储存(python)

刚接触opencv,参照opencv的sample例子做了一个视频头像抓取的小代码,顺便一起学习着用,先上视频抓取及存储代码: ? 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 # -*- coding: cp936 -*- import cv2 capture=cv2.VideoCapture(0) #将capture保存为motion-jpeg,cv_fourcc为保存格式 size

you-get 一个很强的视频地址抓取工具

来源:https://github.com/soimort/you-get 出自于 Mort Yao 大神之手:http://www.geekgrade.com/geeksheet/soimort/blogs 前言(废话): 前段时间,我因公司需求.所以要去研究如何拿到视屏的播放地址.一般普通的网站的视屏播放地址还是很好拿到的.但是对于优酷,腾讯这样的大型视屏资源站就很难拿到视屏资源了.普通的网站你通过网页就可以直接抓取到视屏的播放地址.但是这些大型就不行,这些网站都是做了防盗链的.就拿优酷来讲

网抓取工具和技巧

偶尔会有需求提取竞争对手的网站数据,而且网站一般会有一些防护程序抓取的方案. 工具: httpclient:有点笨重的工具,入门还是要些门槛 jsoup:轻量强大 webdriver:谷歌出品的精品,可以抓取网页和执行javascript Selenium :做测试的朋友推荐的,可以录制脚本 基本jsoup+webdriver就能完成所有浏览器模拟的工作

iOS开发之抓取花瓣网json数据

最近在研究iPhone流水布局的实现,首先得有数据,所以我就随便在网上抓一些数据来实现.网上有很多网站是用瀑布流,比如蘑菇街,花瓣网,美丽说等等,今天就以花瓣网为例子,尝试去抓取里面我们想要的数据. 本来是我是想用objective-c的一个HTML开源框架hpple去解析花瓣网返回的html数据,提取里面我们想要的节点,但是我尝试了一下,实现不了,也听网上说这个框架不是很完善.所以我干脆用工具来实现了,网上有很多这样的工具,现在我先一个叫charles的http代理监听工具,它能够监听我们ht