Note that there are some explanatory texts on larger screens.

plurals
  1. POUsing AVAssetWriter to create QuickTime movie from raw H.264 / AAC files
    text
    copied!<p>Using Mac OSX Objective-C, I'm trying to create a command line tool that takes a single H.264 and a single AAC file as inputs - encoded from the same source material - and, using AVAssetWriter, create a single QuickTime-compatible mov (and/or m4v) file for further editing / distribution.</p> <p>What I've done so far: 1) Using AVFoundation Framework components, i.e., AVAssetWriter, AVAssetWriterInput, etc. and Core Media Framework components, i.e., CMSampleBufferCreate, CMBlockBufferReplaceDataBytes, etc. - I've prototyped the CL tool. 2) I've hooked up the input/output file URLs, created the AVAssetWriter and the AVAssetWriterInput, the CMBlockBuffer, etc. 3) When I execute my runLoop, AVAssetWriter creates the m4v file but, although it is well-formed, it is only a 136 byte file representing the movie header atoms with no video track data. 4) I have searched StackOverflow - as well as the Apple forums and the Internet generally - to find an answer to my specific set of issues.</p> <p>Using the error checking in my code as well as the Xcode debugger, I find that AVAssetWriter is set up properly - it starts to construct the movie file - but CMBlockBufferReplaceDataBytes DOES NOT write H.264 NAL data into the CMBlockBuffer (as I believe I should do). So what am I missing?</p> <p>Here is the relevant portion of my runLoop code:</p> <pre><code>// Create the videoFile.m4v AVAssetWriter. AVAssetWriter *videoFileWriter = [[AVAssetWriter alloc] initWithURL:destinationURL fileType:AVFileTypeQuickTimeMovie error:&amp;error]; NSParameterAssert(videoFileWriter); if (error) { NSLog(@"AVAssetWriter initWithURL failed with error= %@", [error localizedDescription]); } // Create the video file settings dictionary. NSDictionary *videoSettings = [NSDictionary dictionaryWithObjectsAndKeys: AVVideoCodecH264, AVVideoCodecKey, [NSNumber numberWithInt:1280], AVVideoWidthKey, [NSNumber numberWithInt:720], AVVideoHeightKey, nil]; // Perform video settings check. if ([videoFileWriter canApplyOutputSettings:videoSettings forMediaType:AVMediaTypeVideo]) { NSLog(@"videoFileWriter can apply videoSettings..."); } // Create the input to the videoFileWriter AVAssetWriter. AVAssetWriterInput *videoFileWriterInput = [[AVAssetWriterInput alloc] initWithMediaType:AVMediaTypeVideo outputSettings:videoSettings]; videoFileWriterInput.expectsMediaDataInRealTime = YES; NSParameterAssert(videoFileWriterInput); NSParameterAssert([videoFileWriter canAddInput:videoFileWriterInput]); // Connect the videoFileWriterInput to the videoFileWriter. if ([videoFileWriter canAddInput:videoFileWriterInput]) { [videoFileWriter addInput:videoFileWriterInput]; } // Get the contents of videoFile.264 (using current Mac OSX methods). NSData *sourceData = [NSData dataWithContentsOfURL:sourceURL]; const char *videoFileData = [sourceData bytes]; size_t sourceDataLength = [sourceData length]; NSLog(@"The value of 'sourceDataLength' is: %ld", sourceDataLength); // Set up to create the videoSampleBuffer. int32_t videoWidth = 1280; int32_t videoHeight = 720; CMBlockBufferRef videoBlockBuffer = NULL; CMFormatDescriptionRef videoFormat = NULL; CMSampleBufferRef videoSampleBuffer = NULL; CMItemCount numberOfSampleTimeEntries = 1; CMItemCount numberOfSamples = 1; // More set up to create the videoSampleBuffer. CMVideoFormatDescriptionCreate(kCFAllocatorDefault, kCMVideoCodecType_H264, videoWidth, videoHeight, NULL, &amp;videoFormat); result = CMBlockBufferCreateWithMemoryBlock(kCFAllocatorDefault, NULL, 150000, kCFAllocatorDefault, NULL, 0, 150000, kCMBlockBufferAssureMemoryNowFlag, &amp;videoBlockBuffer); NSLog(@"After 'CMBlockBufferCreateWithMemoryBlock', 'result' is: %d", result); // The CMBlockBufferReplaceDataBytes method is supposed to write videoFile.264 data bytes into the videoSampleBuffer. result = CMBlockBufferReplaceDataBytes(videoFileData, videoBlockBuffer, 0, 150000); NSLog(@"After 'CMBlockBufferReplaceDataBytes', 'result' is: %d", result); CMSampleTimingInfo videoSampleTimingInformation = {CMTimeMake(1, 30)}; result = CMSampleBufferCreate(kCFAllocatorDefault, videoBlockBuffer, TRUE, NULL, NULL, videoFormat, numberOfSamples, numberOfSampleTimeEntries, &amp;videoSampleTimingInformation, 0, NULL, &amp;videoSampleBuffer); NSLog(@"After 'CMSampleBufferCreate', 'result' is: %d", result); // Set the videoSampleBuffer to ready (is this needed?). result = CMSampleBufferMakeDataReady(videoSampleBuffer); NSLog(@"After 'CMSampleBufferMakeDataReady', 'result' is: %d", result); // Start writing... if ([videoFileWriter startWriting]) { [videoFileWriter startSessionAtSourceTime:kCMTimeZero]; } // Start the first while loop (DEBUG)... </code></pre> <p>All ideas, comments, and suggestions are welcome.</p> <p>Thank you!</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload