iOS 录制视频

作者: Abson在简书 | 来源:发表于2015-11-25 00:41 被阅读11710次

最近开发中遇到一个需求,就是想微信那样录制一个小视频,然后在录制视频的图层上播放,然后发布到朋友圈,无声播放,但有滚动起来不影响性能。一开始接到这个需求的时候我是很兴奋的,可以好好研究一番 AVFoundation 的东西了。但是在研究中不断的高潮迭起,也是让我心力交瘁呀。但是,做程序猿的成长就是这样的嘛。题外话了,好了,今天我们就说一下怎么用 AVCaptureSession + __ AVCaptureMovieFileOutput__ 来录制视频,并通过AVAssetExportSeeion 手段来压缩视频并转换为 MP4 格式

一开始我们要了解一下 AVFoundation 做视频的类应该有那些,并且他们有什么用呢?

AVCaptureSession

 AVCaptureSession:媒体(音、视频)捕获会话,负责把捕获的音视频数据输出到输出设备中。一个AVCaptureSession可以有多个输入输出。
 AVCaptureDevice :输入设备,包括麦克风、摄像头,通过该对象可以设置物理设备的一些属性(例如相机聚焦、白平衡等)。
 AVCaptureDeviceInput :设备输入数据管理对象,可以根据AVCaptureDevice创建对应的AVCaptureDeviceInput对象,该对象将会被添加到AVCaptureSession中管理。
 AVCaptureVideoPreviewLayer :相机拍摄预览图层,是CALayer的子类,使用该对象可以实时查看拍照或视频录制效果,创建该对象需要指定对应的 AVCaptureSession对象。

 AVCaptureOutput :输出数据管理对象,用于接收各类输出数据,通常使用对应的子类AVCaptureAudioDataOutput、AVCaptureStillImageOutput、
 AVCaptureVideoDataOutput、AVCaptureFileOutput, 该对象将会被添加到AVCaptureSession中管理。
 注意:前面几个对象的输出数据都是NSData类型,而AVCaptureFileOutput代表数据以文件形式输出,类似的,AVCcaptureFileOutput也不会直接创建使用,通常会使用其子类:
 AVCaptureAudioFileOutput、AVCaptureMovieFileOutput。当把一个输入或者输出添加到AVCaptureSession之后AVCaptureSession就会在所有相符的输入、输出设备之间
 建立连接(AVCaptionConnection)。

那么建立视频拍摄的步骤如下 :
1.创建AVCaptureSession对象。

// 创建会话 (AVCaptureSession) 对象。
_captureSession = [[AVCaptureSession alloc] init];
if ([_captureSession canSetSessionPreset:AVCaptureSessionPreset640x480]) {
    // 设置会话的 sessionPreset 属性, 这个属性影响视频的分辨率
    [_captureSession setSessionPreset:AVCaptureSessionPreset640x480];
}

2.使用AVCaptureDevice的静态方法获得需要使用的设备,例如拍照和录像就需要获得摄像头设备,录音就要获得麦克风设备。

// 获取摄像头输入设备, 创建 AVCaptureDeviceInput 对象
// 在获取摄像头的时候,摄像头分为前后摄像头,我们创建了一个方法通过用摄像头的位置来获取摄像头 
AVCaptureDevice *videoCaptureDevice = [self getCameraDeviceWithPosition:AVCaptureDevicePositionBack];
if (!captureDevice) {
    NSLog(@"---- 取得后置摄像头时出现问题---- ");
    return;
}

// 添加一个音频输入设备
// 直接可以拿数组中的数组中的第一个
AVCaptureDevice *audioCaptureDevice = [[AVCaptureDevice devicesWithMediaType:AVMediaTypeAudio] firstObject];

3.利用输入设备AVCaptureDevice初始化AVCaptureDeviceInput对象。

// 视频输入对象
// 根据输入设备初始化输入对象,用户获取输入数据
_videoCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:captureDevice error:&error];
if (error) {
    NSLog(@"---- 取得设备输入对象时出错 ------ %@",error);
    return;
} 

//  音频输入对象
//根据输入设备初始化设备输入对象,用于获得输入数据
_audioCaptureDeviceInput = [[AVCaptureDeviceInput alloc] initWithDevice:audioCaptureDevice error:&error];
if (error) {
    NSLog(@"取得设备输入对象时出错 ------ %@",error);
    return;
}

4.初始化输出数据管理对象,如果要拍照就初始化AVCaptureStillImageOutput对象;如果拍摄视频就初始化AVCaptureMovieFileOutput对象。

// 拍摄视频输出对象
// 初始化输出设备对象,用户获取输出数据
_caputureMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];

5.将数据输入对象AVCaptureDeviceInput、数据输出对象AVCaptureOutput添加到媒体会话管理对象AVCaptureSession中。

// 将视频输入对象添加到会话 (AVCaptureSession) 中
if ([_captureSession canAddInput:_videoCaptureDeviceInput]) {
    [_captureSession addInput:_videoCaptureDeviceInput];
}

// 将音频输入对象添加到会话 (AVCaptureSession) 中
if ([_captureSession canAddInput:_captureDeviceInput]) {
    [_captureSession addInput:audioCaptureDeviceInput];
    AVCaptureConnection *captureConnection = [_caputureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    // 标识视频录入时稳定音频流的接受,我们这里设置为自动
    if ([captureConnection isVideoStabilizationSupported]) {
        captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    }
}

6.创建视频预览图层AVCaptureVideoPreviewLayer并指定媒体会话,添加图层到显示容器中,调用AVCaptureSession的startRuning方法开始捕获。

// 通过会话 (AVCaptureSession) 创建预览层
_captureVideoPreviewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];

// 显示在视图表面的图层
CALayer *layer = self.viewContrain.layer;
layer.masksToBounds = true;

_captureVideoPreviewLayer.frame = layer.bounds;
_captureVideoPreviewLayer.masksToBounds = true;
_captureVideoPreviewLayer.videoGravity=AVLayerVideoGravityResizeAspectFill;//填充模式
[layer addSublayer:_captureVideoPreviewLayer];

// 让会话(AVCaptureSession)勾搭好输入输出,然后把视图渲染到预览层上
[_captureSession startRunning];

7.将捕获的音频或视频数据输出到指定文件。

创建一个拍摄的按钮,当我们点击这个按钮就会触发视频录制,并将这个录制的视频放到 temp 文件夹中

- (IBAction)takeMovie:(id)sender {
[(UIButton *)sender setSelected:![(UIButton *)sender isSelected]];
if ([(UIButton *)sender isSelected]) {
     AVCaptureConnection *captureConnection=[self.caputureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    // 开启视频防抖模式
    AVCaptureVideoStabilizationMode stabilizationMode = AVCaptureVideoStabilizationModeCinematic;
    if ([self.captureDeviceInput.device.activeFormat isVideoStabilizationModeSupported:stabilizationMode]) {
        [captureConnection setPreferredVideoStabilizationMode:stabilizationMode];
    }
    
    //如果支持多任务则则开始多任务
    if ([[UIDevice currentDevice] isMultitaskingSupported]) {
       self.backgroundTaskIdentifier = [[UIApplication sharedApplication] beginBackgroundTaskWithExpirationHandler:nil];
    }
    // 预览图层和视频方向保持一致,这个属性设置很重要,如果不设置,那么出来的视频图像可以是倒向左边的。
    captureConnection.videoOrientation=[self.captureVideoPreviewLayer connection].videoOrientation;
    
   // 设置视频输出的文件路径,这里设置为 temp 文件
    NSString *outputFielPath=[NSTemporaryDirectory() stringByAppendingString:MOVIEPATH];
    
    // 路径转换成 URL 要用这个方法,用 NSBundle 方法转换成 URL 的话可能会出现读取不到路径的错误
    NSURL *fileUrl=[NSURL fileURLWithPath:outputFielPath];
    
   // 往路径的 URL 开始写入录像 Buffer ,边录边写
    [self.caputureMovieFileOutput startRecordingToOutputFileURL:fileUrl recordingDelegate:self];
}
else {
   // 取消视频拍摄
    [self.caputureMovieFileOutput stopRecording];
    [self.captureSession stopRunning];
    [self completeHandle];
}
}

当然我们录制的开始与结束都是有监听方法的,AVCaptureFileOutputRecordingDelegate 这个代理里面就有我们想要做的

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections
{
   NSLog(@"---- 开始录制 ----");
}

- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error
{
    NSLog(@"---- 录制结束 ----");
}

到此,我们录制视频就结束了,那么是不是我们录制好了视频,就可以马上把这个视频上传给服务器分享给你的小伙伴们看了呢?
我们可以用如下方法测试一下我们录制出来的视频有多大 (m)
- (CGFloat)getfileSize:(NSString *)path
{
NSDictionary *outputFileAttributes = [[NSFileManager defaultManager] attributesOfItemAtPath:path error:nil];
NSLog (@"file size: %f", (unsigned long long)[outputFileAttributes fileSize]/1024.00 /1024.00);
return (CGFloat)[outputFileAttributes fileSize]/1024.00 /1024.00;
}
个人在这里做过测试,录制了 10s 的小视频得到的文件大小为 4.1M 左右,而且我用的分辨率还是640x480。。。很无语了是不是?
如果我们录制的视频,录制完成后要与服务器进行必要的上传,那么,我们肯定不能把这个刚刚录制出来的视频上传给服务器的,我们有必要对这个视频进行压缩了。那么我们的压缩方法,就要用到 AVAssetExportSeeion 这个类了。

// 这里我们创建一个按钮,当点击这个按钮,我们就会调用压缩视频的方法,然后再去重新计算大小,这样就会跟未被压缩前的大小有个明显的对比了


// 压缩视频
- (IBAction)compressVideo:(id)sender
{
    NSString *cachePath=[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES) lastObject];
    NSString *savePath=[cachePath stringByAppendingPathComponent:MOVIEPATH];
    NSURL *saveUrl=[NSURL fileURLWithPath:savePath];

    // 通过文件的 url 获取到这个文件的资源
    AVURLAsset *avAsset = [[AVURLAsset alloc] initWithURL:saveUrl options:nil];
    // 用 AVAssetExportSession 这个类来导出资源中的属性
    NSArray *compatiblePresets = [AVAssetExportSession exportPresetsCompatibleWithAsset:avAsset];

    // 压缩视频
    if ([compatiblePresets containsObject:AVAssetExportPresetLowQuality]) { // 导出属性是否包含低分辨率
    // 通过资源(AVURLAsset)来定义 AVAssetExportSession,得到资源属性来重新打包资源 (AVURLAsset, 将某一些属性重新定义
    AVAssetExportSession *exportSession = [[AVAssetExportSession alloc] initWithAsset:avAsset presetName:AVAssetExportPresetLowQuality];
    // 设置导出文件的存放路径
    NSDateFormatter *formatter = [[NSDateFormatter alloc] init];
    [formatter setDateFormat:@"yyyy-MM-dd-HH:mm:ss"];
    NSDate    *date = [[NSDate alloc] init];
    NSString *outPutPath = [[NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, true) lastObject] stringByAppendingPathComponent:[NSString stringWithFormat:@"output-%@.mp4",[formatter stringFromDate:date]]];
    exportSession.outputURL = [NSURL fileURLWithPath:outPutPath];
    
    // 是否对网络进行优化
    exportSession.shouldOptimizeForNetworkUse = true;
    
    // 转换成MP4格式
    exportSession.outputFileType = AVFileTypeMPEG4;
    
    // 开始导出,导出后执行完成的block
    [exportSession exportAsynchronouslyWithCompletionHandler:^{
        // 如果导出的状态为完成
        if ([exportSession status] == AVAssetExportSessionStatusCompleted) {
            dispatch_async(dispatch_get_main_queue(), ^{
                // 更新一下显示包的大小
                self.videoSize.text = [NSString stringWithFormat:@"%f MB",[self getfileSize:outPutPath]];
            });
        }
    }];
}
}

经过我们的压缩,这个时候10s 的 4M 视频就只剩下不够 1M 了。


以下是一些扩展

自动闪光灯开启

- (IBAction)flashAutoClick:(UIButton *)sender {
    [self setFlashMode:AVCaptureFlashModeAuto];
    [self setFlashModeButtonStatus];
}

打开闪光灯

- (IBAction)flashOnClick:(UIButton *)sender {
    [self setFlashMode:AVCaptureFlashModeOn];
    [self setFlashModeButtonStatus];
}

关闭闪光灯

- (IBAction)flashOffClick:(UIButton *)sender {
    [self setFlashMode:AVCaptureFlashModeOff];
    [self setFlashModeButtonStatus];
}

通知

/**
 *  给输入设备添加通知
 */
-(void)addNotificationToCaptureDevice:(AVCaptureDevice *)captureDevice{
//注意添加区域改变捕获通知必须首先设置设备允许捕获
[self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
    captureDevice.subjectAreaChangeMonitoringEnabled=YES;
}];
NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
//捕获区域发生改变
[notificationCenter addObserver:self selector:@selector(areaChange:) name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];
}
-(void)removeNotificationFromCaptureDevice:(AVCaptureDevice *)captureDevice{
NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
[notificationCenter removeObserver:self name:AVCaptureDeviceSubjectAreaDidChangeNotification object:captureDevice];
}
/**
 *  移除所有通知
 */
-(void)removeNotification{
    NSNotificationCenter *notificationCenter= [NSNotificationCenter     defaultCenter];
    [notificationCenter removeObserver:self];
}

-(void)addNotificationToCaptureSession:(AVCaptureSession *)captureSession{
NSNotificationCenter *notificationCenter= [NSNotificationCenter defaultCenter];
//会话出错
[notificationCenter addObserver:self selector:@selector(sessionRuntimeError:) name:AVCaptureSessionRuntimeErrorNotification object:captureSession];
}

/**
 *  设备连接成功
 *
 *  @param notification 通知对象
 */
-(void)deviceConnected:(NSNotification *)notification{
    NSLog(@"设备已连接...");
}
/**
 *  设备连接断开
 *
 *  @param notification 通知对象
 */
-(void)deviceDisconnected:(NSNotification *)notification{
NSLog(@"设备已断开.");
}
/**
 *  捕获区域改变
 *
 *  @param notification 通知对象
 */
-(void)areaChange:(NSNotification *)notification{
    NSLog(@"捕获区域改变...");
}

/**
 *  会话出错
 *
 *  @param notification 通知对象
 */
-(void)sessionRuntimeError:(NSNotification *)notification{
NSLog(@"会话发生错误.");

}

私有方法

/**
 *  取得指定位置的摄像头
 *
 *  @param position 摄像头位置
 *
 *  @return 摄像头设备
 */
-(AVCaptureDevice *)getCameraDeviceWithPosition:(AVCaptureDevicePosition )position{
    NSArray *cameras= [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *camera in cameras) {
        if ([camera position]==position) {
            return camera;
        }
    }
    return nil;
}

/**
 *  改变设备属性的统一操作方法
 *
 *  @param propertyChange 属性改变操作
 */
-(void)changeDeviceProperty:(PropertyChangeBlock)propertyChange{
    AVCaptureDevice *captureDevice= [self.captureDeviceInput device];
    NSError *error;
    //注意改变设备属性前一定要首先调用lockForConfiguration:调用完之后使用unlockForConfiguration方法解锁
    if ([captureDevice lockForConfiguration:&error]) {
        propertyChange(captureDevice);
        [captureDevice unlockForConfiguration];
    }else{
        NSLog(@"设置设备属性过程发生错误,错误信息:%@",error.localizedDescription);
    }
}

/**
 *  设置闪光灯模式
 *
 *  @param flashMode 闪光灯模式
 */
-(void)setFlashMode:(AVCaptureFlashMode )flashMode{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFlashModeSupported:flashMode]) {
            [captureDevice setFlashMode:flashMode];
        }
    }];
}
/**
 *  设置聚焦模式
 *
 *  @param focusMode 聚焦模式
 */
-(void)setFocusMode:(AVCaptureFocusMode )focusMode{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFocusModeSupported:focusMode]) {
            [captureDevice setFocusMode:focusMode];
        }
    }];
}
/**
 *  设置曝光模式
 *
 *  @param exposureMode 曝光模式
 */
-(void)setExposureMode:(AVCaptureExposureMode)exposureMode{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isExposureModeSupported:exposureMode]) {
            [captureDevice setExposureMode:exposureMode];
        }
    }];
}

/**
 *  设置聚焦点
 *
 *  @param point 聚焦点
 */
-(void)focusWithMode:(AVCaptureFocusMode)focusMode exposureMode:(AVCaptureExposureMode)exposureMode atPoint:(CGPoint)point{
    [self changeDeviceProperty:^(AVCaptureDevice *captureDevice) {
        if ([captureDevice isFocusModeSupported:focusMode]) {
            [captureDevice setFocusMode:AVCaptureFocusModeAutoFocus];
        }
        if ([captureDevice isFocusPointOfInterestSupported]) {
            [captureDevice setFocusPointOfInterest:point];
        }
        if ([captureDevice isExposureModeSupported:exposureMode]) {
            [captureDevice setExposureMode:AVCaptureExposureModeAutoExpose];
        }
        if ([captureDevice isExposurePointOfInterestSupported]) {
            [captureDevice setExposurePointOfInterest:point];
        }
    }];
}

/**
 *  添加点按手势,点按时聚焦
 */
-(void)addGenstureRecognizer{
UITapGestureRecognizer *tapGesture=[[UITapGestureRecognizer alloc]initWithTarget:self action:@selector(tapScreen:)];
    [self.viewContainer addGestureRecognizer:tapGesture];
}
-(void)tapScreen:(UITapGestureRecognizer *)tapGesture{
    CGPoint point= [tapGesture locationInView:self.viewContainer];
    //将UI坐标转化为摄像头坐标
    CGPoint cameraPoint= [self.captureVideoPreviewLayer captureDevicePointOfInterestForPoint:point];
    [self setFocusCursorWithPoint:point];
    [self focusWithMode:AVCaptureFocusModeAutoFocus exposureMode:AVCaptureExposureModeAutoExpose atPoint:cameraPoint];
}

/**
 *  设置闪光灯按钮状态
 */
-(void)setFlashModeButtonStatus{
    AVCaptureDevice *captureDevice=[self.captureDeviceInput device];
    AVCaptureFlashMode flashMode=captureDevice.flashMode;
    if([captureDevice isFlashAvailable]){
        self.flashAutoButton.hidden=NO;
    self.flashOnButton.hidden=NO;
    self.flashOffButton.hidden=NO;
    self.flashAutoButton.enabled=YES;
    self.flashOnButton.enabled=YES;
    self.flashOffButton.enabled=YES;
    switch (flashMode) {
        case AVCaptureFlashModeAuto:
            self.flashAutoButton.enabled=NO;
            break;
        case AVCaptureFlashModeOn:
            self.flashOnButton.enabled=NO;
            break;
        case AVCaptureFlashModeOff:
            self.flashOffButton.enabled=NO;
            break;
        default:
            break;
    }
}else{
    self.flashAutoButton.hidden=YES;
    self.flashOnButton.hidden=YES;
    self.flashOffButton.hidden=YES;
}
}

/**
 *  设置聚焦光标位置
 *
 *  @param point 光标位置
 */
-(void)setFocusCursorWithPoint:(CGPoint)point{
    self.focusCursor.center=point;
    self.focusCursor.transform=CGAffineTransformMakeScale(1.5, 1.5);
    self.focusCursor.alpha=1.0;
    [UIView animateWithDuration:1.0 animations:^{
        self.focusCursor.transform=CGAffineTransformIdentity;
    } completion:^(BOOL finished) {
        self.focusCursor.alpha=0;
    
    }];
}

@end

心如止水,奋力前行

相关文章

网友评论

  • MissLu16:同求demo.(1922562135@qq.com)
  • GG266:前置摄像头拍摄完成会有镜面效果,为前置摄像头的connect设置了videoMirrored为yes,videoOrientation为Portrait也没有达到所预想的效果。所以,想请问博主有没有解决这个问题,或者所大家一起讨论一下这个问题
  • 西风颂:亲,麻烦问一下就是横屏录制的视频在播放的时候为什么是竖屏播放呢?怎么才能设置为横屏播放呢?
  • Society2012:录制的视频和音频是分开的吗?
  • zhaihongxia:请问,这样写录制视频时会不会手机发热
  • 妹子爱编程:AVCaptureConnection *captureConnection = [_caputureMovieFileOutput connectionWithMediaType:AVMediaTypeVideo];
    // 标识视频录入时稳定音频流的接受,我们这里设置为自动
    if ([captureConnection isVideoStabilizationSupported]) {
    captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    }

    大神我用swift 重写你的这个代码,为啥运行的时候这里总是崩溃
  • xclidongbo:怎么自定义视频的尺寸? 比如16:9 大小的.
  • KeepStrong:求楼主一份demo,邮箱1301808418@qq.com
  • zero000:感谢分享,求demo 1915853255@qq.com
  • 232ae72d57c9:发下源码谢谢啦:pray:lynne0522@163.com
  • 来宝:大神,demo 460876003@qq.com
  • 277ccd5ab3f3:这样录制的视频格式是什么呢
  • LV大树:弱弱问一下留邮箱会有DEMO吗?
  • LV大树:好人一生苹果平安。
  • 安静野心家:录像写入时写到temp目录,而压缩成MP4时却是从document目录取出来压缩,逗我呢???而且添加输出设备也没写,if([_session canAddOutput:_output]){
    [_session addOutput:_output];
    }
    安静野心家:@葱神大大 你明白我说的什么吗?我哪里表达了我不明白压缩视频的用意?我说的是你这篇文章的内容,录像写入在A目录,然后压缩时不应该从A目录取出来吗?而你是从B目录取出来。那么问题来了,你录的视频是怎么从A目录到B目录的?
    Abson在简书:@安静野心家 压缩只是为了上传文件体积减少,自己观看的是高清的视频,明白么,跟图片是同一个道理
  • 常绿箩:写的很不错,请问可以给下demo吗,1944606304@qq.com
  • 柯柯格格:一看就知道,从网上copy过来的,九成以上可能没有自己敲一下,有些通知都已经废弃了,根本不能用,哎
    Abson在简书:@柯柯格格 我在项目当中还用着呢!心浮气躁之人,将项目得东西分享出来了,不懂感恩就算了,还指望别人帮你写完,写好?那你留美一点自学能力?靠什么在这个行业立足呢?
    柯柯格格:@葱神大大 你就说你自己测试了没就可以了,如果测试了,我给你道歉
    Abson在简书:@柯柯格格 是吧,别人的成果你还诋毁,不知所谓,不跟你这种人一般见识
  • 凯文Kevin21:大神,可以把demo放到github上去啊。开源大法好啊,java保平安。
  • AKinCoder:640*480 视频预览是正方形的,拍摄完成后又称3:4了,怎么破?
  • Y像梦一样自由:大神,同求demo 邮箱376113892@qq.com
  • 经文纬武:大神能发个demo吗 2834384208@qq.com
  • 丶逝水流年:大神,求个demo 905736705@qq.com
  • ea5b2dd6cdd0:求一份Demo大神,825797402@qq.com
  • 经文纬武:求大神发个演示。现在公司要求做个小​​视频上传功能,急,拜托了。 28343384208 @ qq.com
  • ef60b7f382dc:10829580@qq.com 朋友,请发一份demo,感谢。
  • 原味豆浆:大神,求demo(495419587@qq.com)
  • 天亮説晚安:请教一个问题,发现视频播放时候的比例一直是3:4,如何修改这个比例呢?或者如何调整视频播放时的大小呢?
  • Jennifer_鑫:大神,为什么程序启动的时候,屏幕会先黑一下?
  • SAW_: 请教个问题,在tableView上,没当cell出现的时候,尽心赋值,给avplayer设置AVPlayerItem的时候,总是卡顿,视频一多,就卡的不要不要的,有什么思路吗?
    文兴:如果怕滚动的时候,视频是黑的,可以用一个imageview覆盖,播放的时候隐藏就行
    文兴:@SAW 监听srollviewdidend事件,滚动结束才设置playeritem
  • Peak_One:大神求 demo lxh_ios@126.com
  • 72b1e4f01ff8:求demo,大神,muyunli627@163.com
  • 8bad0e5aeda6:求demo youlong118@qq.com
  • 18d8bae340ec:大神求下demo 1443466376@qq.com
  • style_施:怎么获取你录制视频的路径 然后上传呢?
  • RYC:求 DeMO A 787725121@qq.com 大神
  • 6dbbc3992d92:mark 求教一下 ,如何录制双人视频的画面,我无法获取另一个人的视频源 ,所以我暂时只能录制自己的画面,也就是自己的视频源,这个你有涉及到么,求指教。谢谢
  • 桐生一猫:mark 一下 ,以后要压缩和转mp4格式 :+1:
  • zl520k:你好,能发一个demo给我吗?我的邮箱是373907050@qq.com,谢谢
  • 萧城x:大神 求demo 邮箱 asd3306642@qq.com
  • zhao1zhihui:求个demo大神1217212724@qq.com 谢谢!!
  • 1525defe0eda:1250253467@qq.com谢谢!!!
  • puppySweet:你怎么还没有更新啊……
  • O_Mys:如果使用那些私有的方法,是不是会导致APP审核通不过?
    前行哲:@O_Mys ...
    O_Mys:@止于浮水 取得指定位置的摄像头以及下面的方法,你不是写着是私有方法吗?
    Abson在简书:@O_Mys 这里并没有私有方法喔
  • 13ba66721fb5:大神,可以发个Demo吗? 1574463301@qq.com
  • 5aa454cbdc88:你压缩成lowquaitty 根本看不清楚啊 谁有办法大神们 这里的压缩还是不行啊
    Abson在简书:@puppySweet 这个比较复杂,就这么打几行字无法说明,而且 ffmpeg 这个库比较庞大,接下来我会写一写博客慢慢说明
    puppySweet:@止于浮水 ffmpeg怎么编译成h265
    Abson在简书:@WX了个g 那就用 ffmepg 吧,自己去编译一下,把包集成过去,编译成 h264就可以了
  • 欧阳蓝缺:代码这里有 https://github.com/AndyFightting/VideoRecord
    欧阳蓝缺:@puppySweet 没有。上面的代码也是我无意中找到的。只能再找找。
    puppySweet:@欧阳蓝缺 有没有 讲如何设置压缩比率 比特率 帧数 尺寸的demo AVsset搞了一周还是搞不定疯了哎
  • bellchen:求demo 1010542165@qq.com
  • 1bfe74af6929:798009633@qq.com,谢谢老板
  • 27ab7fcb648a:你好 方便发一份Demo吗 ? ( 695587725@qq.com ) 谢谢。
  • 权仔:大神,最好贴出源码git地址比较方便 也想学习下,发个demo吧 1551205489@qq.com ,谢谢
  • dengxf:求相关系列demo学习一下,之前对这边了解的不多
    dxf1125@126.com 3q.
  • ryugaku:马克
  • 166ad58f7be3:大神 发个demo吧 10543398282qq.com
  • Se7ven:大神,跪求发个demo,谢谢!Q2502305577
  • 946e6dad0540:大牛求demo 494969990@qq.com
  • 8a3b2566b8ca:self.viewContrain指的是什么啊
  • 90a272ed37b2:可以的话希望大神贴下demo,最近也对这个很有兴趣
  • b1f19a146295:麻烦您发给Demo给我借鉴学习一下,谢谢 hnistduanao@outlook.com
  • 44bc540e0746:能发个demo吗,谢谢了(1214044269@qq.com)
  • youn_ger:能不能把写的demo上传一下贴个地址出来呢
  • 8c57f78d7ad6:谢谢分享,请问可以压缩成h.264格式吗
  • zgcrichard:可以考虑传到网盘上,地址贴出来。
  • 易木:1014003798@qq.com亲。可以发demo?
  • 进击的小学生:求demo,494969990@qq.com :heart_eyes:
  • 拾忆_aa:大神 你好 能否发个demo我学习下么 初学者 870037485@qq.com
  • 梦的梦:Demo能发邮箱吗 最近需要写视频录制 没有头绪 792237442@qq.com
  • 00d10f8a50de:1191548306@qq.com 谢了昂
  • Ashoka_APP:求demo 初学者 没怎么看懂563583336@qq.com
  • fcb856a4cf0e::heart_eyes:大神 求Demo1205822423@qq.com
  • 颖颖颖火的虫:大神 你好 能否发个demo我学习下 ,211818965@qq.com 谢谢啦
  • 平平无奇DeBug:写的很全面,我现在要做的也有这个,只是还要再加上一些滤镜效果。demo可否发一份参考,150861311@qq.com,另外怎么做添加滤镜效果,能指点一二么
    Abson在简书:@BlackRing GPUImage 能帮到你
  • e6a4db1a9746:大神,demo 496288307@qq.com
    b3b346dd7e43:能给我一份你写的demo吗?137338612@qq.com
    欧阳蓝缺:网上找的,https://github.com/AndyFightting/VideoRecord

本文标题:iOS 录制视频

本文链接:https://www.haomeiwen.com/subject/ukgrhttx.html