Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
index 56924cb0dfa7b2da1dc06303baddb26fe60867fa..ed0a351716c417c5fd72ff775733016af57cd030 100644 (file)
@@ -1,4 +1,5 @@
 /*
+ *
  * ffmpeg-write support
  *
  * Partial Copyright (c) 2006 Peter Schlaile
  *
  */
 
+/** \file blender/blenkernel/intern/writeffmpeg.c
+ *  \ingroup bke
+ */
 
 #ifdef WITH_FFMPEG
 #include <string.h>
 #include <stdio.h>
 
-#if defined(_WIN32) && defined(_DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
+#if defined(_WIN32) && defined(DEBUG) && !defined(__MINGW32__) && !defined(__CYGWIN__)
 /* This does not seem necessary or present on MSVC 8, but may be needed in earlier versions? */
 #if _MSC_VER < 1400
 #include <stdint.h>
 #include <libswscale/swscale.h>
 #include <libavcodec/opt.h>
 
-#if LIBAVFORMAT_VERSION_INT < (49 << 16)
-#define FFMPEG_OLD_FRAME_RATE 1
-#else
-#define FFMPEG_CODEC_IS_POINTER 1
-#define FFMPEG_CODEC_TIME_BASE  1
-#endif
-
-#if LIBAVFORMAT_VERSION_INT >= (52 << 16)
-#define OUTFILE_PB (outfile->pb)
-#else
-#define OUTFILE_PB (&outfile->pb)
-#endif
-
-#if defined(WIN32) && (!(defined snprintf))
-#define snprintf _snprintf
-#endif
-
 #include "MEM_guardedalloc.h"
 
 #include "DNA_scene_types.h"
 
 #include "BLI_blenlib.h"
 
-#include "AUD_C-API.h" /* must be before BKE_sound.h for define */
+#ifdef WITH_AUDASPACE
+#  include "AUD_C-API.h"
+#endif
 
 #include "BKE_global.h"
 #include "BKE_idprop.h"
 #include "IMB_imbuf_types.h"
 #include "IMB_imbuf.h"
 
-#ifdef HAVE_CONFIG_H
-#include <config.h>
-#endif
+#include "ffmpeg_compat.h"
 
-extern void do_init_ffmpeg();
+extern void do_init_ffmpeg(void);
 
 static int ffmpeg_type = 0;
 static int ffmpeg_codec = CODEC_ID_MPEG4;
-static int ffmpeg_audio_codec = CODEC_ID_MP2;
+static int ffmpeg_audio_codec = CODEC_ID_NONE;
 static int ffmpeg_video_bitrate = 1150;
 static int ffmpeg_audio_bitrate = 128;
 static int ffmpeg_gop_size = 12;
-static int ffmpeg_multiplex_audio = 1;
 static int ffmpeg_autosplit = 0;
 static int ffmpeg_autosplit_count = 0;
 
@@ -96,11 +82,14 @@ static uint8_t* video_buffer = 0;
 static int video_buffersize = 0;
 
 static uint8_t* audio_input_buffer = 0;
-static int audio_input_frame_size = 0;
+static int audio_input_samples = 0;
 static uint8_t* audio_output_buffer = 0;
 static int audio_outbuf_size = 0;
+static double audio_time = 0.0f;
 
+#ifdef WITH_AUDASPACE
 static AUD_Device* audio_mixdown_device = 0;
+#endif
 
 #define FFMPEG_AUTOSPLIT_SIZE 2000000000
 
@@ -114,50 +103,50 @@ static void delete_picture(AVFrame* f)
        }
 }
 
-#ifdef FFMPEG_CODEC_IS_POINTER
-static AVCodecContext* get_codec_from_stream(AVStream* stream)
-{
-       return stream->codec;
-}
-#else
-static AVCodecContext* get_codec_from_stream(AVStream* stream)
-{
-       return &stream->codec;
-}
-#endif
-
+#ifdef WITH_AUDASPACE
 static int write_audio_frame(void) 
 {
        AVCodecContext* c = NULL;
        AVPacket pkt;
 
-       c = get_codec_from_stream(audio_stream);
-
-       if(audio_mixdown_device)
-               AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_frame_size);
+       c = audio_stream->codec;
 
        av_init_packet(&pkt);
+       pkt.size = 0;
+
+       AUD_readDevice(audio_mixdown_device, audio_input_buffer, audio_input_samples);
+       audio_time += (double) audio_input_samples / (double) c->sample_rate;
 
        pkt.size = avcodec_encode_audio(c, audio_output_buffer,
-                                       audio_outbuf_size, 
+                                       audio_outbuf_size,
                                        (short*) audio_input_buffer);
+
+       if(pkt.size < 0)
+       {
+               // XXX error("Error writing audio packet");
+               return -1;
+       }
+
        pkt.data = audio_output_buffer;
-#ifdef FFMPEG_CODEC_TIME_BASE
-       pkt.pts = av_rescale_q(c->coded_frame->pts, 
-                              c->time_base, audio_stream->time_base);
-#else
-       pkt.pts = c->coded_frame->pts;
-#endif
-       fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts);
+
+       if(c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
+       {
+               pkt.pts = av_rescale_q(c->coded_frame->pts,
+                                      c->time_base, audio_stream->time_base);
+               fprintf(stderr, "Audio Frame PTS: %d\n", (int)pkt.pts);
+       }
 
        pkt.stream_index = audio_stream->index;
-       pkt.flags |= PKT_FLAG_KEY;
+
+       pkt.flags |= AV_PKT_FLAG_KEY;
+
        if (av_interleaved_write_frame(outfile, &pkt) != 0) {
-               //XXX error("Error writing audio packet");
+               fprintf(stderr, "Error writing audio packet!\n");
                return -1;
        }
        return 0;
 }
+#endif // #ifdef WITH_AUDASPACE
 
 /* Allocate a temporary frame */
 static AVFrame* alloc_picture(int pix_fmt, int width, int height) 
@@ -195,7 +184,7 @@ static const char** get_file_extensions(int format)
        }
        case FFMPEG_MPEG2: {
                static const char * rv[] = { ".dvd", ".vob", ".mpg", ".mpeg",
-                                            NULL };
+                                                NULL };
                return rv;
        }
        case FFMPEG_MPEG4: {
@@ -233,6 +222,14 @@ static const char** get_file_extensions(int format)
                static const char * rv[] = { ".ogg", ".ogv", NULL };
                return rv;
        }
+       case FFMPEG_MP3: {
+               static const char * rv[] = { ".mp3", NULL };
+               return rv;
+       }
+       case FFMPEG_WAV: {
+               static const char * rv[] = { ".wav", NULL };
+               return rv;
+       }
        default:
                return NULL;
        }
@@ -243,39 +240,37 @@ static int write_video_frame(RenderData *rd, AVFrame* frame, ReportList *reports
 {
        int outsize = 0;
        int ret, success= 1;
-       AVCodecContext* c = get_codec_from_stream(video_stream);
-#ifdef FFMPEG_CODEC_TIME_BASE
+       AVCodecContext* c = video_stream->codec;
+
        frame->pts = rd->cfra - rd->sfra;
-#endif
+
        if (rd->mode & R_FIELDS) {
                frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
        }
 
        outsize = avcodec_encode_video(c, video_buffer, video_buffersize, 
-                                      frame);
+                                          frame);
        if (outsize != 0) {
                AVPacket packet;
                av_init_packet(&packet);
 
                if (c->coded_frame->pts != AV_NOPTS_VALUE) {
-#ifdef FFMPEG_CODEC_TIME_BASE
                        packet.pts = av_rescale_q(c->coded_frame->pts,
                                                  c->time_base,
                                                  video_stream->time_base);
-#else
-                       packet.pts = c->coded_frame->pts;
-#endif
                        fprintf(stderr, "Video Frame PTS: %d\n", (int)packet.pts);
                } else {
                        fprintf(stderr, "Video Frame PTS: not set\n");
                }
                if (c->coded_frame->key_frame)
-                       packet.flags |= PKT_FLAG_KEY;
+                       packet.flags |= AV_PKT_FLAG_KEY;
                packet.stream_index = video_stream->index;
                packet.data = video_buffer;
                packet.size = outsize;
                ret = av_interleaved_write_frame(outfile, &packet);
-       } else ret = 0;
+       } else {
+               ret = 0;
+       }
 
        if (ret != 0) {
                success= 0;
@@ -290,7 +285,7 @@ static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)
 {
        uint8_t* rendered_frame;
 
-       AVCodecContext* c = get_codec_from_stream(video_stream);
+       AVCodecContext* c = video_stream->codec;
        int width = c->width;
        int height = c->height;
        AVFrame* rgb_frame;
@@ -347,7 +342,7 @@ static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)
        }
 
        if (c->pix_fmt != PIX_FMT_BGR32) {
-               sws_scale(img_convert_ctx, rgb_frame->data,
+               sws_scale(img_convert_ctx, (const uint8_t * const*) rgb_frame->data,
                          rgb_frame->linesize, 0, c->height, 
                          current_frame->data, current_frame->linesize);
                delete_picture(rgb_frame);
@@ -363,7 +358,7 @@ static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop)
 
        fprintf(stderr, "FFMPEG expert option: %s: ", prop->name);
 
-       strncpy(name, prop->name, 128);
+       BLI_strncpy(name, prop->name, sizeof(name));
 
        param = strchr(name, ':');
 
@@ -374,7 +369,7 @@ static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop)
        switch(prop->type) {
        case IDP_STRING:
                fprintf(stderr, "%s.\n", IDP_String(prop));
-               rv = av_set_string(c, prop->name, IDP_String(prop));
+               av_set_string3(c, prop->name, IDP_String(prop), 1, &rv);
                break;
        case IDP_FLOAT:
                fprintf(stderr, "%g.\n", IDP_Float(prop));
@@ -385,7 +380,7 @@ static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop)
                
                if (param) {
                        if (IDP_Int(prop)) {
-                               rv = av_set_string(c, name, param);
+                               av_set_string3(c, name, param, 1, &rv);
                        } else {
                                return;
                        }
@@ -411,8 +406,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
                return;
        }
        
-       prop = IDP_GetPropertyFromGroup(
-               rd->ffcodecdata.properties, (char*) prop_name);
+       prop = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, prop_name);
        if (!prop) {
                return;
        }
@@ -427,7 +421,7 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
 /* prepare a video stream for the output file */
 
 static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContext* of,
-                                   int rectx, int recty) 
+                                       int rectx, int recty) 
 {
        AVStream* st;
        AVCodecContext* c;
@@ -437,9 +431,9 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
 
        /* Set up the codec context */
        
-       c = get_codec_from_stream(st);
+       c = st->codec;
        c->codec_id = codec_id;
-       c->codec_type = CODEC_TYPE_VIDEO;
+       c->codec_type = AVMEDIA_TYPE_VIDEO;
 
 
        /* Get some values from the current render settings */
@@ -447,7 +441,6 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
        c->width = rectx;
        c->height = recty;
 
-#ifdef FFMPEG_CODEC_TIME_BASE
        /* FIXME: Really bad hack (tm) for NTSC support */
        if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
                c->time_base.den = 2997;
@@ -460,20 +453,6 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                c->time_base.den = rd->frs_sec * 100000;
                c->time_base.num = ((double) rd->frs_sec_base) * 100000;
        }
-#else
-       /* FIXME: Really bad hack (tm) for NTSC support */
-       if (ffmpeg_type == FFMPEG_DV && rd->frs_sec != 25) {
-               c->frame_rate = 2997;
-               c->frame_rate_base = 100;
-       } else if ((double) ((int) rd->frs_sec_base) == 
-                  rd->frs_sec_base) {
-               c->frame_rate = rd->frs_sec;
-               c->frame_rate_base = rd->frs_sec_base;
-       } else {
-               c->frame_rate = rd->frs_sec * 100000;
-               c->frame_rate_base = ((double) rd->frs_sec_base)*100000;
-       }
-#endif
        
        c->gop_size = ffmpeg_gop_size;
        c->bit_rate = ffmpeg_video_bitrate*1000;
@@ -497,11 +476,24 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                c->pix_fmt = PIX_FMT_YUV422P;
        }
 
-       if (codec_id == CODEC_ID_XVID) {
+       if (ffmpeg_type == FFMPEG_XVID) {
                /* arghhhh ... */
                c->pix_fmt = PIX_FMT_YUV420P;
+               c->codec_tag = (('D'<<24) + ('I'<<16) + ('V'<<8) + 'X');
+       }
+
+       if (codec_id == CODEC_ID_H264) {
+               /* correct wrong default ffmpeg param which crash x264 */
+               c->qmin=10;
+               c->qmax=51;
        }
        
+       // Keep lossless encodes in the RGB domain.
+       if (codec_id == CODEC_ID_HUFFYUV || codec_id == CODEC_ID_FFV1) {
+               /* HUFFYUV was PIX_FMT_YUV422P before */
+               c->pix_fmt = PIX_FMT_RGB32;
+       }
+
        if ((of->oformat->flags & AVFMT_GLOBALHEADER)
 //             || !strcmp(of->oformat->name, "mp4")
 //         || !strcmp(of->oformat->name, "mov")
@@ -531,9 +523,9 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                return NULL;
        }
 
-       video_buffersize = 2000000;
-       video_buffer = (uint8_t*)MEM_mallocN(video_buffersize
-                                            "FFMPEG video buffer");
+       video_buffersize = avpicture_get_size(c->pix_fmt, c->width, c->height);
+       video_buffer = (uint8_t*)MEM_mallocN(video_buffersize*sizeof(uint8_t),
+                                                "FFMPEG video buffer");
        
        current_frame = alloc_picture(c->pix_fmt, c->width, c->height);
 
@@ -557,13 +549,14 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
        st = av_new_stream(of, 1);
        if (!st) return NULL;
 
-       c = get_codec_from_stream(st);
+       c = st->codec;
        c->codec_id = codec_id;
-       c->codec_type = CODEC_TYPE_AUDIO;
+       c->codec_type = AVMEDIA_TYPE_AUDIO;
 
        c->sample_rate = rd->ffcodecdata.audio_mixrate;
        c->bit_rate = ffmpeg_audio_bitrate*1000;
-       c->channels = 2;
+       c->sample_fmt = SAMPLE_FMT_S16;
+       c->channels = rd->ffcodecdata.audio_channels;
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec) {
                //XXX error("Couldn't find a valid audio codec");
@@ -577,39 +570,29 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
                return NULL;
        }
 
-       /* FIXME: Should be user configurable */
-       if (ffmpeg_type == FFMPEG_DV) {
-               /* this is a hack around the poor ffmpeg dv multiplexer. */
-               /* only fixes PAL for now 
-                  (NTSC is a lot more complicated here...)! */
-               audio_outbuf_size = 7680;
-       } else {
-               audio_outbuf_size = 10000;
-       }
-       audio_output_buffer = (uint8_t*)MEM_mallocN(
-               audio_outbuf_size, "FFMPEG audio encoder input buffer");
+       /* need to prevent floating point exception when using vorbis audio codec,
+          initialize this value in the same way as it's done in FFmpeg iteslf (sergey) */
+       st->codec->time_base.num= 1;
+       st->codec->time_base.den= st->codec->sample_rate;
 
-       /* ugly hack for PCM codecs */
+       audio_outbuf_size = FF_MIN_BUFFER_SIZE;
 
-       if (c->frame_size <= 1) {
-               audio_input_frame_size = audio_outbuf_size / c->channels;
-               switch(c->codec_id) {
-               case CODEC_ID_PCM_S16LE:
-               case CODEC_ID_PCM_S16BE:
-               case CODEC_ID_PCM_U16LE:
-               case CODEC_ID_PCM_U16BE:
-                       audio_input_frame_size >>= 1;
-                       break;
-               default:
-                       break;
-               }
-       } else {
-               audio_input_frame_size = c->frame_size;
+       if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
+               audio_input_samples = audio_outbuf_size * 8 / c->bits_per_coded_sample / c->channels;
+       else
+       {
+               audio_input_samples = c->frame_size;
+               if(c->frame_size * c->channels * sizeof(int16_t) * 4 > audio_outbuf_size)
+                       audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
        }
 
-       audio_input_buffer = (uint8_t*)MEM_mallocN(
-               audio_input_frame_size * sizeof(short) * c->channels, 
-               "FFMPEG audio encoder output buffer");
+       audio_output_buffer = (uint8_t*)av_malloc(
+               audio_outbuf_size);
+
+       audio_input_buffer = (uint8_t*)av_malloc(
+               audio_input_samples * c->channels * sizeof(int16_t));
+
+       audio_time = 0.0f;
 
        return st;
 }
@@ -629,8 +612,6 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        ffmpeg_video_bitrate = rd->ffcodecdata.video_bitrate;
        ffmpeg_audio_bitrate = rd->ffcodecdata.audio_bitrate;
        ffmpeg_gop_size = rd->ffcodecdata.gop_size;
-       ffmpeg_multiplex_audio = rd->ffcodecdata.flags
-               & FFMPEG_MULTIPLEX_AUDIO;
        ffmpeg_autosplit = rd->ffcodecdata.flags
                & FFMPEG_AUTOSPLIT_OUTPUT;
        
@@ -641,25 +622,24 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        fprintf(stderr, "Starting output to %s(ffmpeg)...\n"
                "  Using type=%d, codec=%d, audio_codec=%d,\n"
                "  video_bitrate=%d, audio_bitrate=%d,\n"
-               "  gop_size=%d, multiplex=%d, autosplit=%d\n"
+               "  gop_size=%d, autosplit=%d\n"
                "  render width=%d, render height=%d\n", 
                name, ffmpeg_type, ffmpeg_codec, ffmpeg_audio_codec,
                ffmpeg_video_bitrate, ffmpeg_audio_bitrate,
-               ffmpeg_gop_size, ffmpeg_multiplex_audio,
-               ffmpeg_autosplit, rectx, recty);
+               ffmpeg_gop_size, ffmpeg_autosplit, rectx, recty);
        
        exts = get_file_extensions(ffmpeg_type);
        if (!exts) {
                BKE_report(reports, RPT_ERROR, "No valid formats found.");
                return 0;
        }
-       fmt = guess_format(NULL, exts[0], NULL);
+       fmt = av_guess_format(NULL, exts[0], NULL);
        if (!fmt) {
                BKE_report(reports, RPT_ERROR, "No valid formats found.");
                return 0;
        }
 
-       of = av_alloc_format_context();
+       of = avformat_alloc_context();
        if (!of) {
                BKE_report(reports, RPT_ERROR, "Error opening output file");
                return 0;
@@ -667,7 +647,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        
        of->oformat = fmt;
        of->packet_size= rd->ffcodecdata.mux_packet_size;
-       if (ffmpeg_multiplex_audio) {
+       if (ffmpeg_audio_codec != CODEC_ID_NONE) {
                of->mux_rate = rd->ffcodecdata.mux_rate;
        } else {
                of->mux_rate = 0;
@@ -676,15 +656,19 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        of->preload = (int)(0.5*AV_TIME_BASE);
        of->max_delay = (int)(0.7*AV_TIME_BASE);
 
-       snprintf(of->filename, sizeof(of->filename), "%s", name);
+       fmt->audio_codec = ffmpeg_audio_codec;
+
+       BLI_snprintf(of->filename, sizeof(of->filename), "%s", name);
        /* set the codec to the user's selection */
        switch(ffmpeg_type) {
        case FFMPEG_AVI:
        case FFMPEG_MOV:
-       case FFMPEG_OGG:
        case FFMPEG_MKV:
                fmt->video_codec = ffmpeg_codec;
                break;
+       case FFMPEG_OGG:
+               fmt->video_codec = CODEC_ID_THEORA;
+               break;
        case FFMPEG_DV:
                fmt->video_codec = CODEC_ID_DVVIDEO;
                break;
@@ -698,11 +682,16 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
                fmt->video_codec = CODEC_ID_H264;
                break;
        case FFMPEG_XVID:
-               fmt->video_codec = CODEC_ID_XVID;
+               fmt->video_codec = CODEC_ID_MPEG4;
                break;
        case FFMPEG_FLV:
                fmt->video_codec = CODEC_ID_FLV1;
                break;
+       case FFMPEG_MP3:
+               fmt->audio_codec = CODEC_ID_MP3;
+       case FFMPEG_WAV:
+               fmt->video_codec = CODEC_ID_NONE;
+               break;
        case FFMPEG_MPEG4:
        default:
                fmt->video_codec = CODEC_ID_MPEG4;
@@ -723,55 +712,118 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
                }
        }
        
-       fmt->audio_codec = ffmpeg_audio_codec;
-
        if (ffmpeg_type == FFMPEG_DV) {
                fmt->audio_codec = CODEC_ID_PCM_S16LE;
-               if (ffmpeg_multiplex_audio && rd->ffcodecdata.audio_mixrate != 48000) {
+               if (ffmpeg_audio_codec != CODEC_ID_NONE && rd->ffcodecdata.audio_mixrate != 48000 && rd->ffcodecdata.audio_channels != 2) {
                        BKE_report(reports, RPT_ERROR, "FFMPEG only supports 48khz / stereo audio for DV!");
                        return 0;
                }
        }
        
-       video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty);
-       printf("alloc video stream %p\n", video_stream);
-       if (!video_stream) {
-               BKE_report(reports, RPT_ERROR, "Error initializing video stream.");
-               return 0;
+       if (fmt->video_codec != CODEC_ID_NONE) {
+               video_stream = alloc_video_stream(rd, fmt->video_codec, of, rectx, recty);
+               printf("alloc video stream %p\n", video_stream);
+               if (!video_stream) {
+                       BKE_report(reports, RPT_ERROR, "Error initializing video stream.");
+                       return 0;
+               }
        }
-       
-       if (ffmpeg_multiplex_audio) {
+
+       if (ffmpeg_audio_codec != CODEC_ID_NONE) {
                audio_stream = alloc_audio_stream(rd, fmt->audio_codec, of);
                if (!audio_stream) {
                        BKE_report(reports, RPT_ERROR, "Error initializing audio stream.");
                        return 0;
                }
-               //XXX audiostream_play(SFRA, 0, 1);
        }
        if (av_set_parameters(of, NULL) < 0) {
                BKE_report(reports, RPT_ERROR, "Error setting output parameters.");
                return 0;
        }
        if (!(fmt->flags & AVFMT_NOFILE)) {
-               if (url_fopen(&of->pb, name, URL_WRONLY) < 0) {
+               if (avio_open(&of->pb, name, AVIO_FLAG_WRITE) < 0) {
                        BKE_report(reports, RPT_ERROR, "Could not open file for writing.");
                        return 0;
                }
        }
 
-       av_write_header(of);
+       if (av_write_header(of) < 0) {
+               BKE_report(reports, RPT_ERROR, "Could not initialize streams. Probably unsupported codec combination.");
+               return 0;
+       }
+
        outfile = of;
-       dump_format(of, 0, name, 1);
+       av_dump_format(of, 0, name, 1);
 
        return 1;
 }
 
+/**
+ * Writes any delayed frames in the encoder. This function is called before 
+ * closing the encoder.
+ *
+ * <p>
+ * Since an encoder may use both past and future frames to predict 
+ * inter-frames (H.264 B-frames, for example), it can output the frames 
+ * in a different order from the one it was given.
+ * For example, when sending frames 1, 2, 3, 4 to the encoder, it may write
+ * them in the order 1, 4, 2, 3 - first the two frames used for predition, 
+ * and then the bidirectionally-predicted frames. What this means in practice 
+ * is that the encoder may not immediately produce one output frame for each 
+ * input frame. These delayed frames must be flushed before we close the 
+ * stream. We do this by calling avcodec_encode_video with NULL for the last 
+ * parameter.
+ * </p>
+ */
+void flush_ffmpeg(void)
+{
+       int outsize = 0;
+       int ret = 0;
+       
+       AVCodecContext* c = video_stream->codec;
+       /* get the delayed frames */
+       while (1) {
+               AVPacket packet;
+               av_init_packet(&packet);
+               
+               outsize = avcodec_encode_video(c, video_buffer, video_buffersize, NULL);
+               if (outsize < 0) {
+                       fprintf(stderr, "Error encoding delayed frame %d\n", outsize);
+                       break;
+               }
+               if (outsize == 0) {
+                       break;
+               }
+               if (c->coded_frame->pts != AV_NOPTS_VALUE) {
+                       packet.pts = av_rescale_q(c->coded_frame->pts,
+                                                 c->time_base,
+                                                 video_stream->time_base);
+                       fprintf(stderr, "Video Frame PTS: %d\n", (int)packet.pts);
+               } else {
+                       fprintf(stderr, "Video Frame PTS: not set\n");
+               }
+               if (c->coded_frame->key_frame) {
+                       packet.flags |= AV_PKT_FLAG_KEY;
+               }
+               packet.stream_index = video_stream->index;
+               packet.data = video_buffer;
+               packet.size = outsize;
+               ret = av_interleaved_write_frame(outfile, &packet);
+               if (ret != 0) {
+                       fprintf(stderr, "Error writing delayed frame %d\n", ret);
+                       break;
+               }
+       }
+       avcodec_flush_buffers(video_stream->codec);
+}
+
 /* **********************************************************************
    * public interface
    ********************************************************************** */
 
 /* Get the output filename-- similar to the other output formats */
-void filepath_ffmpeg(char* string, RenderData* rd) {
+void filepath_ffmpeg(char* string, RenderData* rd)
+{
        char autosplit[20];
 
        const char ** exts = get_file_extensions(rd->ffcodecdata.type);
@@ -780,8 +832,7 @@ void filepath_ffmpeg(char* string, RenderData* rd) {
        if (!string || !exts) return;
 
        strcpy(string, rd->pic);
-       BLI_convertstringcode(string, G.sce);
-       BLI_convertstringframe(string, rd->cfra);
+       BLI_path_abs(string, G.main->name);
 
        BLI_make_existing_file(string);
 
@@ -802,11 +853,7 @@ void filepath_ffmpeg(char* string, RenderData* rd) {
        if (!*fe) {
                strcat(string, autosplit);
 
-               /* if we dont have any #'s to insert numbers into, use 4 numbers by default */
-               if (strchr(string, '#')==NULL)
-                       strcat(string, "####"); /* 4 numbers */
-
-               BLI_convertstringframe_range(string, rd->sfra, rd->efra);
+               BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
                strcat(string, *exts);
        } else {
                *(string + strlen(string) - strlen(*fe)) = 0;
@@ -822,83 +869,94 @@ int start_ffmpeg(struct Scene *scene, RenderData *rd, int rectx, int recty, Repo
        ffmpeg_autosplit_count = 0;
 
        success = start_ffmpeg_impl(rd, rectx, recty, reports);
-
-       if(ffmpeg_multiplex_audio && audio_stream)
+#ifdef WITH_AUDASPACE
+       if(audio_stream)
        {
-               AVCodecContext* c = get_codec_from_stream(audio_stream);
+               AVCodecContext* c = audio_stream->codec;
                AUD_DeviceSpecs specs;
                specs.channels = c->channels;
                specs.format = AUD_FORMAT_S16;
                specs.rate = rd->ffcodecdata.audio_mixrate;
-               audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->efra, rd->ffcodecdata.audio_volume);
+               audio_mixdown_device = sound_mixdown(scene, specs, rd->sfra, rd->ffcodecdata.audio_volume);
+#ifdef FFMPEG_CODEC_TIME_BASE
+               c->time_base.den = specs.rate;
+               c->time_base.num = 1;
+#endif
        }
-
+#endif
        return success;
 }
 
 void end_ffmpeg(void);
 
-static void write_audio_frames()
+#ifdef WITH_AUDASPACE
+static void write_audio_frames(double to_pts)
 {
        int finished = 0;
 
-       while (ffmpeg_multiplex_audio && !finished) {
-               double a_pts = ((double)audio_stream->pts.val 
-                               * audio_stream->time_base.num 
-                               / audio_stream->time_base.den);
-               double v_pts = ((double)video_stream->pts.val 
-                               * video_stream->time_base.num 
-                               / video_stream->time_base.den);
-               
-               if (a_pts < v_pts) {
-                       write_audio_frame();
-               } else {
+       while (audio_stream && !finished) {
+               if((audio_time >= to_pts) ||
+                  (write_audio_frame())) {
                        finished = 1;
                }
        }
 }
+#endif
 
 int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports) 
 {
        AVFrame* avframe;
-       int success;
+       int success = 1;
 
        fprintf(stderr, "Writing frame %i, "
                "render width=%d, render height=%d\n", frame,
                rectx, recty);
 
-       write_audio_frames();
+// why is this done before writing the video frame and again at end_ffmpeg?
+//     write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
 
-       avframe= generate_video_frame((unsigned char*) pixels, reports);
-       success= (avframe && write_video_frame(rd, avframe, reports));
-
-       if (ffmpeg_autosplit) {
-               if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) {
-                       end_ffmpeg();
-                       ffmpeg_autosplit_count++;
-                       success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+       if(video_stream)
+       {
+               avframe= generate_video_frame((unsigned char*) pixels, reports);
+               success= (avframe && write_video_frame(rd, avframe, reports));
+
+               if (ffmpeg_autosplit) {
+                       if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
+                               end_ffmpeg();
+                               ffmpeg_autosplit_count++;
+                               success &= start_ffmpeg_impl(rd, rectx, recty, reports);
+                       }
                }
        }
 
+#ifdef WITH_AUDASPACE
+       write_audio_frames((frame - rd->sfra) / (((double)rd->frs_sec) / rd->frs_sec_base));
+#endif
        return success;
 }
 
-
 void end_ffmpeg(void)
 {
-       int i;
+       unsigned int i;
        
        fprintf(stderr, "Closing ffmpeg...\n");
 
-       if (audio_stream && video_stream) {
+/*     if (audio_stream) { SEE UPPER
                write_audio_frames();
-       }
+       }*/
 
+#ifdef WITH_AUDASPACE
        if(audio_mixdown_device)
        {
                AUD_closeReadDevice(audio_mixdown_device);
                audio_mixdown_device = 0;
        }
+#endif
+
+       if (video_stream && video_stream->codec) {
+               fprintf(stderr, "Flushing delayed frames...\n");
+               flush_ffmpeg ();                
+       }
        
        if (outfile) {
                av_write_trailer(outfile);
@@ -906,10 +964,10 @@ void end_ffmpeg(void)
        
        /* Close the video codec */
 
-       if (video_stream && get_codec_from_stream(video_stream)) {
-               avcodec_close(get_codec_from_stream(video_stream));
-               video_stream = 0;
+       if (video_stream && video_stream->codec) {
+               avcodec_close(video_stream->codec);
                printf("zero video stream %p\n", video_stream);
+               video_stream = 0;
        }
 
        
@@ -928,7 +986,7 @@ void end_ffmpeg(void)
        }
        if (outfile && outfile->oformat) {
                if (!(outfile->oformat->flags & AVFMT_NOFILE)) {
-                       url_fclose(OUTFILE_PB);
+                       avio_close(outfile->pb);
                }
        }
        if (outfile) {
@@ -940,11 +998,11 @@ void end_ffmpeg(void)
                video_buffer = 0;
        }
        if (audio_output_buffer) {
-               MEM_freeN(audio_output_buffer);
+               av_free(audio_output_buffer);
                audio_output_buffer = 0;
        }
        if (audio_input_buffer) {
-               MEM_freeN(audio_input_buffer);
+               av_free(audio_input_buffer);
                audio_input_buffer = 0;
        }
 
@@ -965,8 +1023,7 @@ void ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
                return;
        }
 
-       group = IDP_GetPropertyFromGroup(
-               rd->ffcodecdata.properties, (char*) type);
+       group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
        if (group && prop) {
                IDP_RemFromGroup(group, prop);
                IDP_FreeProperty(prop);
@@ -984,6 +1041,8 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
        IDPropertyTemplate val;
        int idp_type;
        char name[256];
+       
+       val.i = 0;
 
        avcodec_get_context_defaults(&c);
 
@@ -991,19 +1050,14 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
        parent = c.av_class->option + parent_index;
 
        if (!rd->ffcodecdata.properties) {
-               IDPropertyTemplate val;
-
                rd->ffcodecdata.properties 
                        = IDP_New(IDP_GROUP, val, "ffmpeg"); 
        }
 
-       group = IDP_GetPropertyFromGroup(
-               rd->ffcodecdata.properties, (char*) type);
+       group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
        
        if (!group) {
-               IDPropertyTemplate val;
-               
-               group = IDP_New(IDP_GROUP, val, (char*) type); 
+               group = IDP_New(IDP_GROUP, val, type);
                IDP_AddToGroup(rd->ffcodecdata.properties, group);
        }
 
@@ -1024,12 +1078,12 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
        switch (o->type) {
        case FF_OPT_TYPE_INT:
        case FF_OPT_TYPE_INT64:
-               val.i = o->default_val;
+               val.i = FFMPEG_DEF_OPT_VAL_INT(o);
                idp_type = IDP_INT;
                break;
        case FF_OPT_TYPE_DOUBLE:
        case FF_OPT_TYPE_FLOAT:
-               val.f = o->default_val;
+               val.f = FFMPEG_DEF_OPT_VAL_DOUBLE(o);
                idp_type = IDP_FLOAT;
                break;
        case FF_OPT_TYPE_STRING:
@@ -1051,7 +1105,7 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
 /* not all versions of ffmpeg include that, so here we go ... */
 
 static const AVOption *my_av_find_opt(void *v, const char *name, 
-                                     const char *unit, int mask, int flags){
+                                         const char *unit, int mask, int flags){
        AVClass *c= *(AVClass**)v; 
        const AVOption *o= c->option;
 
@@ -1076,7 +1130,7 @@ int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * s
        
        avcodec_get_context_defaults(&c);
 
-       strncpy(name_, str, 128);
+       strncpy(name_, str, sizeof(name_));
 
        name = name_;
        while (*name == ' ') name++;
@@ -1190,27 +1244,54 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
                rd->ffcodecdata.mux_packet_size = 2048;
                rd->ffcodecdata.mux_rate = 10080000;
 
+               /*
+                * All options here are for x264, but must be set via ffmpeg.
+                * The names are therefore different - Search for "x264 to FFmpeg option mapping"
+                * to get a list.
+                */
+               
+               /*
+                * Use CABAC coder. Using "coder:1", which should be equivalent,
+                * crashes Blender for some reason. Either way - this is no big deal.
+                */
                ffmpeg_property_add_string(rd, "video", "coder:vlc");
+               
+               /* 
+                * The other options were taken from the libx264-default.preset
+                * included in the ffmpeg distribution.
+                */
                ffmpeg_property_add_string(rd, "video", "flags:loop");
                ffmpeg_property_add_string(rd, "video", "cmp:chroma");
                ffmpeg_property_add_string(rd, "video", "partitions:parti4x4");
                ffmpeg_property_add_string(rd, "video", "partitions:partp8x8");
                ffmpeg_property_add_string(rd, "video", "partitions:partb8x8");
                ffmpeg_property_add_string(rd, "video", "me:hex");
-               ffmpeg_property_add_string(rd, "video", "subq:5");
+               ffmpeg_property_add_string(rd, "video", "subq:6");
                ffmpeg_property_add_string(rd, "video", "me_range:16");
+               ffmpeg_property_add_string(rd, "video", "qdiff:4");
                ffmpeg_property_add_string(rd, "video", "keyint_min:25");
                ffmpeg_property_add_string(rd, "video", "sc_threshold:40");
                ffmpeg_property_add_string(rd, "video", "i_qfactor:0.71");
                ffmpeg_property_add_string(rd, "video", "b_strategy:1");
-
+               ffmpeg_property_add_string(rd, "video", "bf:3");
+               ffmpeg_property_add_string(rd, "video", "refs:2");
+               ffmpeg_property_add_string(rd, "video", "qcomp:0.6");
+               ffmpeg_property_add_string(rd, "video", "directpred:3");
+               ffmpeg_property_add_string(rd, "video", "trellis:0");
+               ffmpeg_property_add_string(rd, "video", "flags2:wpred");
+               ffmpeg_property_add_string(rd, "video", "flags2:dct8x8");
+               ffmpeg_property_add_string(rd, "video", "flags2:fastpskip");
+               ffmpeg_property_add_string(rd, "video", "wpredp:2");
+               
+               // This makes x264 output lossless. Will be a separate option later.
+               //ffmpeg_property_add_string(rd, "video", "cqp:0");
                break;
 
        case FFMPEG_PRESET_THEORA:
        case FFMPEG_PRESET_XVID:
                if(preset == FFMPEG_PRESET_XVID) {
                        rd->ffcodecdata.type = FFMPEG_AVI;
-                       rd->ffcodecdata.codec = CODEC_ID_XVID;
+                       rd->ffcodecdata.codec = CODEC_ID_MPEG4;
                }
                else if(preset == FFMPEG_PRESET_THEORA) {
                        rd->ffcodecdata.type = FFMPEG_OGG; // XXX broken
@@ -1240,7 +1321,11 @@ void ffmpeg_verify_image_type(RenderData *rd)
                   rd->ffcodecdata.video_bitrate <= 1) {
 
                        rd->ffcodecdata.codec = CODEC_ID_MPEG2VIDEO;
-                       ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD);
+                       /* Don't set preset, disturbs render resolution.
+                        * ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD); */
+               }
+               if(rd->ffcodecdata.type == FFMPEG_OGG) {
+                       rd->ffcodecdata.type = FFMPEG_MPEG2;
                }
 
                audio= 1;
@@ -1252,7 +1337,7 @@ void ffmpeg_verify_image_type(RenderData *rd)
                }
        }
        else if(rd->imtype == R_XVID) {
-               if(rd->ffcodecdata.codec != CODEC_ID_XVID) {
+               if(rd->ffcodecdata.codec != CODEC_ID_MPEG4) {
                        ffmpeg_set_preset(rd, FFMPEG_PRESET_XVID);
                        audio= 1;
                }
@@ -1264,8 +1349,8 @@ void ffmpeg_verify_image_type(RenderData *rd)
                }
        }
 
-       if(audio && rd->ffcodecdata.audio_codec <= 0) {
-               rd->ffcodecdata.audio_codec = CODEC_ID_MP2;
+       if(audio && rd->ffcodecdata.audio_codec < 0) {
+               rd->ffcodecdata.audio_codec = CODEC_ID_NONE;
                rd->ffcodecdata.audio_bitrate = 128;
        }
 }