FFmpeg output fixes and small improvement
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
index 0b043e26ab7e09586bb39a579a94864e4b8ff04b..1e2791acfeee307877759e02597a3431de3aab68 100644 (file)
@@ -49,6 +49,8 @@
 #  include "AUD_C-API.h"
 #endif
 
+#include "BLI_utildefines.h"
+
 #include "BKE_global.h"
 #include "BKE_idprop.h"
 #include "BKE_main.h"
@@ -76,6 +78,7 @@ static AVFormatContext* outfile = 0;
 static AVStream* video_stream = 0;
 static AVStream* audio_stream = 0;
 static AVFrame* current_frame = 0;
+static int img_convert_fmt = 0;
 static struct SwsContext *img_convert_ctx = 0;
 
 static uint8_t* video_buffer = 0;
@@ -250,7 +253,8 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame* frame, ReportLis
 
        outsize = avcodec_encode_video(c, video_buffer, video_buffersize, 
                                           frame);
-       if (outsize != 0) {
+
+       if (outsize > 0) {
                AVPacket packet;
                av_init_packet(&packet);
 
@@ -268,14 +272,13 @@ static int write_video_frame(RenderData *rd, int cfra, AVFrame* frame, ReportLis
                packet.data = video_buffer;
                packet.size = outsize;
                ret = av_interleaved_write_frame(outfile, &packet);
-       } else {
-               ret = 0;
+               success = (ret == 0);
+       } else if (outsize < 0) {
+               success = 0;
        }
 
-       if (ret != 0) {
-               success= 0;
+       if (!success)
                BKE_report(reports, RPT_ERROR, "Error writing frame.");
-       }
 
        return success;
 }
@@ -290,8 +293,8 @@ static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)
        int height = c->height;
        AVFrame* rgb_frame;
 
-       if (c->pix_fmt != PIX_FMT_BGR32) {
-               rgb_frame = alloc_picture(PIX_FMT_BGR32, width, height);
+       if (c->pix_fmt != img_convert_fmt) {
+               rgb_frame = alloc_picture(img_convert_fmt, width, height);
                if (!rgb_frame) {
                        BKE_report(reports, RPT_ERROR, "Couldn't allocate temporary frame.");
                        return NULL;
@@ -341,7 +344,7 @@ static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)
                }
        }
 
-       if (c->pix_fmt != PIX_FMT_BGR32) {
+       if (c->pix_fmt != img_convert_fmt) {
                sws_scale(img_convert_ctx, (const uint8_t * const*) rgb_frame->data,
                          rgb_frame->linesize, 0, c->height,
                          current_frame->data, current_frame->linesize);
@@ -483,7 +486,9 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
        if (!codec) return NULL;
        
        /* Be sure to use the correct pixel format(e.g. RGB, YUV) */
-       
+
+       img_convert_fmt = PIX_FMT_BGR32;
+
        if (codec->pix_fmts) {
                c->pix_fmt = codec->pix_fmts[0];
        } else {
@@ -509,6 +514,13 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                c->pix_fmt = PIX_FMT_RGB32;
        }
 
+       if ( codec_id == CODEC_ID_QTRLE ) {
+               if (rd->im_format.planes ==  R_IMF_PLANES_RGBA) {
+                       c->pix_fmt = PIX_FMT_ARGB;
+                       img_convert_fmt = PIX_FMT_BGRA;
+               }
+       }
+
        if ((of->oformat->flags & AVFMT_GLOBALHEADER)
 //             || !strcmp(of->oformat->name, "mp4")
 //         || !strcmp(of->oformat->name, "mov")
@@ -538,14 +550,26 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                return NULL;
        }
 
-       video_buffersize = avpicture_get_size(c->pix_fmt, c->width, c->height);
+       if ( codec_id == CODEC_ID_QTRLE ) {
+               // normally it should be enough to have buffer with actual image size,
+               // but some codecs like QTRLE might store extra information in this buffer,
+               // so it should be a way larger
+
+               // maximum video buffer size is 6-bytes per pixel, plus DPX header size (1664)
+               // (from FFmpeg sources)
+               int size = c->width * c->height;
+               video_buffersize = 7*size + 10000;
+       }
+       else
+               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);
 
        img_convert_ctx = sws_getContext(c->width, c->height,
-                                        PIX_FMT_BGR32,
+                                        img_convert_fmt,
                                         c->width, c->height,
                                         c->pix_fmt,
                                         SWS_BICUBIC,
@@ -1200,12 +1224,14 @@ int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * s
        return 1;
 }
 
-static void ffmpeg_set_expert_options(RenderData *rd, int preset)
+static void ffmpeg_set_expert_options(RenderData *rd)
 {
+       int codec_id = rd->ffcodecdata.codec;
+
        if(rd->ffcodecdata.properties)
                IDP_FreeProperty(rd->ffcodecdata.properties);
 
-       if(preset == FFMPEG_PRESET_H264) {
+       if(codec_id == CODEC_ID_H264) {
                /*
                 * All options here are for x264, but must be set via ffmpeg.
                 * The names are therefore different - Search for "x264 to FFmpeg option mapping"
@@ -1248,6 +1274,12 @@ static void ffmpeg_set_expert_options(RenderData *rd, int preset)
                if(rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
                        ffmpeg_property_add_string(rd, "video", "cqp:0");
        }
+#if 0  /* disabled for after release */
+       else if(codec_id == CODEC_ID_DNXHD) {
+               if(rd->ffcodecdata.flags & FFMPEG_LOSSLESS_OUTPUT)
+                       ffmpeg_property_add_string(rd, "video", "mbd:rd");
+       }
+#endif
 }
 
 void ffmpeg_set_preset(RenderData *rd, int preset)
@@ -1317,7 +1349,6 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
                rd->ffcodecdata.mux_packet_size = 2048;
                rd->ffcodecdata.mux_rate = 10080000;
 
-               ffmpeg_set_expert_options(rd, preset);
                break;
 
        case FFMPEG_PRESET_THEORA:
@@ -1341,6 +1372,8 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
                break;
 
        }
+
+       ffmpeg_set_expert_options(rd);
 }
 
 void ffmpeg_verify_image_type(RenderData *rd, ImageFormatData *imf)
@@ -1388,11 +1421,9 @@ void ffmpeg_verify_image_type(RenderData *rd, ImageFormatData *imf)
        }
 }
 
-void ffmpeg_verify_lossless_format(RenderData *rd, ImageFormatData *imf)
+void ffmpeg_verify_codec_settings(RenderData *rd)
 {
-       if(imf->imtype == R_IMF_IMTYPE_H264) {
-               ffmpeg_set_expert_options(rd, FFMPEG_PRESET_H264);
-       }
+       ffmpeg_set_expert_options(rd);
 }
 
 #endif