iOS 模仿微信的小視頻功能開發(fā)

著急的朋友直接翻到最下面的GitHub鏈接

先說(shuō)一下思路
  1. 創(chuàng)建捕獲會(huì)話AVCaptureSession.
  2. 創(chuàng)建捕獲輸入設(shè)備(輸入設(shè)備有兩個(gè):視頻輸入AVCaptureDeviceInput *videoInput;音頻輸入AVCaptureDeviceInput *audioInput)
  3. 創(chuàng)建捕獲視頻文件輸入AVCaptureMovieFileOutput.
  4. 將輸入、輸出加入到捕獲會(huì)話。
  5. 創(chuàng)建錄像預(yù)覽圖層AVCaptureVideoPreviewLayer.

==這里只放主要代碼,詳細(xì)的看demo,小視頻本人已封裝好,使用不到5行代碼就可以實(shí)現(xiàn)小視頻功能==

1.創(chuàng)建各種捕獲對(duì)象加入到捕獲會(huì)話中

- (void)zh_buildSession {
    // 捕獲會(huì)話
    _captureSession = [[AVCaptureSession alloc] init];
    if ([_captureSession canSetSessionPreset:AVCaptureSessionPresetHigh]) {
        [_captureSession setSessionPreset:AVCaptureSessionPresetHigh];
    }
    // 捕捉輸入
    // 攝像頭
    NSError *videoError = nil;
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo] error:&videoError];
    if (!videoInput || videoError) {
        NSLog(@"攝像頭設(shè)備創(chuàng)建失敗");
        return;
    }
    if ([_captureSession canAddInput:videoInput]) {
        [_captureSession addInput:videoInput];
        _videoInput = videoInput;
    } else {
        NSLog(@"會(huì)話無(wú)法加入攝像頭");
        return;
    }
    // 麥克風(fēng)
    NSError *audioError = nil;
    AVCaptureDeviceInput *audioInput = [AVCaptureDeviceInput deviceInputWithDevice:[AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio] error:&audioError];
    if (!audioInput || audioError) {
        NSLog(@"麥克風(fēng)設(shè)備創(chuàng)建失敗");
        return;
    }
    if ([_captureSession canAddInput:audioInput]) {
        [_captureSession addInput:audioInput];
    } else {
        NSLog(@"會(huì)話無(wú)法加入麥克風(fēng)");
        return;
    }
    // 視頻輸出
    _output = [[AVCaptureMovieFileOutput alloc] init];
    // 設(shè)置錄制模式
    AVCaptureConnection *captureConnection = [_output connectionWithMediaType:AVMediaTypeVideo];
    // 設(shè)置防抖
    if ([captureConnection isVideoStabilizationSupported]) {
        captureConnection.preferredVideoStabilizationMode = AVCaptureVideoStabilizationModeAuto;
    }
    if ([_captureSession canAddOutput:_output]) {
        [_captureSession addOutput:_output];
    } else {
        NSLog(@"會(huì)話無(wú)法加入輸出設(shè)備");
        return;
    }
    // 添加錄像圖層
    _previewLayer = [[AVCaptureVideoPreviewLayer alloc] initWithSession:_captureSession];
    _previewLayer.frame = CGRectMake(0.f, 0.f, [UIScreen mainScreen].bounds.size.width, [UIScreen mainScreen].bounds.size.height);
    _previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill; // 填充模式
    [self.view.layer addSublayer:_previewLayer];
}

2.創(chuàng)建3個(gè)操作按鈕(錄像、切換攝像頭、取消),這步要在創(chuàng)建捕捉會(huì)話后面,否則按鈕就添加到了預(yù)覽圖層下面

- (void)zh_buildUI {
    // 切換攝像頭
    _switchCameraBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [_switchCameraBtn setImage:[UIImage imageNamed:@"video_camera_0104"] forState:UIControlStateNormal];
    [_switchCameraBtn sizeToFit];
    _switchCameraBtn.frame = CGRectMake(self.view.frame.size.width - 15.f - _switchCameraBtn.frame.size.width, 30.f, _switchCameraBtn.frame.size.width, _switchCameraBtn.frame.size.height);
    [_switchCameraBtn addTarget:self action:@selector(zh_switchCameraButtonClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_switchCameraBtn];
    // 錄像按鈕
    _recordBtn = [ZHRecordButton buttonWithType:UIButtonTypeCustom];
    CGFloat recordBtnW = 60.f;
    _recordBtn.frame = CGRectMake(self.view.frame.size.width / 2 - recordBtnW / 2, self.view.frame.size.height - recordBtnW - recordBtnW, recordBtnW, recordBtnW);
    _recordBtn.zh_delegate = self;
    [_recordBtn addTarget:self action:@selector(zh_startRecording:) forControlEvents:UIControlEventTouchDown];
    [_recordBtn addTarget:self action:@selector(zh_endRecord:) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_recordBtn];
    // 取消按鈕
    _cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
    [_cancelBtn setImage:[UIImage imageNamed:@"video_close_0104"] forState:UIControlStateNormal];
    [_cancelBtn sizeToFit];
    _cancelBtn.center = _recordBtn.center;
    _cancelBtn.frame = CGRectMake(_recordBtn.frame.origin.x - 50.f * zScaleWidth - _cancelBtn.frame.size.width, _cancelBtn.frame.origin.y, _cancelBtn.frame.size.width, _cancelBtn.frame.size.height);
    [_cancelBtn addTarget:self action:@selector(zh_cancelButtonClick) forControlEvents:UIControlEventTouchUpInside];
    [self.view addSubview:_cancelBtn];
}

3.封裝錄像時(shí)的按鈕,錄像時(shí)轉(zhuǎn)動(dòng)圓環(huán)

// 繪制轉(zhuǎn)動(dòng)圓環(huán)
- (void)zh_circleAnimation {
    CAShapeLayer *circleLayer = [CAShapeLayer layer];
    circleLayer.frame = _animationLayer.bounds;
    [_animationLayer addSublayer:circleLayer];
    _circleLayer = circleLayer; // 指向這個(gè)layer用來(lái)刪除
    circleLayer.fillColor =  [UIColor clearColor].CGColor;
    circleLayer.strokeColor  = [UIColor greenColor].CGColor;
    circleLayer.lineWidth = 3.f;
    CGFloat radius = _animationLayer.bounds.size.width / 2 - circleLayer.lineWidth / 2;
    UIBezierPath *path = [UIBezierPath bezierPathWithArcCenter:circleLayer.position radius:radius startAngle:-M_PI / 2 endAngle:M_PI * 3 / 2 clockwise:true];
    circleLayer.path = path.CGPath;
    CABasicAnimation *checkAnimation = [CABasicAnimation animationWithKeyPath:@"strokeEnd"];
    checkAnimation.duration = 10;
    checkAnimation.fromValue = @(0.0f);
    checkAnimation.toValue = @(1.0f);
    [checkAnimation setValue:@"checkAnimation" forKey:@"animationName"];
    [circleLayer addAnimation:checkAnimation forKey:nil];
}

4.封裝小視頻錄制完的預(yù)覽播放

- (instancetype)initWithFrame:(CGRect)frame url:(NSURL *)url {
    self = [super initWithFrame:frame];
    if (self) {
        self.userInteractionEnabled = YES;
        // 監(jiān)聽播放完成通知,用來(lái)重復(fù)播放
        [[NSNotificationCenter defaultCenter] addObserver:self selector:@selector(zh_playFinish) name:AVPlayerItemDidPlayToEndTimeNotification object:nil];
        // 創(chuàng)建播放器
        _playerItem = [AVPlayerItem playerItemWithURL:url];
        _player = [AVPlayer playerWithPlayerItem:_playerItem];
        _playerLayer = [AVPlayerLayer playerLayerWithPlayer:_player];
        _playerLayer.frame = self.layer.bounds;
        _playerLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        [self.layer addSublayer:_playerLayer];
        [_player play];
        // 創(chuàng)建返回按鈕
        UIButton *cancelBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        cancelBtn.tag = 1000;
        [cancelBtn setImage:[UIImage imageNamed:@"video_return_0104"] forState:UIControlStateNormal];
        CGFloat cancelBtnW = 60.f;
        cancelBtn.center = CGPointMake(self.frame.size.width / 2, self.frame.size.height / 2);
        cancelBtn.frame = CGRectMake(cancelBtn.frame.origin.x, self.frame.size.height - cancelBtnW * 2, cancelBtnW, cancelBtnW);
        [cancelBtn addTarget:self action:@selector(zh_buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:cancelBtn];
        // 創(chuàng)建使用按鈕
        UIButton *confirmBtn = [UIButton buttonWithType:UIButtonTypeCustom];
        confirmBtn.tag = 1001;
        [confirmBtn setImage:[UIImage imageNamed:@"video_success_0104"] forState:UIControlStateNormal];
        [confirmBtn sizeToFit];
        confirmBtn.frame = cancelBtn.frame;
        [confirmBtn addTarget:self action:@selector(zh_buttonClick:) forControlEvents:UIControlEventTouchUpInside];
        [self addSubview:confirmBtn];
        // 移動(dòng)
        [self zh_moveButton:cancelBtn value:(-50 * zScaleWidth - cancelBtn.frame.size.width)]; // 左移需要多加一個(gè)按鈕的距離
        [self zh_moveButton:confirmBtn value:50 * zScaleWidth];
    }
    return self;
}

最后附上GitHub

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

友情鏈接更多精彩內(nèi)容