I’m updating an application to be 64-bit-compatible, but I’m having a little difficulty with our movie recording code. We have a FireWire camera that feeds YUV frames into our application, which we process and encode out to disk within an MPEG4 movie. Currently, we are using the C-based QuickTime API to do this (using Image Compression Manager, etc.), but the old QuickTime API does not have support for 64 bit.
My first attempt was to use QTKit’s QTMovie and encode individual frames using -addImage:forDuration:withAttributes:, but that requires the creation of an NSImage for each frame (which is computationally expensive) and it does not do temporal compression, so it doesn’t generate the most compact files.
I’d like to use something like QTKit Capture’s QTCaptureMovieFileOutput, but I can’t figure out how to feed raw frames into that which aren’t associated with a QTCaptureInput. We can’t use our camera directly with QTKit Capture because of our need to manually control the gain, exposure, etc. for it.
On Lion, we now have the AVAssetWriter class in AVFoundation which lets you do this, but I still have to target Snow Leopard for the time being, so I’m trying to find a solution that works there as well.
Therefore, is there a way to do non-QuickTime frame-by-frame recording of video that is more efficient than QTMovie’s -addImage:forDuration:withAttributes: and produces file sizes comparable to what the older QuickTime API can?
In the end, I decided to go with the approach suggested by TiansHUo, and use libavcodec for the video compression here. Based on the instructions by Martin here, I downloaded the FFmpeg source and built a 64-bit compatible version of the necessary libraries using
This creates the LGPL shared libraries for the 64-bit Core2 processors in the Mac.
Unfortunately, I haven’t yet figured a way to make the library run without crashing when the MMX optimizations are enabled, so that is disabled right now. This slows down encoding somewhat.After some experimentation, I found that I could build a 64-bit version of the library which had MMX optimizations enabled and was stable on the Mac by using the above configuration options. This is much faster when encoding than the library built with MMX disabled.Note that if you use these shared libraries, you should make sure you follow the LGPL compliance instructions on FFmpeg’s site to the letter.
In order to get these shared libraries to function properly when placed in proper folder within my Mac application bundle, I needed to use
install_name_toolto adjust the internal search paths in these libraries to point to their new location in the Frameworks directory within the application bundle:Your specific paths may vary. This adjustment lets them work from within the application bundle without having to install them in /usr/local/lib on the user’s system.
I then had my Xcode project link against these libraries, and I created a separate class to handle the video encoding. This class takes in raw video frames (in BGRA format) through the
videoFrameToEncodeproperty and encodes them within themovieFileNamefile as MPEG4 video in an MP4 container. The code is as follows:SPVideoRecorder.h
SPVideoRecorder.m
This works under Lion and Snow Leopard in a 64-bit application. It records at the same bitrate as my previous QuickTime-based approach, with overall lower CPU usage.
Hopefully, this will help out someone else in a similar situation.