Non Stop Video Cam Using CMSampleBufferRef

Record single nonstop video from camera and continue anytime where you left off even when you pause and switch cams while recording. You do not have to go through the hassle of merging clips together in a single video. With Nonstop Video Cam, you can pause the unwanted and record the fun part. No tedious editing and merging of clips when all you really needed was a pause button. This app allows you to start recording, pause unwanted and then resume recording later on where you left off- all in one video!

This app is super easy and free to use and makes it easy to pause and continue recording into a single video clip. You do not have to record videos in chunks and splice them together later. Videos will be auto saved in drafts. No editing, no waiting, just fast and fun!

Getting Started

Before starting we expect that you are familiar with Objective-C which is used as primary language. This code can be converted into Swift code easily but its time taking.

This will involve following steps which we will go through one by one

  • XCode Project Creation

  • AVCaptureSession creation with all inputs and outputs and sets its delegate

  • some logics in delegate method

  • Play and pause option

  • Camera rotation

  • Mic on/off

  • Completion of video

  • Merging of new video in existing video

XCode Project Creation

Open up XCode and create a single view new project “Video Cam App”. User Storyboard to design application UI and select Objective-C for code syntax.

AVCaptureSession creation with all inputs and outputs and sets its delegate

While capturing video if user want to pause current video than AVCaptureSession not provide pause option , so in this case user have to stop video and than capture new video and then using AVAssetExportSession these videos can b merged but its enough time taking in merging videos,

But using AVCaptureVideoDataOutput & AVCaptureAudioDataOutput user can create video with play pause, camera rotation, mic on/off options, these are delegate methods than return video & audio buffers of every moment. Let me explain this technique.

First of all create session for capturing video using AVCaptureSession, add possible input like mic/ back cam and outputs of AVCaptureVideoDataOutput & AVCaptureAudioDataOutput like this

AVCaptureSession* _session   = [[AVCaptureSession alloc] init];
        AVCaptureDevice* backCamera = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeVideo];
        AVCaptureDeviceInput* input = [AVCaptureDeviceInput deviceInputWithDevice:backCamera error:nil];
        activeInput                 = input;
        [_session addInput:input];
		
		AVCaptureDevice* mic 				= [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
        AVCaptureDeviceInput* micinput = [AVCaptureDeviceInput deviceInputWithDevice:mic error:nil];
        [_session addInput:micinput];

and set setSampleBufferDelegate for both AVCaptureVideoDataOutput & AVCaptureAudioDataOutput, Like this

AVCaptureVideoDataOutput* videoout = [[AVCaptureVideoDataOutput alloc] init];
        [videoout setSampleBufferDelegate:self queue:_captureQueue];
		
		AVCaptureAudioDataOutput* audioout = [[AVCaptureAudioDataOutput alloc] init];
            [audioout setSampleBufferDelegate:self queue:_captureQueue];
Some logics in delegate method

When set this delegate than its delegate method didOutputSampleBuffer starts calling in every moment.

- (void) captureOutput:(AVCaptureOutput *)captureOutput didOutputSampleBuffer:(CMSampleBufferRef)sampleBuffer fromConnection:(AVCaptureConnection *)connection

initially a flag isCapture is false and condition added in this method, either if its false than simple return this didOutputSampleBuffer method,

 if (self.isPaused)
        {
            return;
        }

when user press start capturing then this flag will true and these buffer will starts utilised and when press start capturing create video file in local directory where this buffer can append in this file by encode using AVAssetWriter.

Play and pause option

Here on play and pause button set flag like isPaused if isPaused is true than simple return this didOutputSampleBuffer method by checking flag. If is false then these audio & video sampleBuffers need to encode using AVAssetWriter, this writer append these encoding buffers in initially created video file when user starts capturing, Like this

Camera rotation

For camera rotation, get current running session and here get all inputs of this session and get backCam input remove this input and after this again add frontCam input, like this

AVCaptureDeviceInput* currentCamInput = [AVCaptureDeviceInput alloc];
    
    for (int i = 0; i < [_session.inputs count]; i++) {
        
        AVCaptureDeviceInput* deviceInput = [_session.inputs objectAtIndex:i];
        if (deviceInput == activeInput)
        {
            currentCamInput = deviceInput;
        }
    }
    
    NSLog(@"%@", currentCamInput);
    
    [_session beginConfiguration];
    [_session removeInput:currentCamInput];
    
    AVCaptureDevice* newCamera = nil;
    
    if (currentCamInput != nil)
    {
        if (currentCamInput.device.position == AVCaptureDevicePositionFront)
        {
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionBack];
        }
       else
        {
            newCamera = [self cameraWithPosition:AVCaptureDevicePositionFront];
        }
    }
    
    AVCaptureDeviceInput *newVideoInput = nil;
    
    newVideoInput = [AVCaptureDeviceInput deviceInputWithDevice:newCamera error:nil];
    activeInput   = newVideoInput;
    [_session addInput:newVideoInput];
	[_session commitConfiguration];
Mic on/off

And for mic on/off , there are two methods, one is simple remove/add input in current running session, like this

if (_isMicActive)
    {
        AVCaptureDeviceInput* currentAudInput = [AVCaptureDeviceInput alloc];
        
        for (AVCaptureDeviceInput* deviceInput in _session.inputs) {
            if (deviceInput != activeInput)
            {
                currentAudInput = deviceInput;
            }
        }
        
        [_session beginConfiguration];
        [_session removeInput:currentAudInput];
        _isMicActive = false;
        isMicEnableInitially = false;
    }
    else
    {
        AVCaptureDevice* mic = [AVCaptureDevice defaultDeviceWithMediaType:AVMediaTypeAudio];
        AVCaptureDeviceInput* micinput = [AVCaptureDeviceInput deviceInputWithDevice:mic error:nil];
        [_session beginConfiguration];
        [_session addInput:micinput];
        _isMicActive = true;
        isMicEnableInitially = true;
    }
    
    [_session commitConfiguration];

and other is create globally flag for mic like isMicOff , this variable can be accessible in writer class , when during encoding sampleBuffers add in video file there is isMicOff is true then add empty audioBuffer.

if ([[CameraEngine engine] isMicActive])
            {
                if (_audioInput.readyForMoreMediaData)
                {
                    [_audioInput appendSampleBuffer:sampleBuffer];
                    return YES;
                }
            }
            else
            {
                if (_audioInput.readyForMoreMediaData)
                {
                    [self muteAudioInBuffer:sampleBuffer];
                    [_audioInput appendSampleBuffer:sampleBuffer];
                    return YES;
                }
            }
Completion of video

Finally, when user stops capturing video then , method of AVAssetWriter finishWritingWithCompletionHandler need to call , this will finish writing video file.

[_writer finishWritingWithCompletionHandler: handler];

Moreover, when app goes in background then you have to call stop Capturing method, then your video will save in directory.

if video file completed then no buffer can add on existing video file, so if you need to add more video than you can merge one more video file with existing file, you can get your video file from document directory where you saved earlier.

Merging of new video in existing video

AVAssetExportSession merge videos in one video file,

AVAssetExportSession provide multiple presetName to merge video e.g. AVAssetExportPresetLowQuality, AVAssetExportPresetMediumQuality, AVAssetExportPresetHighestQuality and more but these are little time taking, but AVAssetExportPresetPassthrough is best for fast merging.


Share this blog
Group Meeting

This field cannot be blank.

Talk to us and

Get your project moving!