The first trick is to wrap the #includes within extern "C":
extern "C" {
#include <libavutil/avutil.h>
#include <libavcodec/avfft.h>
The second trick is that to use the nice C++ array types std::vector or boost::multi_array, it is necessary to use a custom allocator class that calls the libav av_malloc() and av_free(). The reason is that these ensure the 32-byte alignment that libav assumes (without checking every time) is present when it utilizes SIMD instructions. Without a custom allocator, std::vector and boost::multi_array just use new[], which does not allocate aligned, and libav in the process of ANDing addresses ends up running past the end of the buffer and generating a segmentation fault.
The code below uses a custom allocator adapted from The C++ Standard Library -- a Tutorial and Reference. The advantage of using std::vector or boost::multi_array, of course, is automated memory management using the Resource Acquisition Is Initialization pattern/idiom, similar to C++ auto_ptr (which can't be used for arrays because it is hard-coded to delete instead of delete[]). Although std::vector is used below, the same allocator works equally well with boost::multi_array.
#define __STDC_CONSTANT_MACROS
#include <cstring>
#include <vector>
extern "C" {
#include <libavutil/avutil.h>
#include <libavcodec/avfft.h>
}
template <typename T> class allocator_av {
public:
typedef T value_type;
typedef T* pointer;
typedef const T* const_pointer;
typedef T& reference;
typedef const T& const_reference;
typedef std::size_t size_type;
template <typename U>
struct rebind {
typedef allocator_av<U> other;
};
allocator_av() {}
template <typename U> allocator_av(const allocator_av<U>&) {}
size_type max_size () const { return 1 << 16; }
pointer allocate (size_type num, const void* = 0) {
return static_cast<pointer>(av_malloc(num*sizeof(T)));
}
void construct (pointer p, const T& value) {}
void destroy (pointer p) {}
void deallocate (pointer p, size_type num) { av_free(p); }
};
int main(int argc, char** argv) {
std::vector<FFTComplex, allocator_av<FFTComplex> > z(256);
FFTContext* c = av_fft_init(8, 0);
av_fft_permute(c, z.data());
av_fft_calc(c, z.data());
av_free(c);
}
1 comment:
Thanks for posting this. It was a great help, allocator_av in particular.
Post a Comment