Cycles: svn merge -r41225:41232 ^/trunk/blender
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
index 917ecd044ea6fb4b4f8dff30d8aaa77a33bc4a29..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;
@@ -99,7 +87,9 @@ 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
 
@@ -113,24 +103,13 @@ 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);
+       c = audio_stream->codec;
 
        av_init_packet(&pkt);
        pkt.size = 0;
@@ -152,23 +131,22 @@ static int write_audio_frame(void)
 
        if(c->coded_frame && c->coded_frame->pts != AV_NOPTS_VALUE)
        {
-#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
+                                      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) 
@@ -206,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: {
@@ -262,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;
@@ -309,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;
@@ -366,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);
@@ -382,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, ':');
 
@@ -393,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));
@@ -404,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;
                        }
@@ -430,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;
        }
@@ -446,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;
@@ -456,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 */
@@ -466,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;
@@ -479,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;
@@ -516,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")
@@ -550,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);
 
@@ -576,14 +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->sample_fmt = SAMPLE_FMT_S16;
-       c->channels = 2;
+       c->channels = rd->ffcodecdata.audio_channels;
        codec = avcodec_find_encoder(c->codec_id);
        if (!codec) {
                //XXX error("Couldn't find a valid audio codec");
@@ -597,6 +570,11 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
                return NULL;
        }
 
+       /* 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;
+
        audio_outbuf_size = FF_MIN_BUFFER_SIZE;
 
        if((c->codec_id >= CODEC_ID_PCM_S16LE) && (c->codec_id <= CODEC_ID_PCM_DVD))
@@ -608,12 +586,11 @@ static AVStream* alloc_audio_stream(RenderData *rd, int codec_id, AVFormatContex
                        audio_outbuf_size = c->frame_size * c->channels * sizeof(int16_t) * 4;
        }
 
-       audio_output_buffer = (uint8_t*)MEM_mallocN(
-               audio_outbuf_size, "FFMPEG audio encoder input buffer");
+       audio_output_buffer = (uint8_t*)av_malloc(
+               audio_outbuf_size);
 
-       audio_input_buffer = (uint8_t*)MEM_mallocN(
-               audio_input_samples * c->channels * sizeof(int16_t),
-               "FFMPEG audio encoder output buffer");
+       audio_input_buffer = (uint8_t*)av_malloc(
+               audio_input_samples * c->channels * sizeof(int16_t));
 
        audio_time = 0.0f;
 
@@ -656,13 +633,13 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
                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;
@@ -681,15 +658,17 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
 
        fmt->audio_codec = ffmpeg_audio_codec;
 
-       snprintf(of->filename, sizeof(of->filename), "%s", name);
+       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;
@@ -703,7 +682,7 @@ 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;
@@ -735,7 +714,7 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
        
        if (ffmpeg_type == FFMPEG_DV) {
                fmt->audio_codec = CODEC_ID_PCM_S16LE;
-               if (ffmpeg_audio_codec != CODEC_ID_NONE && 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;
                }
@@ -762,25 +741,89 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
                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);
@@ -789,7 +832,7 @@ void filepath_ffmpeg(char* string, RenderData* rd) {
        if (!string || !exts) return;
 
        strcpy(string, rd->pic);
-       BLI_convertstringcode(string, G.sce);
+       BLI_path_abs(string, G.main->name);
 
        BLI_make_existing_file(string);
 
@@ -810,7 +853,7 @@ void filepath_ffmpeg(char* string, RenderData* rd) {
        if (!*fe) {
                strcat(string, autosplit);
 
-               BLI_convertstringframe_range(string, rd->sfra, rd->efra, 4);
+               BLI_path_frame_range(string, rd->sfra, rd->efra, 4);
                strcat(string, *exts);
        } else {
                *(string + strlen(string) - strlen(*fe)) = 0;
@@ -826,22 +869,27 @@ 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);
-
+#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->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);
 
+#ifdef WITH_AUDASPACE
 static void write_audio_frames(double to_pts)
 {
        int finished = 0;
@@ -853,6 +901,7 @@ static void write_audio_frames(double to_pts)
                }
        }
 }
+#endif
 
 int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty, ReportList *reports) 
 {
@@ -872,7 +921,7 @@ int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty,
                success= (avframe && write_video_frame(rd, avframe, reports));
 
                if (ffmpeg_autosplit) {
-                       if (url_ftell(OUTFILE_PB) > FFMPEG_AUTOSPLIT_SIZE) {
+                       if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
                                end_ffmpeg();
                                ffmpeg_autosplit_count++;
                                success &= start_ffmpeg_impl(rd, rectx, recty, reports);
@@ -880,15 +929,15 @@ int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty,
                }
        }
 
-       write_audio_frames(frame / (((double)rd->frs_sec) / rd->frs_sec_base));
-
+#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");
 
@@ -896,11 +945,18 @@ void end_ffmpeg(void)
                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);
@@ -908,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;
        }
 
        
@@ -930,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) {
@@ -942,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;
        }
 
@@ -967,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);
@@ -986,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);
 
@@ -993,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);
        }
 
@@ -1026,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:
@@ -1053,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;
 
@@ -1078,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++;
@@ -1192,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
@@ -1242,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;
@@ -1254,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;
                }