3

I'm trying to take a video created using the iVidCap plugin and add audio to it. Basically the exact same thing as in this question: Writing video + generated audio to AVAssetWriterInput, audio stuttering. I've used the code from this post as a basis to try and modify the iVidCap.mm file myself, but the app always crashes in endRecordingSession.

I'm not sure how I need to modify endRecordingSession to accomodate for the audio (the original plugin just creates a video file). Here is the function:

- (int) endRecordingSession: (VideoDisposition) action {

NSLog(@"Start endRecordingSession");
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];

NSLog(@"Auto released pool");

NSString *filePath;
BOOL success = false;

[videoWriterInput markAsFinished];
NSLog(@"Mark video writer input as finished");
//[audioWriterInput markAsFinished];

// Wait for the video status to become known.
// Is this really doing anything?
int status = videoWriter.status;
while (status == AVAssetWriterStatusUnknown) {
    NSLog(@"Waiting for video to complete...");
    [NSThread sleepForTimeInterval:0.5f];
    status = videoWriter.status;
}

NSLog(@"Video completed");

@synchronized(self) {
    success = [videoWriter finishWriting];
    NSLog(@"Success: %@", success);
    if (!success) {
        // We failed to successfully finalize the video file.
        NSLog(@"finishWriting returned NO");

    } else {
        // The video file was successfully written to the Documents folder.
        filePath = [[self getDocumentsFileURL:videoFileName] path];
        if (action == Save_Video_To_Album) {

            // Move the video to an accessible location on the device.
            NSLog(@"Temporary video filePath=%@", filePath);
            if (UIVideoAtPathIsCompatibleWithSavedPhotosAlbum(filePath)) {
                NSLog(@"Video IS compatible. Adding it to photo album.");
                UISaveVideoAtPathToSavedPhotosAlbum(filePath, self, @selector(copyToPhotoAlbumCompleteFromVideo: didFinishSavingWithError: contextInfo:), nil);
            } else {
                NSLog(@"Video IS NOT compatible. Could not be added to the photo album.");
                success = NO;
            }
        } else if (action == Discard_Video) {
            NSLog(@"Video cancelled. Removing temporary video file: %@", filePath);
            [self removeFile:filePath];  
        }
    }

    [self cleanupWriter];
}

isRecording = false;

[pool drain];

return success; }

Right now it crashes on [videoWriter finishWriting]. I tried adding [audioWriterInput markAsFinished], but then it crashes on that. I would contact the original poster since it seems like they got it working, but there doesn't seem to be a way to send private messages.

Does anyone have any suggestions on how I can get this to work or why it's crashing? I've tried my best to figure this out but I'm pretty new to Obj-C. I can post the rest of the code if needed (a lot of it is in the original post referenced earlier).

Community
  • 1
  • 1

1 Answers1

2

The issue might actually be in the writeAudioBuffer function.

If you copied the code from that post but didnlt change it then you will certainly have some problems.

You need to do something like this:

if ( ![self waitForAudioWriterReadiness]) {
    NSLog(@"WARNING: writeAudioBuffer dropped frame after wait limit reached.");
    return 0;
}

OSStatus status;
CMBlockBufferRef bbuf = NULL;
CMSampleBufferRef sbuf = NULL;

size_t buflen = n * nchans * sizeof(float);

CMBlockBufferRef tmp_bbuf = NULL;
status = CMBlockBufferCreateWithMemoryBlock(
                                            kCFAllocatorDefault, 
                                            samples, 
                                            buflen, 
                                            kCFAllocatorDefault, 
                                            NULL, 
                                            0, 
                                            buflen, 
                                            0, 
                                            &tmp_bbuf);

if (status != noErr || !tmp_bbuf) {
    NSLog(@"CMBlockBufferCreateWithMemoryBlock error");
    return -1;
}
// Copy the buffer so that we get a copy of the samples in memory.
// CMBlockBufferCreateWithMemoryBlock does not actually copy the data!
// 
status = CMBlockBufferCreateContiguous(kCFAllocatorDefault, tmp_bbuf, kCFAllocatorDefault, NULL, 0, buflen, kCMBlockBufferAlwaysCopyDataFlag, &bbuf);
//CFRelease(tmp_bbuf); // causes abort?!
if (status != noErr) {
    NSLog(@"CMBlockBufferCreateContiguous error");
    //CFRelease(bbuf);
    return -1;
}


CMTime timestamp = CMTimeMake(sample_position_, 44100);

status = CMAudioSampleBufferCreateWithPacketDescriptions(
    kCFAllocatorDefault, bbuf, TRUE, 0, NULL, audio_fmt_desc_, 1, timestamp, NULL, &sbuf);

sample_position_ += n;
if (status != noErr) {
    NSLog(@"CMSampleBufferCreate error");
    return -1;
}
BOOL r = [audioWriterInput appendSampleBuffer:sbuf];
if (!r) {
    NSLog(@"appendSampleBuffer error");
}
//CFRelease(bbuf); // crashes, don't know why..  Is there a leak here?
//CFRelease(sbuf);

return 0;

There are a few things to do with memory management that I am unsure on here.

Additionally be sure to use:

audioWriterInput.expectsMediaDataInRealTime = YES;
Pete
  • 4,784
  • 26
  • 33