录制视频(无帧数版) IOS

本文介绍了如何使用特定代码片段更改以实现视频录制并设置文件输出功能,包括摄像头选择、预览显示、录制开始与停止等操作。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

利用网上提供的获取每一帧的代码更改过来的。

//
//  GLRecord.h
//  PlayVideo
//
//  Created by Ghost on 12-8-18.
//  Copyright (c) 2012年 ZEPPLAB. All rights reserved.
//

#import <UIKit/UIKit.h>

#import <AVFoundation/AVFoundation.h>
#undef PRODUCER_HAS_VIDEO_CAPTURE
#define PRODUCER_HAS_VIDEO_CAPTURE (__IPHONE_OS_VERSION_MIN_REQUIRED >= 40000 && TARGET_OS_EMBEDDED)
@protocol GLRecordDelegate ;
@interface GLRecord : NSObject
#if PRODUCER_HAS_VIDEO_CAPTURE
<AVCaptureFileOutputRecordingDelegate>
#endif
{
@private
    BOOL m_frontCamera;
    BOOL m_started;
    NSString *m_nameStr ;
    UIView* m_preview;
    id<GLRecordDelegate> outDelegate ;
#if PRODUCER_HAS_VIDEO_CAPTURE
    AVCaptureSession* m_captureSession;
    AVCaptureDevice *m_captureDevice;
    AVCaptureMovieFileOutput *m_captureMovieFileOutput ;
#endif
}
// 单例模式
+ (GLRecord*)shareGLRecord;
+ (void)closeCamera;
// 设置前置摄像头
- (BOOL)setFrontCamera;
// 设置后置摄像头
- (BOOL)setBackCamera;
// 开始前设置捕获参数
- (void)prepareVideoCaptureFrontCamera:(BOOL) v_bfront andPreview:(UIView*) v_view;
// 启动显示
- (void)startVideoCapture;
// 停止显示
- (void)stopVideoCapture;
// 开始录制
- (void)startRecording ;
// 停止录制
- (void)stopRecording ;
// 重置录制
- (void)resetRecording ;
// 设置要显示到得View
- (void)setPreview: (UIView*)v_preview;
// 设置数据输出
- (void)setVideoFileOutput:(id<GLRecordDelegate>)delegate;
// 设置文件保存名称
- (void)setVideoFileName:(NSString *) v_nameStr ;
@end

@protocol GLRecordDelegate
- (void) capture:(GLRecord *) glRecord didFailWithError:(NSError *)error;
- (void) captureRecordingBegan:(GLRecord *) glRecord;
- (void) captureRecordingFinished:(GLRecord *) glRecord;
@end
------------------------------------------------------------------------
//
//  GLRecord.m
//  PlayVideo
//
//  Created by Ghost on 12-8-18.
//  Copyright (c) 2012年 ZEPPLAB. All rights reserved.
//
#import "GLRecord.h"
//
//    Private
//
@interface  GLRecord(Private)

#define TEMP_MOVE_NAME @"TEMP_FILE.MOV"


#if PRODUCER_HAS_VIDEO_CAPTURE
+(AVCaptureDevice *)cameraAtPosition:(AVCaptureDevicePosition)position;
+ (NSURL *) tempFileURL ;
- (void)startPreview ;
- (void)stopPreview ;
#endif

@end

@implementation GLRecord (Private)

#if PRODUCER_HAS_VIDEO_CAPTURE
+ (AVCaptureDevice *)cameraAtPosition:(AVCaptureDevicePosition)position{
    NSArray *cameras = [AVCaptureDevice devicesWithMediaType:AVMediaTypeVideo];
    for (AVCaptureDevice *device in cameras){
        if (device.position == position){
            return device;
        }
    }
    return [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
}

+ (AVCaptureConnection *)connectionWithMediaType:(NSString *)mediaType fromConnections:(NSArray *)connections
{
    for ( AVCaptureConnection *connection in connections ) {
        for ( AVCaptureInputPort *port in [connection inputPorts] ) {
            if ( [[port mediaType] isEqual:mediaType] ) {
                return connection;
            }
        }
    }
    return nil;
}

+ (NSURL *) tempFileURL {
    return [NSURL fileURLWithPath:[NSString stringWithFormat:@"%@%@", NSTemporaryDirectory(), TEMP_MOVE_NAME]];
}

- (void)startPreview{
    if(m_captureSession && m_preview && m_started){
        AVCaptureVideoPreviewLayer* previewLayer = [AVCaptureVideoPreviewLayer layerWithSession: m_captureSession];
        previewLayer.frame = m_preview.bounds;
        previewLayer.videoGravity = AVLayerVideoGravityResizeAspectFill;
        //        if(previewLayer.orientationSupported){
        //            previewLayer.orientation = mOrientation;
        //        }
        [m_preview.layer addSublayer: previewLayer];
       
        if(![m_captureSession isRunning]){
            [m_captureSession startRunning];
        }
    }
}

- (void)stopPreview{
    if(m_captureSession){       
        if([m_captureSession isRunning]){
            [m_captureSession stopRunning];
           
            // remove all sublayers
            if(m_preview){
                for(CALayer *ly in m_preview.layer.sublayers){
                    if([ly isKindOfClass: [AVCaptureVideoPreviewLayer class]])
                        {
                        [ly removeFromSuperlayer];
                        break;
                        }
                }
            }
        }
    }
}
#endif
@end

@implementation GLRecord
static GLRecord* g_camera = 0;
- (id)init
{
    if(g_camera)
        return g_camera;
    else
        {
        if(self = [super init])
            {
            self->m_frontCamera = NO;
            self->m_started = NO;
            g_camera = self;
            outDelegate = nil;
            }
        return g_camera;
        }
}
-(void)dealloc
{
#if PRODUCER_HAS_VIDEO_CAPTURE
    [m_captureSession release];
    [m_captureDevice release];
    [m_captureMovieFileOutput release];
    [m_preview release];
#endif
    [super dealloc];
}
+ (GLRecord*)shareGLRecord
{
    if(!g_camera)
        g_camera = [[GLRecord alloc] init];
    return g_camera;
}
+ (void)closeCamera
{
    if(g_camera)
        {
        [g_camera dealloc];
        g_camera = nil;
        }
}
- (void)prepareVideoCaptureFrontCamera:(BOOL) v_bfront andPreview:(UIView*) v_view
{
    self->m_frontCamera = v_bfront;
    if(v_view)
        self->m_preview = [v_view retain];
#if PRODUCER_HAS_VIDEO_CAPTURE   
    if([m_captureSession isRunning])
        {
        [self stopVideoCapture];
        [self startVideoCapture];
        }
#endif
}
- (void)startVideoCapture
{
#if PRODUCER_HAS_VIDEO_CAPTURE   
    //防锁
    [[UIApplication sharedApplication] setIdleTimerDisabled:YES];
    //打开摄像设备,并开始捕抓图像
    //[labelState setText:@"Starting Video stream"];
    if(m_captureDevice || m_captureSession || m_captureMovieFileOutput)
        {
        NSLog(@"Already capturing");
        return;
        }
   
    if((m_captureDevice = [GLRecord cameraAtPosition:m_frontCamera? AVCaptureDevicePositionFront:AVCaptureDevicePositionBack]) == nil)
        {
        NSLog(@"Failed to get valide capture device");
        return;
        }
   
    NSError *error = nil;
    AVCaptureDeviceInput *videoInput = [AVCaptureDeviceInput deviceInputWithDevice:m_captureDevice error:&error];
    if (!videoInput)
        {
        NSLog(@"Failed to get video input");
        m_captureDevice = nil;
        return;
        }
   
    m_captureSession = [[AVCaptureSession alloc] init];
   
    m_captureSession.sessionPreset = AVCaptureSessionPreset640x480;
    if ([m_captureSession canAddInput:videoInput]) {
        [m_captureSession addInput:videoInput];       
    }
   

   
    m_captureMovieFileOutput = [[AVCaptureMovieFileOutput alloc] init];
    if ([m_captureSession canAddOutput:m_captureMovieFileOutput])
        [m_captureSession addOutput:m_captureMovieFileOutput];
   
    if (![self recordsVideo]) {
        NSString *localizedDescription = NSLocalizedString(@"Video recording unavailable", @"Video recording unavailable description");
        NSString *localizedFailureReason = NSLocalizedString(@"Movies recorded on this device will only contain audio. They will be accessible through iTunes file sharing.", @"Video recording unavailable failure reason");
        NSDictionary *errorDict = [NSDictionary dictionaryWithObjectsAndKeys:
                                   localizedDescription, NSLocalizedDescriptionKey,
                                   localizedFailureReason, NSLocalizedFailureReasonErrorKey,
                                   nil];
        NSError *noVideoError = [NSError errorWithDomain:@"AVCam" code:0 userInfo:errorDict];
        if (outDelegate && [outDelegate respondsToSelector:@selector(capture:didFailWithError:)]) {
            [outDelegate capture:self didFailWithError:noVideoError];
        }
    }
#if 0
//   
//    // Currently, the only supported key is kCVPixelBufferPixelFormatTypeKey. Recommended pixel format choices are
//    // kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange or kCVPixelFormatType_32BGRA.
//    // On iPhone 3G, the recommended pixel format choices are kCVPixelFormatType_422YpCbCr8 or kCVPixelFormatType_32BGRA.
//    //
//    AVCaptureVideoDataOutput *avCaptureVideoDataOutput = [[AVCaptureVideoDataOutput alloc] init];
//   
//    NSString* key = (NSString*)kCVPixelBufferPixelFormatTypeKey;
//    NSNumber* value = [NSNumber numberWithUnsignedInt:kCVPixelFormatType_32BGRA];
//    NSDictionary* settings = [NSDictionary dictionaryWithObject:value forKey:key];
//    //    NSDictionary *settings = [[NSDictionary alloc] initWithObjectsAndKeys:
//    //                              //[NSNumber numberWithUnsignedInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange], //kCVPixelBufferPixelFormatTypeKey,
//    //                              [NSNumber numberWithInt: mWidth], (id)kCVPixelBufferWidthKey,
//    //                              [NSNumber numberWithInt: mHeight], (id)kCVPixelBufferHeightKey,
//    //                              nil];
//   
//    avCaptureVideoDataOutput.videoSettings = settings;
//    //[settings release];
//    //    avCaptureVideoDataOutput.minFrameDuration = CMTimeMake(1, 1.0f/30);
//    avCaptureVideoDataOutput.alwaysDiscardsLateVideoFrames = YES;
//   
//   
//   
//    dispatch_queue_t queue = dispatch_queue_create("com.gh.cecall", NULL);
//    [avCaptureVideoDataOutput setSampleBufferDelegate:self queue:queue];
//    [m_captureSession addOutput:avCaptureVideoDataOutput];
//    [settings release];
//    [avCaptureVideoDataOutput release];
//    dispatch_release(queue);
#endif
    m_started = YES;
    //start preview
    [self startPreview];
   
#endif
}
- (void)stopVideoCapture
{
#if PRODUCER_HAS_VIDEO_CAPTURE   
    if(m_captureSession){
        [m_captureSession stopRunning];
        [m_captureSession release], m_captureSession = nil;
        NSLog(@"Video capture stopped");
    }
    [m_captureDevice release], m_captureDevice = nil;
    [m_captureMovieFileOutput release], m_captureMovieFileOutput = nil ;
    if(m_preview){
        for (UIView *view in m_preview.subviews) {
            [view removeFromSuperview];
        }
    }
#endif
}
-(BOOL)recordsVideo
{
    AVCaptureConnection *videoConnection = [GLRecord connectionWithMediaType:AVMediaTypeVideo fromConnections:m_captureMovieFileOutput.connections];
   
    return [videoConnection isActive];
}
-(void)startRecording
{
    AVCaptureConnection *videoConnection = [GLRecord connectionWithMediaType:AVMediaTypeVideo fromConnections:m_captureMovieFileOutput.connections] ;
    // if ([videoConnection isVideoOrientationSupported])
    // 此处保存的视频可以更换宽高AVCaptureVideoOrientationPortrait||AVCaptureVideoOrientationLandscapeRight
    [videoConnection setVideoOrientation:AVCaptureVideoOrientationPortrait];
   
    NSURL *outputFileUrl = [GLRecord tempFileURL] ;
    // 生成缓存文件
   
    [m_captureMovieFileOutput startRecordingToOutputFileURL:outputFileUrl recordingDelegate:self];
}

-(void)stopRecording
{
    [m_captureMovieFileOutput stopRecording];
}

- (void) resetRecording {
    [m_captureMovieFileOutput stopRecording];
    // 移除缓存文件
   
   
   
}

- (BOOL)setFrontCamera
{
    if(m_frontCamera)
        return YES;
    [self stopVideoCapture];
    m_frontCamera = YES;
    [self startVideoCapture];
    return YES;
}

- (BOOL)setBackCamera{
    if(!m_frontCamera)
        return YES;
    [self stopVideoCapture];
    m_frontCamera = NO;
    [self startVideoCapture];
    return YES;
}

- (void) setPreview: (UIView*)v_preview{
#if PRODUCER_HAS_VIDEO_CAPTURE   
    if(v_preview == nil){
        // stop preview
        [self stopPreview];
        // remove layers
        if(m_preview){
            for(CALayer *ly in m_preview.layer.sublayers){
                if([ly isKindOfClass: [AVCaptureVideoPreviewLayer class]]){
                    [ly removeFromSuperlayer];
                    break;
                }
            }
            [m_preview release], m_preview = nil;
        }
    }
    else {
        //start preview
        if (m_preview) {
            [m_preview release];
            m_preview = nil;
        }
        if((m_preview = [v_preview retain])){
            [self startPreview];
        }
    }
   
#endif
}
- (void)setVideoFileOutput:(id<GLRecordDelegate>)delegate
{
    outDelegate = delegate;
}
// 设置文件保存名称
- (void)setVideoFileName:(NSString *) v_nameStr {
    if (m_nameStr) {
        [m_nameStr release];
        m_nameStr = nil ;
    }
    m_nameStr = [v_nameStr retain];
}
#pragma mark -
#pragma mark AVCaptureFileOutputRecordingDelegate
#if PRODUCER_HAS_VIDEO_CAPTURE   
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didStartRecordingToOutputFileAtURL:(NSURL *)fileURL fromConnections:(NSArray *)connections {
    NSLog(@"begin");
    if (outDelegate && [outDelegate respondsToSelector:@selector(captureRecordingBegan:)]) {
        [outDelegate captureRecordingBegan:self];
    }
}
- (void)captureOutput:(AVCaptureFileOutput *)captureOutput didFinishRecordingToOutputFileAtURL:(NSURL *)outputFileURL fromConnections:(NSArray *)connections error:(NSError *)error {
    NSLog(@"finish");
    if (!m_nameStr) {
        return ;
    }
    // 进行文件复制
    NSArray *paths = NSSearchPathForDirectoriesInDomains(NSDocumentDirectory, NSUserDomainMask, YES);
    NSString *docDir = [paths objectAtIndex:0];
    NSString *strMovPath = [docDir stringByAppendingPathComponent:[NSString stringWithFormat:@"%@.mov",m_nameStr]];
   
    NSFileManager *fm = [[NSFileManager alloc] init];
    // 是否存在
    BOOL isExistsOk = [fm fileExistsAtPath:[[GLRecord tempFileURL] path]];
    NSLog(@"文件 %d 存在",isExistsOk);
    BOOL isCopyOk ;
    if (isExistsOk) {
        // 进行copy
        isCopyOk = [fm copyItemAtURL:[GLRecord tempFileURL] toURL:[NSURL fileURLWithPath:strMovPath] error:&error];
        NSLog(@"复制 %d",isCopyOk);
        // 不管成功还是失败。都删除这个缓存
        BOOL isDeleteOk = [fm removeItemAtURL:[GLRecord tempFileURL] error:nil];
        NSLog(@"删除缓存 %d",isDeleteOk);
    }
    if (!isCopyOk || !isExistsOk) {
        if (outDelegate && [outDelegate respondsToSelector:@selector(capture:didFailWithError:)]) {
            [outDelegate capture:self didFailWithError:error];
        }
    }else {
        if (outDelegate && [outDelegate respondsToSelector:@selector(captureRecordingFinished:)]) {
            [outDelegate captureRecordingFinished:self];
        }
    }
   
    [fm release];
}
#endif
@end
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值