视频采集部分
import UIKit
import AVFoundation
class ViewController: UIViewController {
fileprivate lazy var videoQueue = DispatchQueue.global()
fileprivate lazy var session : AVCaptureSession = AVCaptureSession()
fileprivate lazy var previewLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)
}
@IBAction func startCapture() {
// 1.创建捕捉会话
// let session = AVCaptureSession()
// self.session = session
// 2.设置输入源(摄像头)
// 2.1.获取摄像头
guard let devices = AVCaptureDevice.devices(withMediaType:AVMediaTypeVideo) as? [AVCaptureDevice] else {
print("摄像头不可用")
return
}
guard let device = devices.filter({ $0.position == .front }).first else { return }
// 2.2.通过 device 创建 AVCaptureInput 对象
guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
// 2.3.将 input 添加到会话中
session.addInput(videoInput)
// 3.设置输出源
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: videoQueue)
session.addOutput(videoOutput)
// 4.设置预览图层
// let previewLayer = AVCaptureVideoPreviewLayer(session: session)
// previewLayer?.frame = view.bounds
// view.layer.addSublayer(previewLayer!)
previewLayer.frame = view.bounds
view.layer.insertSublayer(previewLayer, at: 0)
// 5.开始采集
session.startRunning()
}
@IBAction func stopCapture() {
// 停止采集
session.stopRunning()
previewLayer.removeFromSuperlayer()
print("停止采集")
}
extension ViewController : AVCaptureVideoDataOutSampleBufferDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
// sampleBuffer 就是我们拿到的画面,美颜等操作都是对 sampleBuffer 进行的
print("已经采集到视频")
}
}
获取摄像头时,也可以这样遍历
var device : AVCaptureDevice!
for d in devices {
if d.position == .front {
device = d
break
}
}
或者通过闭包
let device = devices.filter { (device : AVCaptureDevice) -> Bool in
return device.position == .front
}.first
不过还是推荐第一种,比较简洁,一行代码就搞定了( $0 表示数组内第一个元素)
guard let device = devices.filter({ $0.position == .front }).first else { return }
音频采集部分
extension ViewController {
@IBAction func startCapture() {
// 1.设置视频输入、输出
setupVideo()
// 2.设置音频输入、输出
setupAudio()
// 3.设置预览图层
previewLayer.frame = view.bounds
view.layer.insertSublayer(previewLayer, at: 0)
// 4.开始采集
session.startRunning()
}
@IBAction func stopCapture() {
// 停止采集
session.stopRunning()
previewLayer.removeFromSuperlayer()
print("停止采集")
}
}
extension ViewController {
fileprivate func setupVideo() {
// 1.设置输入源(摄像头)
// 1.1.获取摄像头设备
guard let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as? [AVCaptureDevice] else {
print("摄像头不可用")
return
}
guard let device = devices.filter({ $0.position == .front }).first else { return }
// 1.2.通过 device 创建 AVCaptureInput 对象
guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
// 1.3.将 input 添加到会话中
session.addInput(videoInput)
// 2.设置输出源
let videoOutput = AVCaptureVideoDataOutput()
videoOutput.setSampleBufferDelegate(self, queue: videoQueue)
session.addOutput(videoOutput)
}
fileprivate func setupAudio() {
}
}
import UIKit
import AVFoundation
class ViewController: UIViewController {
fileprivate lazy var videoQueue = DispatchQueue.global()
fileprivate lazy var audioQueue = DispatchQueue.global()
fileprivate lazy var session : AVCaptureSession = AVCaptureSession()
fileprivate lazy var previewLayer : AVCaptureVideoPreviewLayer = AVCaptureVideoPreviewLayer(session: self.session)
}
fileprivate func setupAudio() {
// 1.设置输入源(麦克风)
// 1.1.获取麦克风
guard let device = AVCaptureDevice.defaultDevice(withMediaType: AVMediaTypeAudio) else { return }
// 1.2.根据 device 创建 AVCaptureInput
guard let audioInput = try? AVCaptureDeviceInput(device: device) else { return }
// 1.3.将 input 添加到会话中
session.addInput(audioInput)
// 2.设置输出源
let audioOutput = AVCaptureAudioDataOutput()
audioOutput.setSampleBufferDelegate(self, queue: audioQueue)
session.addOutput(audioOutput)
}
extension ViewController : AVCaptureVideoDataOutSampleBufferDelegate, AVCaptureAudioDataOutSampleBufferDelegate {
// 获取音频数据的代理方法是一样的
// 所以为了区分拿到的是视频还是音频数据,我们一般通过 connection 来判断
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
print("已经采集到音频")
}
}
fileprivate func setupVideo() {
// 1.设置输入源(摄像头)
// 1.1.获取摄像头设备
// 1.2.通过 device 创建 AVCaptureInput 对象
// 1.3.将 input 添加到会话中
// 2.设置输出源
// 3.获取 video 对应的 connection
connection = videoOutput.connection(withMediaType: AVMediaTypeVideo)
}
// 因为这的 connection 是个局部变量,在代理方法中拿不到,所以定义一个 connection
class ViewController: UIViewController {
fileprivate var connection : AVCaptureConnection?
}
extension ViewController : AVCaptureVideoDataOutSampleBufferDelegate, AVCaptureAudioDataOutSampleBufferDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
if connection == self. connection {
print("已经采集视频—-video")
} else {
print("已经采集音频--audio")
}
}
}
切换镜头操作
// 因为切换镜头,需要拿到之前的视频输入源
// 而之前的输入源是局部,切换镜头方法中拿不到,所以定义一个 videoInput
class ViewController: UIViewController {
fileprivate var videoInput : AVCaptureDeviceInput?
}
// 然后在 setupVideo() 中的 2.2 赋值给 videoInput
// 2.2.通过 device 创建 AVCaptureInput 对象
guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
self.videoInput = videoInput
@IBAction func switchScene() {
// 1.获取当前镜头
guard var position = videoInput?.device.position else { return }
// 2.获取将要显示镜头
position = position == .front ? .back : .front
// 3.根据将要显示镜头创建 device
let devices = AVCaptureDevice.devices(withMediaType: AVMediaTypeVideo) as! [AVCaptureDevice]
guard let device = devices.filter({ $0.position == position }).first else { return }
// 4.根据 device 创建 input
guard let videoInput = try? AVCaptureDeviceInput(device: device) else { return }
// 5.在 session 中切换 input
session.beginConfiguration()
session.removeInput(self.videoInput!)
session.addInput(videoInput)
session.commitConfiguration()
self.videoInput = videoInput
print("切换镜头")
}
这时运行程序,切换镜头后会发现控制台只打印“已经采集音频--audio”。因为镜头切换,之前获得的 connection 也会改变,所以我们还要进行一个操作,获取新的 connection
fileprivate var connection : AVCaptureConnection?
connection = videoOutput.connection(withMediaType: AVMediaTypeVideo)
然后定义 videoOutput,通过 videoOutput 获取新的 connection
class ViewController: UIViewController {
fileprivate var videoOutput : AVCaptureVideoDataOutput?
}
// 然后修改 setupVideo() 中的 3 步骤,也就是删除之前获取 connection 的步骤,赋值给 videoOutput
// 3.获取 video 对应的 connection
self.videoOutput = videoOutput
extension ViewController : AVCaptureVideoDataOutputSampleBufferDelegate, AVCaptureAudioDataOutputSampleBufferDelegate {
func captureOutput(_ captureOutput: AVCaptureOutput!, didOutputSampleBuffer sampleBuffer: CMSampleBuffer!, from connection: AVCaptureConnection!) {
if connection == videoOutput?.connection(withMediaType: AVMediaTypeVideo) {
print("已经采集视频—-video")
} else {
print("已经采集音频--audio")
}
}
}
文件写入部分
class ViewController: UIViewController {
fileprivate var movieOutput : AVCaptureMovieFileOutput?
}
@IBAction func startCapture() {
// 1.设置视频输入、输出
// 2.设置音频输入、输出
// 3.添加写入文件的 output
let movieOutput = AVCaptureMovieFileOutput()
session.addOutput(movieOutput)
self.movieOutput = movieOutput
// 设置写入稳定性(不做这一步可能会丢帧)
let connection = movieOutput.connection(withMediaType: AVMediaTypeVideo)
connection?.preferredVideoStabilizationMode = .auto
// 4.设置预览图层
// 5.开始采集
// 6.将采集到的画面写入到文件中
let path = NSSearchPathForDirectoriesInDomains(.documentDirectory, .userDomainMask, true).first! + "/test.mp4"
let url = URL(fileURLWithPath: path)
movieOutput.startRecording(toOutputFileURL: url, recordingDelegate: self)
}
@IBAction func stopCapture() {
// 停止写入
movieOutput?.stopRecording()
print("停止写入")
// 停止采集
session.stopRunning()
previewLayer.removeFromSuperlayer()
print("停止采集")
}
extension ViewController : AVCaptureFileOutputRecordingDelegate {
func capture(_ captureOutput: AVCaptureFileOutput!, didStartRecordingToOutputFileAt fileURL: URL!, fromConnections connections: [Any]!) {
print("开始写入文件")
}
func capture(_ captureOutput: AVCaptureFileOutput!, didFinishRecordingToOutputFileAt outputFileURL: URL!, fromConnections connections: [Any]!, error: Error!) {
print("结束写入文件")
}
}
这样就完成了视频的采集,并将视频写入了沙盒。
我有一个Ruby程序,它使用rubyzip压缩XML文件的目录树。gem。我的问题是文件开始变得很重,我想提高压缩级别,因为压缩时间不是问题。我在rubyzipdocumentation中找不到一种为创建的ZIP文件指定压缩级别的方法。有人知道如何更改此设置吗?是否有另一个允许指定压缩级别的Ruby库? 最佳答案 这是我通过查看rubyzip内部创建的代码。level=Zlib::BEST_COMPRESSIONZip::ZipOutputStream.open(zip_file)do|zip|Dir.glob("**/*")d
我试图在一个项目中使用rake,如果我把所有东西都放到Rakefile中,它会很大并且很难读取/找到东西,所以我试着将每个命名空间放在lib/rake中它自己的文件中,我添加了这个到我的rake文件的顶部:Dir['#{File.dirname(__FILE__)}/lib/rake/*.rake'].map{|f|requiref}它加载文件没问题,但没有任务。我现在只有一个.rake文件作为测试,名为“servers.rake”,它看起来像这样:namespace:serverdotask:testdoputs"test"endend所以当我运行rakeserver:testid时
我的目标是转换表单输入,例如“100兆字节”或“1GB”,并将其转换为我可以存储在数据库中的文件大小(以千字节为单位)。目前,我有这个:defquota_convert@regex=/([0-9]+)(.*)s/@sizes=%w{kilobytemegabytegigabyte}m=self.quota.match(@regex)if@sizes.include?m[2]eval("self.quota=#{m[1]}.#{m[2]}")endend这有效,但前提是输入是倍数(“gigabytes”,而不是“gigabyte”)并且由于使用了eval看起来疯狂不安全。所以,功能正常,
Rails2.3可以选择随时使用RouteSet#add_configuration_file添加更多路由。是否可以在Rails3项目中做同样的事情? 最佳答案 在config/application.rb中:config.paths.config.routes在Rails3.2(也可能是Rails3.1)中,使用:config.paths["config/routes"] 关于ruby-on-rails-Rails3中的多个路由文件,我们在StackOverflow上找到一个类似的问题
对于具有离线功能的智能手机应用程序,我正在为Xml文件创建单向文本同步。我希望我的服务器将增量/差异(例如GNU差异补丁)发送到目标设备。这是计划:Time=0Server:hasversion_1ofXmlfile(~800kiB)Client:hasversion_1ofXmlfile(~800kiB)Time=1Server:hasversion_1andversion_2ofXmlfile(each~800kiB)computesdeltaoftheseversions(=patch)(~10kiB)sendspatchtoClient(~10kiBtransferred)Cl
我正在寻找执行以下操作的正确语法(在Perl、Shell或Ruby中):#variabletoaccessthedatalinesappendedasafileEND_OF_SCRIPT_MARKERrawdatastartshereanditcontinues. 最佳答案 Perl用__DATA__做这个:#!/usr/bin/perlusestrict;usewarnings;while(){print;}__DATA__Texttoprintgoeshere 关于ruby-如何将脚
使用带有Rails插件的vim,您可以创建一个迁移文件,然后一次性打开该文件吗?textmate也可以这样吗? 最佳答案 你可以使用rails.vim然后做类似的事情::Rgeneratemigratonadd_foo_to_bar插件将打开迁移生成的文件,这正是您想要的。我不能代表textmate。 关于ruby-使用VimRails,您可以创建一个新的迁移文件并一次性打开它吗?,我们在StackOverflow上找到一个类似的问题: https://sta
好的,所以我的目标是轻松地将一些数据保存到磁盘以备后用。您如何简单地写入然后读取一个对象?所以如果我有一个简单的类classCattr_accessor:a,:bdefinitialize(a,b)@a,@b=a,bendend所以如果我从中非常快地制作一个objobj=C.new("foo","bar")#justgaveitsomerandomvalues然后我可以把它变成一个kindaidstring=obj.to_s#whichreturns""我终于可以将此字符串打印到文件或其他内容中。我的问题是,我该如何再次将这个id变回一个对象?我知道我可以自己挑选信息并制作一个接受该信
我正在编写一个小脚本来定位aws存储桶中的特定文件,并创建一个临时验证的url以发送给同事。(理想情况下,这将创建类似于在控制台上右键单击存储桶中的文件并复制链接地址的结果)。我研究过回形针,它似乎不符合这个标准,但我可能只是不知道它的全部功能。我尝试了以下方法:defauthenticated_url(file_name,bucket)AWS::S3::S3Object.url_for(file_name,bucket,:secure=>true,:expires=>20*60)end产生这种类型的结果:...-1.amazonaws.com/file_path/file.zip.A
我注意到像bundler这样的项目在每个specfile中执行requirespec_helper我还注意到rspec使用选项--require,它允许您在引导rspec时要求一个文件。您还可以将其添加到.rspec文件中,因此只要您运行不带参数的rspec就会添加它。使用上述方法有什么缺点可以解释为什么像bundler这样的项目选择在每个规范文件中都需要spec_helper吗? 最佳答案 我不在Bundler上工作,所以我不能直接谈论他们的做法。并非所有项目都checkin.rspec文件。原因是这个文件,通常按照当前的惯例,只