媒体捕捉-拍照

引言

在项目开发中,从媒体库中选择图片或使用相机拍摄图片是一个极为普遍的需求。通常,我们使用UIImagePickerController来实现单张图片选择或启动相机拍照。整个拍照过程由UIImagePickerController内部实现,无需我们关心细节,只需实现相应的回调以获取所需的图片。

然而,你或许好奇拍照的底层实现是什么样的,是否能够自己调用手机摄像头完成拍照功能?这正是AVFoundation发挥作用的地方。AVFoundation是一个强大的框架,提供了访问音视频的底层功能,包括相机和麦克风。通过AVFoundation,我们能够直接与设备的摄像头进行交互,实现自定义的拍照功能,为我们提供更大的灵活性和控制权。

在接下来的内容中,我们将深入探讨AVFoundation的拍照功能,了解如何通过这一框架自定义拍照过程,从而更好地满足项目的需求。

介绍

媒体捕捉主要类

首先介绍一下主要类:

AVCaptureDevice:捕捉设备。相对手机而言,它是摄像头,麦克风等物理设备定义了一个接口。

AVCaptureDeviceInput:捕捉设备的输入。捕捉设备不能直接添加到会话中,需要封装在AVCaptureDeviceInput中再进行添加。

AVCaptureSession:捕捉会话。捕获会话是整个功能的核心,有用链接输入和输出,配置捕捉环境。

AVCaptureOutput:捕捉的输出。AVCaptureOutput是一个抽象类,用于捕捉到的数据进行输出,不能直接使用,通常我们是使用它的子类比如AVCapturePhotoOutput,AVCaptureMovieFileOutput等等。

另外还有一个比较重要的类AVCaptureVideoPreviewLayer它提供了画面的预览功能。

基本使用

这里面演示一下我们使用的最小单元,也就是一个拍照功能的最核心代码:

  • 创建会话
AVCaptureSession * session = [[AVCaptureSession alloc] init];
  • 创建捕捉及输入并添加到会话
AVCaptureDevice * cameraDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
NSError * error;
AVCaptureDeviceInput * cameraInput = [AVCaptureDeviceInput deviceInputWithDevice:cameraDevice error:&error];
if ([session canAddInput:cameraInput]) {[session addInput:cameraInput];
}
  • 创建输出并添加到会话
AVCapturePhotoOutput * photoOutput = [[AVCapturePhotoOutput alloc] init]; 
if ([session canAddOutput:photoOutput]) {[session addOutput:photoOutput];
}

上面的代码创建了一个拍摄图片最基础的框架。创建会话,将设备捕捉到的数据添加到会话,再将数据进行输出静态图片。启动会话,视频数据流就可以开始传输了。真正使用起来会比上面的示例代码复杂一点,但核心内容仍然是这几个步骤。

完整示例

这一部分内容比较多,为了更容易理解,我们将对应的功能分散到不同的类中。

PHCameraController:捕捉核心类。负责启动会话处理输入和输出。

PHPreviewView:预览图层。负责渲染预览画面。

而我们首先把注意力集中在PHCameraController上面。

捕捉核心类
配置会话

我们先来定义一个最小的功能,只声明一些拍照所需要的属性及方法。.h中对外暴漏的属性和接口如下:

#import <Foundation/Foundation.h>
#import <AVFoundation/AVFoundation.h>
NS_ASSUME_NONNULL_BEGIN@interface PHCameraController : NSObject@property(nonatomic,strong,readonly)AVCaptureSession * captureSession;///设置会话
- (BOOL)setupSession:(NSError **)error;
///开始会话
- (void)startSession;
///停止会话
- (void)stopSession;///拍照
- (void)capturePhoto;
@end
NS_ASSUME_NONNULL_END

我们只定义了最基本的功能,设置会话,启动会话,停止会话和拍照。

接下来我们来看一下它的.m文件中的内容。

首先是扩展中的私有属性:

#import "PHCameraController.h"
@interface PHCameraController ()<AVCapturePhotoCaptureDelegate>
///会话启动队列
@property(nonatomic,strong)dispatch_queue_t videoQueue;
///会话
@property(nonatomic,strong)AVCaptureSession * captureSession;
///图片输出
@property(nonatomic,strong)AVCapturePhotoOutput * photoOutput;@end

在这里定义了一个自定义的队列,一个会话session和AVCaptureOutput的子类AVCapturePhotoOutput,专门用于输出静态图片。

再看一下它的接口实现,首先是配置会话相关的代码:

@implementation PHCameraController
- (BOOL)setupSession:(NSError *__autoreleasing  _Nullable *)error{self.captureSession = [[AVCaptureSession alloc] init];self.captureSession.sessionPreset = AVCaptureSessionPresetHigh;//获取默认摄像头AVCaptureDevice * videoDevice = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];AVCaptureDeviceInput * videoInput = [AVCaptureDeviceInput deviceInputWithDevice:videoDevice error:error];if (videoInput) {if ([self.captureSession canAddInput:videoInput]) {[self.captureSession addInput:videoInput];self.activeVideoInput = videoInput;}}else{return NO;}//设置图片输出self.photoOutput = [[AVCapturePhotoOutput alloc] init];NSDictionary * setDic = @{AVVideoCodecKey:AVVideoCodecTypeJPEG};AVCapturePhotoSettings * settings = [AVCapturePhotoSettings photoSettingsWithFormat:setDic];[self.photoOutput capturePhotoWithSettings:settings delegate:self];if ([self.captureSession canAddOutput:self.photoOutput]) {[self.captureSession addOutput:self.photoOutput];}self.videoQueue = dispatch_queue_create("com.panghu.VideoQueue", NULL);return YES;
}
@end

这和上面提到的最核心的代码实现几乎一致,创建会话添加会话输入和输出。

启动会话

再进行捕捉之前,需要先启动会话,也就是让会话处于准备捕捉静态图片的状态。

相关代码试下如下:

- (void)startSession{if (![self.captureSession isRunning]) {dispatch_async(self.videoQueue, ^{[self.captureSession startRunning];});}
}
开始捕捉静态图片

会话启动之后,我们就可以调用捕捉图片的方法来进行图片的捕捉:

- (void)capturePhoto{NSDictionary * setDic = @{AVVideoCodecKey:AVVideoCodecTypeJPEG};AVCapturePhotoSettings * settings = [AVCapturePhotoSettings photoSettingsWithFormat:setDic];self.photoSettings = settings;[self.photoOutput capturePhotoWithSettings:self.photoSettings delegate:self];
}

开始捕捉前,我们可以自定义捕捉静态图片的一些配置参数,比如

AVVideoCodecKey:图片类型。

AVVideoPixelAspectRatioKey:像素宽高比。

AVVideoCompressionPropertiesKey:压缩属性。

AVVideoWidthKey:宽。

AVVideoHeightKey:高。

调用拍照方法后会回调AVCapturePhotoCaptureDelegate中的代理方法:

- (void)captureOutput:(AVCapturePhotoOutput *)output didFinishProcessingPhoto:(AVCapturePhoto *)photo error:(NSError *)error{NSData * data = photo.fileDataRepresentation;UIImage * image = [UIImage imageWithData:data];
}

其中image即是我们想要的静态图片。

结束会话

使用完该功能后,退出拍照功能,需要停止会话:

- (void)stopSession{if ([self.captureSession isRunning]) {dispatch_async(self.videoQueue, ^{[self.captureSession stopRunning];});}
}
画面预览类

我们在这里定义一个专门用作画面预览的视图PHPreviewView。

可以在对应的实例中创建一个AVCaptureVideoPreviewLayer用来渲染预览画面,也可以用另外一种更优雅的方式,通过重写LayerClass方法返回一个AVCaptureVideoPreviewLayer。

.h中的代码如下:

@interface PHPreviewView : UIView
@property(nonatomic,strong)AVCaptureSession * session;
@end

只有一个捕捉会话对象。

.m中的实现如下:

#import "PHPreviewView.h"
@implementation PHPreviewView
+ (Class)layerClass{return [AVCaptureVideoPreviewLayer class];
}
- (void)setSession:(AVCaptureSession *)session{[(AVCaptureVideoPreviewLayer*)self.layer setSession:session];
}
- (AVCaptureSession *)session{return [(AVCaptureVideoPreviewLayer*)self.layer session];
}
@end

通过重写session的set方法来将预览图层与捕捉会话相关联。

通过重写session的get方法来返回捕捉会话。

使用

在视图控制器ViewController中使用拍照功能。

首先声明捕捉的核心类及画面预览类:

@interface ViewController ()//画面预览view
@property(nonatomic,strong)PHPreviewView * previewView;
///相机控制
@property(nonatomic,strong)PHCameraController * controller;@end

添加画面预览视图:

- (void)viewDidLoad {[super viewDidLoad];[self setupView];
}- (void)setupView{[self addPreviewView];[self configController];
}//MARK:画面预览view
- (void)addPreviewView{self.previewView = [[PHPreviewView alloc] initWithFrame:self.view.bounds];[self.view addSubview: self.previewView];
}//MARK:配置相机控制器
- (void)configController{self.controller = [[PHCameraController alloc] init];NSError * error = nil;BOOL isSuccess = [self.controller setupSession:&error];if (isSuccess) {[self.previewView setSession:self.controller.captureSession];[self.controller startSession];}
}

接下来我们只需要在屏幕上添加一个按钮然后调用拍照方法即可完成静态图片的拍摄:

//MARK:拍照或录制
- (void)capture:(UIButton *)sender{[self.controller capturePhoto];
}

结语

在实现自定义拍照功能时,除了深入了解AVCapturePhotoSettings等相关设置外,我们还需关注一系列前置和后续操作,以确保用户体验和功能完整性。

首先,我们必须在应用中请求摄像头和麦克风的权限,确保用户授权后才能正常使用这些设备。这是保护用户隐私的重要步骤,也是提供良好用户体验的前提。

另外,在成功捕获照片后,处理后续操作也至关重要。使用Photos框架将照片存储到相册,以确保用户可以轻松地查看和分享他们的作品。这是一个贴近用户习惯的操作,增强了应用的实用性和友好性。

在整个拍照过程中,我们还有许多机会进行细致的自定义,例如实现自动聚焦、调整曝光、切换摄像头、开启闪光灯等功能。这些细节的处理不仅提升了用户体验,也使应用更具吸引力。

在开发过程中,不断探索和尝试这些功能,根据具体项目需求进行定制,将为用户带来更为出色的拍摄体验。通过充分利用AVFoundation的强大功能,我们能够打造出更具创意和个性化的拍照应用,满足不同用户的期望和需求。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/231122.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

了解近20年临床检验结果互认的推动-九五小庞

检验结果互认的政策沿革 新冠核酸检测可以说是第一个全国范围内&#xff0c;各医疗机构之间的结果互认项目&#xff0c;也是ICL对于检验结果互认的一个实践。我们对于检验结果互认早在2000年&#xff0c;就已经引起了国家层面的重视&#xff0c;并且联合多部委发布了相关指导意…

docker容器化部署及数据持久化

1、加载MySQL 5.7的镜像 docker load -i mysql-5.7.tar.gz 2、执⾏命令启动MySQL容器&#xff1a; sh start-mysql.sh docker run -itd \ --name mysql \ --restart always \ -p 30036:3306 \ -v $PWD/mysql/config-file.cnf:/etc/mysql/conf.d/config-file.cnf \ -v $PWD/m…

【竞技宝】DOTA2:二号位地位发生变化 圣斧、血棘助法核重回巅峰!

北京时间2024年1月5日&#xff0c;目前国服已经更新7.35b版本一段时间了&#xff0c;在这段时间里&#xff0c;各位看官是否感受到了比赛节奏和英雄胜率方面的变化呢&#xff1f;从全分段的出场率以及胜率的变化来看&#xff0c;二号位在游戏内的地位已经发生了很大的变化。 在…

小兔鲜儿 uniapp - SKU 模块

目录 存货单位&#xff08;SKU&#xff09;​ 插件市场​ 下载 SKU 插件​ 使用 SKU 插件​ 插件类型问题​ 核心业务​ 渲染商品规格​ 打开弹窗交互​ 渲染被选中的值​ 存货单位&#xff08;SKU&#xff09;​ SKU 概念 存货单位&#xff08;Stock Keeping Unit&a…

论Acrel-2000MG微电网能量管理系统在储能行业的应用-安科瑞 蒋静

一、概述: 在新型电力系统中新能源装机容量逐年提高&#xff0c;但是新能源比如光伏发电、风力发电是不稳定的能源&#xff0c;所以要维持电网稳定&#xff0c;促进新能源发电的消纳&#xff0c;储能将成为至关重要的一环&#xff0c;是分布式光伏、风电等新能源消纳以及电网安…

年终总结——平凡又不平凡的2023

前言 总结不知道该如何写起&#xff0c;也不知该如何建立这一篇文章的大致框架&#xff0c;只知道我的2023大概也就分成两大块罢了。说起2023一整年&#xff0c;只能用平凡而又不平凡来形容&#xff0c;平凡在我依旧没有什么太突出的技术点&#xff0c;专业水平也一直处于龟速…

不同版本opencvsharp的依赖

结合Github和NuGet查看 Github主页 OpenCvSharp-AnyCPU&#xff08;lastest Version 2.4.10.20170306&#xff09; VC2013 runtime Framework OpenCvSharp3-AnyCPU&#xff08;lastest Version 4.0.0.20181129&#xff09; VC2015 runtime Framework OpenCvSharp4 (lastest…

【InnoDB数据存储结构】第3章节:区、段、碎片区和表空间

文章目录结构 区、段、碎片区和表空间 什么是区&#xff1f;什么是段&#xff1f;什么是碎片区&#xff1f;什么是表空间&#xff1f; 在上文 InooDB 存储行格式一文中已经大致讲述过&#xff0c;再来回顾一下&#xff0c;直接上图&#xff1a; 名词解释如下&#xff1a; 行…

Windows系统如何使用VNC远程连接Deepin桌面【内网穿透】

文章目录 1. 安装x11vnc2. 本地远程连接测试3. Deepin安装Cpolar4. 配置公网远程地址5. 公网远程连接Deepin桌面6. 固定连接公网地址7. 固定公网地址连接测试 x11vnc是一种在Linux系统中实现远程桌面控制的工具&#xff0c;它的原理是通过X Window系统的协议来实现远程桌面的展…

463岛屿周长

题目 给定一个 row x col 的二维网格地图 grid &#xff0c;其中&#xff1a;grid[i][j] 1 表示陆地&#xff0c; grid[i][j] 0 表示水域。 网格中的格子 水平和垂直 方向相连&#xff08;对角线方向不相连&#xff09;。整个网格被水完全包围&#xff0c;但其中恰好有一个…

Linux第15步_安装FTP客户端

安装完FTP服务器后&#xff0c;还需要安装FTP客户端&#xff0c;才可以实现Ubuntu系统和Windows系统进行文件互传。 1、在STM32MP157开发板A盘基础资料\03软件中&#xff0c;找到“FileZilla_3.51.0_win64-setup.exe”&#xff0c;双击它&#xff0c;就可以安装。 2、点击“I …

云计算历年题整理

第一大题纯计算 第一大题4或n个xx&#xff08;只答若干个短语&#xff09; 第一大题AWS描述名词 第二大题CUDA代码 第二大题描述名词&#xff08;很多和第一大题一样与AWS有关但是比第一大题难&#xff09; 第二大题计算 第三大题Map/Reduce项目涉及代码 下列Map/Reduce伪代码…

pygame学习(二)——绘制线条、圆、矩形等图案

导语 pygame是一个跨平台Python库(pygame news)&#xff0c;专门用来开发游戏。pygame主要为开发、设计2D电子游戏而生&#xff0c;提供图像模块&#xff08;image&#xff09;、声音模块&#xff08;mixer&#xff09;、输入/输出&#xff08;鼠标、键盘、显示屏&#xff09;模…

C#利用openvino部署PP-TinyPose人体姿态识别

【官方框架地址】 github.com/PaddlePaddle/PaddleDetection 【算法介绍】 关键点检测算法往往需要部署在轻量化、边缘端设备上&#xff0c;因此长期以来都存在一个难题&#xff1a;精度高、速度则慢、算法体积也随之增加。而PP-TinyPose的出世彻底打破了这个僵局&#xff0c…

Time-series forecasting with deep learning: a survey

人们开发了许多深度学习架构来适应不同领域的时间序列数据集的多样性。在本文中&#xff0c;我们调查了一步前进和多水平时间序列预测中使用的常见编码器和解码器设计&#xff0c;描述了如何将时间信息纳入每个模型的预测中。接下来&#xff0c;我们重点介绍混合深度学习模型的…

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义

任务需求分析中的流程图、用例图、er图、类图、时序图线段、图形的作用意义 流程图 流程图中各种图形的含义及用法解析 连接线符号 连接各要素&#xff0c;表示流程的顺序或过程的方向。 批注符号 批注或说明&#xff0c;也可以做条件叙述。 子流程 流程中一部分图形的逻辑…

MySQL 8.0 开关 Redo Logging

一 前言 前几天有客户测试使用云数据库的时候提出 要禁止mydumper 关闭redo log的操作 (说白了就是导入数据时保持MySQL 实例的redo logging功能)&#xff0c; 这才想起 在 MySQL 8.0.21 版本中&#xff0c;开启了一个新特性 “Redo Logging 动态开关”。 在新实例导数据的场…

三坐标测量机的应用场景及其国产化的重要意义

三坐标测量机广泛应用于制造业和工程领域&#xff0c;测量工件在三维空间中的尺寸、形状和位置&#xff0c;对工件进行精确的测量和检测。它具有高精度、高效率和自动化程度高的优点。 应用场景 1、汽车制造领域 在汽车生产过程中&#xff0c;需要对零部件的精度和质量进行检…

Sonarqube安装(Docker)

一&#xff0c;拉取相关镜像并运行 # 拉取sonarqube镜像 docker pull sonarqube:9.1.0-community在运行之前要提前安装postgres并允许&#xff0c;新建数据库名为sonar的数据库 Docker安装postgres教程 docker run -d --name sonarqube --restartalways \ -p 19000:9000 \ …