ClangFormat: apply to source, most of intern
[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   if (preview) {
170     sfra = rd->psfra;
171     efra = rd->pefra;
172   }
173   else {
174     sfra = rd->sfra;
175     efra = rd->efra;
176   }
177
178   strcpy(string, rd->pic);
179   BLI_path_abs(string, BKE_main_blendfile_path_from_global());
180
181   BLI_make_existing_file(string);
182
183   if (rd->scemode & R_EXTENSION) {
184     if (!BLI_path_extension_check(string, ".avi")) {
185       BLI_path_frame_range(string, sfra, efra, 4);
186       strcat(string, ".avi");
187     }
188   }
189   else {
190     if (BLI_path_frame_check_chars(string)) {
191       BLI_path_frame_range(string, sfra, efra, 4);
192     }
193   }
194
195   BLI_path_suffix(string, FILE_MAX, suffix, "");
196 }
197
198 static int start_avi(void *context_v,
199                      Scene *UNUSED(scene),
200                      RenderData *rd,
201                      int rectx,
202                      int recty,
203                      ReportList *reports,
204                      bool preview,
205                      const char *suffix)
206 {
207   int x, y;
208   char name[256];
209   AviFormat format;
210   int quality;
211   double framerate;
212   AviMovie *avi = context_v;
213
214   filepath_avi(name, rd, preview, suffix);
215
216   x = rectx;
217   y = recty;
218
219   quality = rd->im_format.quality;
220   framerate = (double)rd->frs_sec / (double)rd->frs_sec_base;
221
222   if (rd->im_format.imtype != R_IMF_IMTYPE_AVIJPEG)
223     format = AVI_FORMAT_AVI_RGB;
224   else
225     format = AVI_FORMAT_MJPEG;
226
227   if (AVI_open_compress(name, avi, 1, format) != AVI_ERROR_NONE) {
228     BKE_report(reports, RPT_ERROR, "Cannot open or start AVI movie file");
229     return 0;
230   }
231
232   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_WIDTH, &x);
233   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_HEIGHT, &y);
234   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_QUALITY, &quality);
235   AVI_set_compress_option(avi, AVI_OPTION_TYPE_MAIN, 0, AVI_OPTION_FRAMERATE, &framerate);
236
237   avi->interlace = 0;
238   avi->odd_fields = 0;
239
240   printf("Created avi: %s\n", name);
241   return 1;
242 }
243
244 static int append_avi(void *context_v,
245                       RenderData *UNUSED(rd),
246                       int start_frame,
247                       int frame,
248                       int *pixels,
249                       int rectx,
250                       int recty,
251                       const char *UNUSED(suffix),
252                       ReportList *UNUSED(reports))
253 {
254   unsigned int *rt1, *rt2, *rectot;
255   int x, y;
256   char *cp, rt;
257   AviMovie *avi = context_v;
258
259   if (avi == NULL)
260     return 0;
261
262   /* note that libavi free's the buffer... stupid interface - zr */
263   rectot = MEM_mallocN(rectx * recty * sizeof(int), "rectot");
264   rt1 = rectot;
265   rt2 = (unsigned int *)pixels + (recty - 1) * rectx;
266   /* flip y and convert to abgr */
267   for (y = 0; y < recty; y++, rt1 += rectx, rt2 -= rectx) {
268     memcpy(rt1, rt2, rectx * sizeof(int));
269
270     cp = (char *)rt1;
271     for (x = rectx; x > 0; x--) {
272       rt = cp[0];
273       cp[0] = cp[3];
274       cp[3] = rt;
275       rt = cp[1];
276       cp[1] = cp[2];
277       cp[2] = rt;
278       cp += 4;
279     }
280   }
281
282   AVI_write_frame(avi, (frame - start_frame), AVI_FORMAT_RGB32, rectot, rectx * recty * 4);
283   //  printf("added frame %3d (frame %3d in avi): ", frame, frame-start_frame);
284
285   return 1;
286 }
287
288 static void end_avi(void *context_v)
289 {
290   AviMovie *avi = context_v;
291
292   if (avi == NULL)
293     return;
294
295   AVI_close_compress(avi);
296 }
297
298 static void *context_create_avi(void)
299 {
300   AviMovie *avi = MEM_mallocN(sizeof(AviMovie), "avimovie");
301   return avi;
302 }
303
304 static void context_free_avi(void *context_v)
305 {
306   AviMovie *avi = context_v;
307   if (avi) {
308     MEM_freeN(avi);
309   }
310 }
311
312 #endif /* WITH_AVI */
313
314 /* similar to BKE_image_path_from_imformat() */
315 void BKE_movie_filepath_get(char *string, RenderData *rd, bool preview, const char *suffix)
316 {
317   bMovieHandle *mh = BKE_movie_handle_get(rd->im_format.imtype);
318   if (mh && mh->get_movie_path) {
319     mh->get_movie_path(string, rd, preview, suffix);
320   }
321   else {
322     string[0] = '\0';
323   }
324 }