+ _pending_audio->append (audio);
+
+ while (_pending_audio->frames() >= _audio_codec_context->frame_size) {
+ audio_frame (_audio_codec_context->frame_size);
+ }
+}
+
+void
+FFmpegEncoder::audio_frame (int size)
+{
+ AVFrame* frame = av_frame_alloc ();
+ DCPOMATIC_ASSERT (frame);
+
+ int const channels = _audio_codec_context->channels;
+
+ int const buffer_size = av_samples_get_buffer_size (0, channels, size, _audio_codec_context->sample_fmt, 0);
+ DCPOMATIC_ASSERT (buffer_size >= 0);
+
+ void* samples = av_malloc (buffer_size);
+ DCPOMATIC_ASSERT (samples);
+
+ frame->nb_samples = size;
+ int r = avcodec_fill_audio_frame (frame, channels, _audio_codec_context->sample_fmt, (const uint8_t *) samples, buffer_size, 0);
+ DCPOMATIC_ASSERT (r >= 0);
+
+ float** p = _pending_audio->data ();
+ switch (_audio_codec_context->sample_fmt) {
+ case AV_SAMPLE_FMT_S16:
+ {
+ int16_t* q = reinterpret_cast<int16_t*> (samples);
+ for (int i = 0; i < size; ++i) {
+ for (int j = 0; j < channels; ++i) {
+ *q++ = p[j][i] * 32767;
+ }
+ }
+ break;
+ }
+ case AV_SAMPLE_FMT_FLTP:
+ {
+ float* q = reinterpret_cast<float*> (samples);
+ for (int i = 0; i < channels; ++i) {
+ memcpy (q, p[i], sizeof(float) * size);
+ q += size;
+ }
+ break;
+ }
+ default:
+ DCPOMATIC_ASSERT (false);
+ }
+
+ AVPacket packet;
+ av_init_packet (&packet);
+ packet.data = 0;
+ packet.size = 0;
+
+ int got_packet;
+ if (avcodec_encode_audio2 (_audio_codec_context, &packet, frame, &got_packet) < 0) {
+ throw EncodeError ("FFmpeg audio encode failed");
+ }
+
+ if (got_packet && packet.size) {
+ packet.stream_index = _audio_stream_index;
+ av_interleaved_write_frame (_format_context, &packet);
+ av_packet_unref (&packet);
+ }
+
+ av_free (samples);
+ av_frame_free (&frame);