Camera tracking: fixed issue when track used for rotation stabilization points to...
[blender.git] / source / blender / blenkernel / intern / writeffmpeg.c
index aa7d71b..e9f7823 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"
@@ -236,13 +238,13 @@ static const char** get_file_extensions(int format)
 }
 
 /* Write a frame to the output file */
-static int write_video_frame(RenderData *rd, AVFrame* frame, ReportList *reports)
+static int write_video_frame(RenderData *rd, int cfra, AVFrame* frame, ReportList *reports)
 {
        int outsize = 0;
        int ret, success= 1;
        AVCodecContext* c = video_stream->codec;
 
-       frame->pts = rd->cfra - rd->sfra;
+       frame->pts = cfra;
 
        if (rd->mode & R_FIELDS) {
                frame->top_field_first = ((rd->mode & R_ODDFIELD) != 0);
@@ -250,7 +252,8 @@ static int write_video_frame(RenderData *rd, AVFrame* frame, ReportList *reports
 
        outsize = avcodec_encode_video(c, video_buffer, video_buffersize, 
                                           frame);
-       if (outsize != 0) {
+
+       if (outsize > 0) {
                AVPacket packet;
                av_init_packet(&packet);
 
@@ -268,14 +271,13 @@ static int write_video_frame(RenderData *rd, AVFrame* frame, ReportList *reports
                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;
 }
@@ -483,7 +485,7 @@ 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) */
-       
+
        if (codec->pix_fmts) {
                c->pix_fmt = codec->pix_fmts[0];
        } else {
@@ -509,6 +511,12 @@ 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;
+               }
+       }
+
        if ((of->oformat->flags & AVFMT_GLOBALHEADER)
 //             || !strcmp(of->oformat->name, "mp4")
 //         || !strcmp(of->oformat->name, "mov")
@@ -538,7 +546,19 @@ 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");
        
@@ -918,7 +938,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) 
+int append_ffmpeg(RenderData *rd, int start_frame, int frame, int *pixels, int rectx, int recty, ReportList *reports)
 {
        AVFrame* avframe;
        int success = 1;
@@ -933,7 +953,7 @@ int append_ffmpeg(RenderData *rd, int frame, int *pixels, int rectx, int recty,
        if(video_stream)
        {
                avframe= generate_video_frame((unsigned char*) pixels, reports);
-               success= (avframe && write_video_frame(rd, avframe, reports));
+               success= (avframe && write_video_frame(rd, frame - start_frame, avframe, reports));
 
                if (ffmpeg_autosplit) {
                        if (avio_tell(outfile->pb) > FFMPEG_AUTOSPLIT_SIZE) {
@@ -1077,9 +1097,9 @@ IDProperty *ffmpeg_property_add(RenderData *rd, const char *type, int opt_index,
        }
 
        if (parent_index) {
-               sprintf(name, "%s:%s", parent->name, o->name);
+               BLI_snprintf(name, sizeof(name), "%s:%s", parent->name, o->name);
        } else {
-               strcpy(name, o->name);
+               BLI_strncpy(name, o->name, sizeof(name));
        }
 
        fprintf(stderr, "ffmpeg_property_add: %s %d %d %s\n",
@@ -1200,6 +1220,64 @@ int ffmpeg_property_add_string(RenderData *rd, const char * type, const char * s
        return 1;
 }
 
+static void ffmpeg_set_expert_options(RenderData *rd)
+{
+       int codec_id = rd->ffcodecdata.codec;
+
+       if(rd->ffcodecdata.properties)
+               IDP_FreeProperty(rd->ffcodecdata.properties);
+
+       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"
+                * 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"); // this breaks compatibility for QT
+               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: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");
+
+               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)
 {
        int isntsc = (rd->frs_sec != 25);
@@ -1267,47 +1345,6 @@ 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: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:
@@ -1331,13 +1368,15 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
                break;
 
        }
+
+       ffmpeg_set_expert_options(rd);
 }
 
-void ffmpeg_verify_image_type(RenderData *rd)
+void ffmpeg_verify_image_type(RenderData *rd, ImageFormatData *imf)
 {
        int audio= 0;
 
-       if(rd->imtype == R_IMF_IMTYPE_FFMPEG) {
+       if(imf->imtype == R_IMF_IMTYPE_FFMPEG) {
                if(rd->ffcodecdata.type <= 0 ||
                   rd->ffcodecdata.codec <= 0 ||
                   rd->ffcodecdata.audio_codec <= 0 ||
@@ -1353,19 +1392,19 @@ void ffmpeg_verify_image_type(RenderData *rd)
 
                audio= 1;
        }
-       else if(rd->imtype == R_IMF_IMTYPE_H264) {
+       else if(imf->imtype == R_IMF_IMTYPE_H264) {
                if(rd->ffcodecdata.codec != CODEC_ID_H264) {
                        ffmpeg_set_preset(rd, FFMPEG_PRESET_H264);
                        audio= 1;
                }
        }
-       else if(rd->imtype == R_IMF_IMTYPE_XVID) {
+       else if(imf->imtype == R_IMF_IMTYPE_XVID) {
                if(rd->ffcodecdata.codec != CODEC_ID_MPEG4) {
                        ffmpeg_set_preset(rd, FFMPEG_PRESET_XVID);
                        audio= 1;
                }
        }
-       else if(rd->imtype == R_IMF_IMTYPE_THEORA) {
+       else if(imf->imtype == R_IMF_IMTYPE_THEORA) {
                if(rd->ffcodecdata.codec != CODEC_ID_THEORA) {
                        ffmpeg_set_preset(rd, FFMPEG_PRESET_THEORA);
                        audio= 1;
@@ -1378,4 +1417,9 @@ void ffmpeg_verify_image_type(RenderData *rd)
        }
 }
 
+void ffmpeg_verify_codec_settings(RenderData *rd)
+{
+       ffmpeg_set_expert_options(rd);
+}
+
 #endif