Dino Mic
Dino Mic

Reputation: 181

How to use AVAssetWriter instead of AVAssetExportSession to re-encode existing video

I'm trying to re-encode videos on an iPad which were recorded on that device but with the "wrong" orientation. This is because when the file is converted to an MP4 file and uploaded to a web server for use with the "video" HTML5 tag, only Safari seems to render the video with the correct orientation.

Basically, I've managed to implement what I wanted by using a AVMutableVideoCompositionLayerInstruction, and then using AVAssetExportSession to create the resultant video with audio. However, the problem is that the file sizes jump up considerably after doing this, eg correcting an original file of 4.1MB results in a final file size of 18.5MB! All I've done is rotate the video through 180 degrees!! Incidentally, the video instance that I'm trying to process was originally created by the UIImagePicker during "compression" using videoQuality = UIImagePickerControllerQualityType640x480, which actually results in videos of 568 x 320 on an iPad mini.

I experimented with the various presetName settings on AVAssetExportSession but I couldn't get the desired result. The closest I got filesize-wise was 4.1MB (ie exactly the same as source!) by using AVAssetExportPresetMediumQuality, BUT this also reduced the dimensions of the resultant video to 480 x 272 instead of the 568 x 320 that I had explicitly set.

So, this led me to look into other options, and hence using AVAssetWriter instead. The problem is, I can't get any code that I have found to work! I tried the code found on this SO post (Video Encoding using AVAssetWriter - CRASHES), but can't get it to work. For a start, I get a compilation error for this line:

NSDictionary *videoOptions = [NSDictionary dictionaryWithObject:[NSNumber numberWithInt:kCVPixelFormatType_420YpCbCr8BiPlanarVideoRange] forKey:(id)kCVPixelBufferPixelFormatTypeKey];

The resultant compilation error being:

Undefined symbols for architecture armv7: "_kCVPixelBufferPixelFormatTypeKey"

This aside, I tried passsing in nil for the AVAssetReaderTrackOutput's outputSettings, which should be OK according to header info:

A value of nil for outputSettings configures the output to vend samples in their original format as stored by the specified track.

However, I then get a crash happening at this line:

BOOL result = [videoWriterInput appendSampleBuffer:sampleBuffer];

In short, I've not been able to get any code to work with AVAssetWriter, so I REALLY need some help here. Are there any other ways to achieve my desired results? Incidentally, I'm using Xcode 4.6 and I'm targeting everything from iOS5 upwards, using ARC.

Upvotes: 4

Views: 1729

Answers (2)

Paul A.
Paul A.

Reputation: 597

I have solved similar problems related to your questions. This might help someone who has similar problems:

  1. Assuming writerInput is your object instance of AVAssetWriterInput and assetTrack is the instance of your AVAssetTrack, then your transform problem is solved by simply:

writerInput.transform = assetTrack.preferredTransform;

  1. You have to release sampleBuffer after appending your sample buffer, so you would have something like:

    if (sampleBuffer = [asset_reader_output copyNextSampleBuffer]) { BOOL result = [writerInput appendSampleBuffer:sampleBuffer]; CFRelease(sampleBuffer); // Release sampleBuffer! }

Upvotes: 1

Dino Mic
Dino Mic

Reputation: 181

The compilation error was caused by me not including the CoreVideo.framework. As soon as I had included that and imported it, I could get the code to compile. Also, the code would work and generate a resultant video, but I uncovered 2 new problems:

  1. I can't get the transform to work using the transform property on AVAssetWriterInput. This means that I'm stuck with using a AVMutableVideoCompositionInstruction and AVAssetExportSession for the transformation.
  2. If I use AVAssetWriter to just handle compression (seeing as I don't have many options with AVAssetExportSession), I still have a bad memory leak. I've tried everything I can think of, starting with the solution in this link ( Help Fix Memory Leak release ) and also with @autorelease blocks at key points. But it seems that the following line will cause a leak, no matter what I try:

    CMSampleBufferRef sampleBuffer = [asset_reader_output copyNextSampleBuffer];
    

I could really do with some help.

Upvotes: 0

Related Questions