use BLI_strncpy and BLI_snprintf when the size of the string is known.
[blender-staging.git] / source / blender / blenkernel / intern / writeffmpeg.c
index 24e0fe95a1f5850c627062e8779fb852987a1ac1..bcdd93ed70be1bd8093a3a154eeec2c4c5882228 100644 (file)
@@ -1,8 +1,4 @@
-/** \file blender/blenkernel/intern/writeffmpeg.c
- *  \ingroup bke
- */
 /*
- * $Id$
  *
  * ffmpeg-write support
  *
  *
  */
 
+/** \file blender/blenkernel/intern/writeffmpeg.c
+ *  \ingroup bke
+ */
+
 #ifdef WITH_FFMPEG
 #include <string.h>
 #include <stdio.h>
 #include <libswscale/swscale.h>
 #include <libavcodec/opt.h>
 
-#if defined(WIN32) && (!(defined snprintf))
-#define snprintf _snprintf
-#endif
-
 #include "MEM_guardedalloc.h"
 
 #include "DNA_scene_types.h"
@@ -347,8 +343,8 @@ static AVFrame* generate_video_frame(uint8_t* pixels, ReportList *reports)
 
        if (c->pix_fmt != PIX_FMT_BGR32) {
                sws_scale(img_convert_ctx, (const uint8_t * const*) rgb_frame->data,
-                         rgb_frame->linesize, 0, c->height, 
-                         current_frame->data, current_frame->linesize);
+                         rgb_frame->linesize, 0, c->height,
+                         current_frame->data, current_frame->linesize);
                delete_picture(rgb_frame);
        }
        return current_frame;
@@ -400,6 +396,20 @@ static void set_ffmpeg_property_option(AVCodecContext* c, IDProperty * prop)
        }
 }
 
+static int ffmpeg_proprty_valid(AVCodecContext *c, const char *prop_name, IDProperty *curr)
+{
+       int valid= 1;
+
+       if(strcmp(prop_name, "video")==0) {
+               if(strcmp(curr->name, "bf")==0) {
+                       /* flash codec doesn't support b frames */
+                       valid&= c->codec_id!=CODEC_ID_FLV1;
+               }
+       }
+
+       return valid;
+}
+
 static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char * prop_name)
 {
        IDProperty * prop;
@@ -410,8 +420,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;
        }
@@ -419,7 +428,8 @@ static void set_ffmpeg_properties(RenderData *rd, AVCodecContext *c, const char
        iter = IDP_GetGroupIterator(prop);
 
        while ((curr = IDP_GroupIterNext(iter)) != NULL) {
-               set_ffmpeg_property_option(c, curr);
+               if(ffmpeg_proprty_valid(c, prop_name, curr))
+                       set_ffmpeg_property_option(c, curr);
        }
 }
 
@@ -493,6 +503,12 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                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")
@@ -522,8 +538,8 @@ static AVStream* alloc_video_stream(RenderData *rd, int codec_id, AVFormatContex
                return NULL;
        }
 
-       video_buffersize = 2000000;
-       video_buffer = (uint8_t*)MEM_mallocN(video_buffersize
+       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);
@@ -569,6 +585,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))
@@ -652,7 +673,7 @@ 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:
@@ -741,7 +762,11 @@ static int start_ffmpeg_impl(struct RenderData *rd, int rectx, int recty, Report
                }
        }
 
-       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;
        av_dump_format(of, 0, name, 1);
 
@@ -812,7 +837,8 @@ void flush_ffmpeg(void)
    ********************************************************************** */
 
 /* 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);
@@ -1012,8 +1038,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);
@@ -1021,7 +1046,7 @@ void ffmpeg_property_del(RenderData *rd, void *type, void *prop_)
        }
 }
 
-IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int parent_index)
+IDProperty *ffmpeg_property_add(RenderData *rd, const char *type, int opt_index, int parent_index)
 {
        AVCodecContext c;
        const AVOption * o;
@@ -1041,21 +1066,20 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
 
        if (!rd->ffcodecdata.properties) {
                rd->ffcodecdata.properties 
-                       = IDP_New(IDP_GROUP, val, "ffmpeg"); 
+                       = IDP_New(IDP_GROUP, &val, "ffmpeg"); 
        }
 
-       group = IDP_GetPropertyFromGroup(
-               rd->ffcodecdata.properties, (char*) type);
+       group = IDP_GetPropertyFromGroup(rd->ffcodecdata.properties, type);
        
        if (!group) {
-               group = IDP_New(IDP_GROUP, val, (char*) type); 
+               group = IDP_New(IDP_GROUP, &val, type);
                IDP_AddToGroup(rd->ffcodecdata.properties, group);
        }
 
        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",
@@ -1078,7 +1102,9 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
                idp_type = IDP_FLOAT;
                break;
        case FF_OPT_TYPE_STRING:
-               val.str = "                                                                               ";
+               val.string.str = (char *)"                                                                               ";
+               val.string.len = 80;
+/*             val.str = (char *)"                                                                               ";*/
                idp_type = IDP_STRING;
                break;
        case FF_OPT_TYPE_CONST:
@@ -1088,7 +1114,7 @@ IDProperty *ffmpeg_property_add(RenderData *rd, char * type, int opt_index, int
        default:
                return NULL;
        }
-       prop = IDP_New(idp_type, val, name);
+       prop = IDP_New(idp_type, &val, name);
        IDP_AddToGroup(group, prop);
        return prop;
 }
@@ -1178,6 +1204,9 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
 {
        int isntsc = (rd->frs_sec != 25);
 
+       if(rd->ffcodecdata.properties)
+               IDP_FreeProperty(rd->ffcodecdata.properties);
+
        switch (preset) {
        case FFMPEG_PRESET_VCD:
                rd->ffcodecdata.type = FFMPEG_MPEG1;
@@ -1208,8 +1237,11 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
        case FFMPEG_PRESET_DVD:
                rd->ffcodecdata.type = FFMPEG_MPEG2;
                rd->ffcodecdata.video_bitrate = 6000;
-               rd->xsch = 720;
-               rd->ysch = isntsc ? 480 : 576;
+
+               /* Don't set resolution, see [#21351]
+                * rd->xsch = 720;
+                * rd->ysch = isntsc ? 480 : 576; */
+
                rd->ffcodecdata.gop_size = isntsc ? 18 : 15;
                rd->ffcodecdata.rc_max_rate = 9000;
                rd->ffcodecdata.rc_min_rate = 0;
@@ -1301,19 +1333,19 @@ void ffmpeg_set_preset(RenderData *rd, int preset)
        }
 }
 
-void ffmpeg_verify_image_type(RenderData *rd)
+void ffmpeg_verify_image_type(RenderData *rd, ImageFormatData *imf)
 {
        int audio= 0;
 
-       if(rd->imtype == R_FFMPEG) {
+       if(imf->imtype == R_IMF_IMTYPE_FFMPEG) {
                if(rd->ffcodecdata.type <= 0 ||
                   rd->ffcodecdata.codec <= 0 ||
                   rd->ffcodecdata.audio_codec <= 0 ||
                   rd->ffcodecdata.video_bitrate <= 1) {
 
                        rd->ffcodecdata.codec = CODEC_ID_MPEG2VIDEO;
-                       /* Don't set preset, disturbs render resolution.
-                        * ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD); */
+
+                       ffmpeg_set_preset(rd, FFMPEG_PRESET_DVD);
                }
                if(rd->ffcodecdata.type == FFMPEG_OGG) {
                        rd->ffcodecdata.type = FFMPEG_MPEG2;
@@ -1321,19 +1353,19 @@ void ffmpeg_verify_image_type(RenderData *rd)
 
                audio= 1;
        }
-       else if(rd->imtype == R_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_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_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;
@@ -1347,4 +1379,3 @@ void ffmpeg_verify_image_type(RenderData *rd)
 }
 
 #endif
-