Cleanup: style, use braces for blenkernel
[blender.git] / source / blender / blenkernel / intern / writeavi.c
1 /*
2  * This program is free software; you can redistribute it and/or
3  * modify it under the terms of the GNU General Public License
4  * as published by the Free Software Foundation; either version 2
5  * of the License, or (at your option) any later version.
6  *
7  * This program is distributed in the hope that it will be useful,
8  * but WITHOUT ANY WARRANTY; without even the implied warranty of
9  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
10  * GNU General Public License for more details.
11  *
12  * You should have received a copy of the GNU General Public License
13  * along with this program; if not, write to the Free Software Foundation,
14  * Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
15  *
16  * The Original Code is Copyright (C) 2001-2002 by NaN Holding BV.
17  * All rights reserved.
18  * Functions for writing avi-format files.
19  * Added interface for generic movie support (ton)
20  */
21
22 /** \file
23  * \ingroup bke
24  */
25
26 #include <string.h>
27
28 #include "MEM_guardedalloc.h"
29
30 #include "DNA_scene_types.h"
31
32 #include "BLI_utildefines.h"
33
34 #include "BKE_report.h"
35 #ifdef WITH_AVI
36 #  include "BLI_blenlib.h"
37
38 #  include "BKE_main.h"
39 #endif
40
41 #include "BKE_writeavi.h"
42
43 /* ********************** general blender movie support ***************************** */
44
45 static int start_stub(void *UNUSED(context_v),
46                       Scene *UNUSED(scene),
47                       RenderData *UNUSED(rd),
48                       int UNUSED(rectx),
49                       int UNUSED(recty),
50                       ReportList *UNUSED(reports),
51                       bool UNUSED(preview),
52                       const char *UNUSED(suffix))
53 {
54   return 0;
55 }
56
57 static void end_stub(void *UNUSED(context_v))
58 {
59 }
60
61 static int append_stub(void *UNUSED(context_v),
62                        RenderData *UNUSED(rd),
63                        int UNUSED(start_frame),
64                        int UNUSED(frame),
65                        int *UNUSED(pixels),
66                        int UNUSED(rectx),
67                        int UNUSED(recty),
68                        const char *UNUSED(suffix),
69                        ReportList *UNUSED(reports))
70 {
71   return 0;
72 }
73
74 static void *context_create_stub(void)
75 {
76   return NULL;
77 }
78
79 static void context_free_stub(void *UNUSED(context_v))
80 {
81 }
82
83 #ifdef WITH_AVI
84 #  include "AVI_avi.h"
85
86 /* callbacks */
87 static int start_avi(void *context_v,
88                      Scene *scene,
89                      RenderData *rd,
90                      int rectx,
91                      int recty,
92                      ReportList *reports,
93                      bool preview,
94                      const char *suffix);
95 static void end_avi(void *context_v);
96 static int append_avi(void *context_v,
97                       RenderData *rd,
98                       int start_frame,
99                       int frame,
100                       int *pixels,
101                       int rectx,
102                       int recty,
103                       const char *suffix,
104                       ReportList *reports);
105 static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix);
106 static void *context_create_avi(void);
107 static void context_free_avi(void *context_v);
108 #endif /* WITH_AVI */
109
110 #ifdef WITH_FFMPEG
111 #  include "BKE_writeffmpeg.h"
112 #endif
113
114 bMovieHandle *BKE_movie_handle_get(const char imtype)
115 {
116   static bMovieHandle mh = {NULL};
117   /* stub callbacks in case none of the movie formats is supported */
118   mh.start_movie = start_stub;
119   mh.append_movie = append_stub;
120   mh.end_movie = end_stub;
121   mh.get_next_frame = NULL;
122   mh.get_movie_path = NULL;
123   mh.context_create = context_create_stub;
124   mh.context_free = context_free_stub;
125
126   /* set the default handle, as builtin */
127 #ifdef WITH_AVI
128   mh.start_movie = start_avi;
129   mh.append_movie = append_avi;
130   mh.end_movie = end_avi;
131   mh.get_movie_path = filepath_avi;
132   mh.context_create = context_create_avi;
133   mh.context_free = context_free_avi;
134 #endif
135
136   /* do the platform specific handles */
137 #ifdef WITH_FFMPEG
138   if (ELEM(imtype,
139            R_IMF_IMTYPE_FFMPEG,
140            R_IMF_IMTYPE_H264,
141            R_IMF_IMTYPE_XVID,
142            R_IMF_IMTYPE_THEORA)) {
143     mh.start_movie = BKE_ffmpeg_start;
144     mh.append_movie = BKE_ffmpeg_append;
145     mh.end_movie = BKE_ffmpeg_end;
146     mh.get_movie_path = BKE_ffmpeg_filepath_get;
147     mh.context_create = BKE_ffmpeg_context_create;
148     mh.context_free = BKE_ffmpeg_context_free;
149   }
150 #endif
151
152   /* in case all above are disabled */
153   (void)imtype;
154
155   return (mh.append_movie != append_stub) ? &mh : NULL;
156 }
157
158 /* ****************************************************************** */
159
160 #ifdef WITH_AVI
161
162 static void filepath_avi(char *string, RenderData *rd, bool preview, const char *suffix)
163 {
164   int sfra, efra;
165
166   if (string == NULL) {
167     return;
168   }
169
170   if (preview) {
171     sfra = rd->psfra;
172     efra = rd->pefra;
173   }
174   else {
175     sfra = rd->sfra;
176     efra = rd->efra;
177   }
178
179   strcpy(string, rd->pic);
180   BLI_path_abs(string, BKE_main_blendfile_path_from_global());
181
182   BLI_make_existing_file(string);
183
184   if (rd->scemode & R_EXTENSION) {
185     if (!BLI_path_extension_check(string, ".avi")) {
186       BLI_path_frame_range(string, sfra, efra, 4);
187       strcat(string, ".avi");
188     }
189   }
190   else {
191     if (BLI_path_frame_check_chars(string)) {
192       BLI_path_frame_range(string, sfra, efra, 4);
193     }
194   }
195
196   BLI_path_suffix(string, FILE_MAX, suffix, "");
197 }
198
199 static int start_avi(void *context_v,
200                      Scene *UNUSED(scene),
201                      RenderData *rd,
202                      int rectx,
203                      int recty,
204                      ReportList *reports,
205                      bool preview,
206                      const char *suffix)
207 {
208   int x, y;
209   char name[256];
210   AviFormat format;
211   int quality;
212   double framerate;
213   AviMovie *avi = context_v;
214
215   filepath_avi(name, rd, preview, suffix);
216
217   x = rectx;
218   y = recty;
219
220   quality = rd->im_format.quality;
221   framerate = (double)rd->frs_sec / (double)rd->frs_sec_base;
222
223   if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG) {
224     format = AVI_FORMAT_AVI_RGB;
225   }
226   else {
227     format = AVI_FORMAT_MJPEG;
228   }
229
230   if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
231     BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
232     return 0;
233   }
234
235   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
236   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
237   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
238   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
239
240   avi->interlace = 0;
241   avi->odd_fields = 0;
242
243   printf("Created avi: %s\n", name);
244   return 1;
245 }
246
247 static int append_avi(void *context_v,
248                       RenderData *UNUSED(rd),
249                       int start_frame,
250                       int frame,
251                       int *pixels,
252                       int rectx,
253                       int recty,
254                       const char *UNUSED(suffix),
255                       ReportList *UNUSED(reports))
256 {
257   unsigned int *rt1, *rt2, *rectot;
258   int x, y;
259   char *cp, rt;
260   AviMovie *avi = context_v;
261
262   if (avi == NULL) {
263     return 0;
264   }
265
266   /* note that libavi free's the buffer... stupid interface - zr */
267   rectot = MEM_mallocN(rectx * recty * sizeof(int), "rectot");
268   rt1 = rectot;
269   rt2 = (unsigned int *)pixels + (recty - 1) * rectx;
270   /* flip y and convert to abgr */
271   for (y = 0; y < recty; y++, rt1 += rectx, rt2 -= rectx) {
272     memcpy(rt1, rt2, rectx * sizeof(int));
273
274     cp = (char *)rt1;
275     for (x = rectx; x > 0; x--) {
276       rt = cp[0];
277       cp[0] = cp[3];
278       cp[3] = rt;
279       rt = cp[1];
280       cp[1] = cp[2];
281       cp[2] = rt;
282       cp += 4;
283     }
284   }
285
286   AVI_write_frame(avi, (frame - start_frame), AVI_FORMAT_RGB32, rectot, rectx * recty * 4);
287   //  printf("added frame %3d (frame %3d in avi): ", frame, frame-start_frame);
288
289   return 1;
290 }
291
292 static void end_avi(void *context_v)
293 {
294   AviMovie *avi = context_v;
295
296   if (avi == NULL) {
297     return;
298   }
299
300   AVI_close_compress(avi);
301 }
302
303 static void *context_create_avi(void)
304 {
305   AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
306   return avi;
307 }
308
309 static void context_free_avi(void *context_v)
310 {
311   AviMovie *avi = context_v;
312   if (avi) {
313     MEM_freeN(avi);
314   }
315 }
316
317 #endif /* WITH_AVI */
318
319 /* similar to BKE_image_path_from_imformat() */
320 void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
321 {
322   bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
323   if (mh && mh->get_movie_path) {
324     mh->get_movie_path(string, rd, preview, suffix);
325   }
326   else {
327     string[0] = '\0';
328   }
329 }