Blender  V2.93
avi.c
Go to the documentation of this file.
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  */
19 
26 #include <ctype.h>
27 #include <stdarg.h>
28 #include <stdio.h>
29 #include <stdlib.h>
30 #include <string.h>
31 
32 #ifdef WIN32
33 # include "BLI_winstuff.h"
34 #endif
35 
36 #include "MEM_guardedalloc.h"
37 
38 #include "BLI_fileops.h"
39 #include "BLI_sys_types.h"
40 #include "BLI_utildefines.h"
41 
42 #include "AVI_avi.h"
43 #include "avi_intern.h"
44 
45 #include "avi_endian.h"
46 
47 static int AVI_DEBUG = 0;
48 static char DEBUG_FCC[4];
49 
50 #define DEBUG_PRINT(x) \
51  if (AVI_DEBUG) { \
52  printf("AVI DEBUG: " x); \
53  } \
54  (void)0
55 
56 /* local functions */
57 char *fcc_to_char(unsigned int fcc);
58 char *tcc_to_char(unsigned int tcc);
59 
60 /* implementation */
61 
62 unsigned int GET_FCC(FILE *fp)
63 {
64  unsigned char tmp[4];
65 
66  tmp[0] = getc(fp);
67  tmp[1] = getc(fp);
68  tmp[2] = getc(fp);
69  tmp[3] = getc(fp);
70 
71  return FCC(tmp);
72 }
73 
74 unsigned int GET_TCC(FILE *fp)
75 {
76  char tmp[5];
77 
78  tmp[0] = getc(fp);
79  tmp[1] = getc(fp);
80  tmp[2] = 0;
81  tmp[3] = 0;
82 
83  return FCC(tmp);
84 }
85 
86 char *fcc_to_char(unsigned int fcc)
87 {
88  DEBUG_FCC[0] = (fcc)&127;
89  DEBUG_FCC[1] = (fcc >> 8) & 127;
90  DEBUG_FCC[2] = (fcc >> 16) & 127;
91  DEBUG_FCC[3] = (fcc >> 24) & 127;
92 
93  return DEBUG_FCC;
94 }
95 
96 char *tcc_to_char(unsigned int tcc)
97 {
98  DEBUG_FCC[0] = (tcc)&127;
99  DEBUG_FCC[1] = (tcc >> 8) & 127;
100  DEBUG_FCC[2] = 0;
101  DEBUG_FCC[3] = 0;
102 
103  return DEBUG_FCC;
104 }
105 
106 int AVI_get_stream(AviMovie *movie, int avist_type, int stream_num)
107 {
108  int cur_stream;
109 
110  if (movie == NULL) {
111  return -AVI_ERROR_OPTION;
112  }
113 
114  for (cur_stream = 0; cur_stream < movie->header->Streams; cur_stream++) {
115  if (movie->streams[cur_stream].sh.Type == avist_type) {
116  if (stream_num == 0) {
117  return cur_stream;
118  }
119 
120  stream_num--;
121  }
122  }
123 
124  return -AVI_ERROR_FOUND;
125 }
126 
127 static int fcc_get_stream(int fcc)
128 {
129  char fccs[4];
130 
131  fccs[0] = fcc;
132  fccs[1] = fcc >> 8;
133  fccs[2] = fcc >> 16;
134  fccs[3] = fcc >> 24;
135 
136  return 10 * (fccs[0] - '0') + (fccs[1] - '0');
137 }
138 
139 static bool fcc_is_data(int fcc)
140 {
141  char fccs[4];
142 
143  fccs[0] = fcc;
144  fccs[1] = fcc >> 8;
145  fccs[2] = fcc >> 16;
146  fccs[3] = fcc >> 24;
147 
148  if (!isdigit(fccs[0]) || !isdigit(fccs[1]) || (fccs[2] != 'd' && fccs[2] != 'w')) {
149  return 0;
150  }
151  if (!ELEM(fccs[3], 'b', 'c')) {
152  return 0;
153  }
154 
155  return 1;
156 }
157 
159 {
160  int error;
161 
162  if ((int)in_error < 0) {
163  error = -in_error;
164  }
165  else {
166  error = in_error;
167  }
168 
169  switch (error) {
170  case AVI_ERROR_NONE:
171  break;
173  printf("AVI ERROR: compressed in an unsupported format\n");
174  break;
175  case AVI_ERROR_OPEN:
176  printf("AVI ERROR: could not open file\n");
177  break;
178  case AVI_ERROR_READING:
179  printf("AVI ERROR: could not read from file\n");
180  break;
181  case AVI_ERROR_WRITING:
182  printf("AVI ERROR: could not write to file\n");
183  break;
184  case AVI_ERROR_FORMAT:
185  printf("AVI ERROR: file is in an illegal or unrecognized format\n");
186  break;
187  case AVI_ERROR_ALLOC:
188  printf("AVI ERROR: error encountered while allocating memory\n");
189  break;
190  case AVI_ERROR_OPTION:
191  printf("AVI ERROR: program made illegal request\n");
192  break;
193  case AVI_ERROR_FOUND:
194  printf("AVI ERROR: movie did not contain expected item\n");
195  break;
196  default:
197  break;
198  }
199 
200  return in_error;
201 }
202 
203 bool AVI_is_avi(const char *name)
204 {
205  int temp, fcca, j;
206  AviMovie movie = {NULL};
207  AviMainHeader header;
208  AviBitmapInfoHeader bheader;
209  int movie_tracks = 0;
210 
211  DEBUG_PRINT("opening movie\n");
212 
213  movie.type = AVI_MOVIE_READ;
214  movie.fp = BLI_fopen(name, "rb");
215  movie.offset_table = NULL;
216 
217  if (movie.fp == NULL) {
218  return 0;
219  }
220 
221  if (GET_FCC(movie.fp) != FCC("RIFF") || !(movie.size = GET_FCC(movie.fp))) {
222  fclose(movie.fp);
223  return 0;
224  }
225 
226  movie.header = &header;
227 
228  if (GET_FCC(movie.fp) != FCC("AVI ") || GET_FCC(movie.fp) != FCC("LIST") || !GET_FCC(movie.fp) ||
229  GET_FCC(movie.fp) != FCC("hdrl") || (movie.header->fcc = GET_FCC(movie.fp)) != FCC("avih") ||
230  !(movie.header->size = GET_FCC(movie.fp))) {
231  DEBUG_PRINT("bad initial header info\n");
232  fclose(movie.fp);
233  return 0;
234  }
235 
236  movie.header->MicroSecPerFrame = GET_FCC(movie.fp);
237  movie.header->MaxBytesPerSec = GET_FCC(movie.fp);
238  movie.header->PaddingGranularity = GET_FCC(movie.fp);
239  movie.header->Flags = GET_FCC(movie.fp);
240  movie.header->TotalFrames = GET_FCC(movie.fp);
241  movie.header->InitialFrames = GET_FCC(movie.fp);
242  movie.header->Streams = GET_FCC(movie.fp);
243  movie.header->SuggestedBufferSize = GET_FCC(movie.fp);
244  movie.header->Width = GET_FCC(movie.fp);
245  movie.header->Height = GET_FCC(movie.fp);
246  movie.header->Reserved[0] = GET_FCC(movie.fp);
247  movie.header->Reserved[1] = GET_FCC(movie.fp);
248  movie.header->Reserved[2] = GET_FCC(movie.fp);
249  movie.header->Reserved[3] = GET_FCC(movie.fp);
250 
251  BLI_fseek(movie.fp, movie.header->size - 14 * 4, SEEK_CUR);
252 
253  /* Limit number of streams to some reasonable amount to prevent
254  * buffer overflow vulnerabilities. */
255  if (movie.header->Streams < 1 || movie.header->Streams > 65536) {
256  DEBUG_PRINT("Number of streams should be in range 1-65536\n");
257  fclose(movie.fp);
258  return 0;
259  }
260 
262  movie.header->Streams, sizeof(AviStreamRec), "moviestreams");
263 
264  for (temp = 0; temp < movie.header->Streams; temp++) {
265 
266  if (GET_FCC(movie.fp) != FCC("LIST") || !GET_FCC(movie.fp) ||
267  GET_FCC(movie.fp) != FCC("strl") ||
268  (movie.streams[temp].sh.fcc = GET_FCC(movie.fp)) != FCC("strh") ||
269  !(movie.streams[temp].sh.size = GET_FCC(movie.fp))) {
270  DEBUG_PRINT("bad stream header information\n");
271 
272  MEM_freeN(movie.streams);
273  fclose(movie.fp);
274  return 0;
275  }
276 
277  movie.streams[temp].sh.Type = GET_FCC(movie.fp);
278  movie.streams[temp].sh.Handler = GET_FCC(movie.fp);
279 
280  fcca = movie.streams[temp].sh.Handler;
281 
282  if (movie.streams[temp].sh.Type == FCC("vids")) {
283  if (fcca == FCC("DIB ") || fcca == FCC("RGB ") || fcca == FCC("rgb ") ||
284  fcca == FCC("RAW ") || fcca == 0) {
285  movie.streams[temp].format = AVI_FORMAT_AVI_RGB;
286  }
287  else if (fcca == FCC("mjpg") || fcca == FCC("MJPG")) {
288  movie.streams[temp].format = AVI_FORMAT_MJPEG;
289  }
290  else {
291  MEM_freeN(movie.streams);
292  fclose(movie.fp);
293  return 0;
294  }
295  movie_tracks++;
296  }
297 
298  movie.streams[temp].sh.Flags = GET_FCC(movie.fp);
299  movie.streams[temp].sh.Priority = GET_TCC(movie.fp);
300  movie.streams[temp].sh.Language = GET_TCC(movie.fp);
301  movie.streams[temp].sh.InitialFrames = GET_FCC(movie.fp);
302  movie.streams[temp].sh.Scale = GET_FCC(movie.fp);
303  movie.streams[temp].sh.Rate = GET_FCC(movie.fp);
304  movie.streams[temp].sh.Start = GET_FCC(movie.fp);
305  movie.streams[temp].sh.Length = GET_FCC(movie.fp);
306  movie.streams[temp].sh.SuggestedBufferSize = GET_FCC(movie.fp);
307  movie.streams[temp].sh.Quality = GET_FCC(movie.fp);
308  movie.streams[temp].sh.SampleSize = GET_FCC(movie.fp);
309  movie.streams[temp].sh.left = GET_TCC(movie.fp);
310  movie.streams[temp].sh.top = GET_TCC(movie.fp);
311  movie.streams[temp].sh.right = GET_TCC(movie.fp);
312  movie.streams[temp].sh.bottom = GET_TCC(movie.fp);
313 
314  BLI_fseek(movie.fp, movie.streams[temp].sh.size - 14 * 4, SEEK_CUR);
315 
316  if (GET_FCC(movie.fp) != FCC("strf")) {
317  DEBUG_PRINT("no stream format information\n");
318  MEM_freeN(movie.streams);
319  fclose(movie.fp);
320  return 0;
321  }
322 
323  movie.streams[temp].sf_size = GET_FCC(movie.fp);
324  if (movie.streams[temp].sh.Type == FCC("vids")) {
325  j = movie.streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8);
326  if (j >= 0) {
328 
329  movie.streams[temp].sf = &bheader;
330  bi = (AviBitmapInfoHeader *)movie.streams[temp].sf;
331 
332  bi->fcc = FCC("strf");
333  bi->size = movie.streams[temp].sf_size;
334  bi->Size = GET_FCC(movie.fp);
335  bi->Width = GET_FCC(movie.fp);
336  bi->Height = GET_FCC(movie.fp);
337  bi->Planes = GET_TCC(movie.fp);
338  bi->BitCount = GET_TCC(movie.fp);
339  bi->Compression = GET_FCC(movie.fp);
340  bi->SizeImage = GET_FCC(movie.fp);
341  bi->XPelsPerMeter = GET_FCC(movie.fp);
342  bi->YPelsPerMeter = GET_FCC(movie.fp);
343  bi->ClrUsed = GET_FCC(movie.fp);
344  bi->ClrImportant = GET_FCC(movie.fp);
345 
346  fcca = bi->Compression;
347 
348  if (movie.streams[temp].format == AVI_FORMAT_AVI_RGB) {
349  if (fcca == FCC("DIB ") || fcca == FCC("RGB ") || fcca == FCC("rgb ") ||
350  fcca == FCC("RAW ") || fcca == 0) {
351  /* pass */
352  }
353  else if (fcca == FCC("mjpg") || fcca == FCC("MJPG")) {
354  movie.streams[temp].format = AVI_FORMAT_MJPEG;
355  }
356  else {
357  MEM_freeN(movie.streams);
358  fclose(movie.fp);
359  return 0;
360  }
361  }
362  }
363  if (j > 0) {
364  BLI_fseek(movie.fp, j, SEEK_CUR);
365  }
366  }
367  else {
368  BLI_fseek(movie.fp, movie.streams[temp].sf_size, SEEK_CUR);
369  }
370 
371  /* Walk to the next LIST */
372  while (GET_FCC(movie.fp) != FCC("LIST")) {
373  temp = GET_FCC(movie.fp);
374  if (temp < 0 || BLI_ftell(movie.fp) > movie.size) {
375  DEBUG_PRINT("incorrect size in header or error in AVI\n");
376 
377  MEM_freeN(movie.streams);
378  fclose(movie.fp);
379  return 0;
380  }
381  BLI_fseek(movie.fp, temp, SEEK_CUR);
382  }
383 
384  BLI_fseek(movie.fp, -4L, SEEK_CUR);
385  }
386 
387  MEM_freeN(movie.streams);
388  fclose(movie.fp);
389 
390  /* at least one video track is needed */
391  return (movie_tracks != 0);
392 }
393 
394 AviError AVI_open_movie(const char *name, AviMovie *movie)
395 {
396  int temp, fcca, size, j;
397 
398  DEBUG_PRINT("opening movie\n");
399 
400  memset(movie, 0, sizeof(AviMovie));
401 
402  movie->type = AVI_MOVIE_READ;
403  movie->fp = BLI_fopen(name, "rb");
404  movie->offset_table = NULL;
405 
406  if (movie->fp == NULL) {
407  return AVI_ERROR_OPEN;
408  }
409 
410  if (GET_FCC(movie->fp) != FCC("RIFF") || !(movie->size = GET_FCC(movie->fp))) {
411  return AVI_ERROR_FORMAT;
412  }
413 
414  movie->header = (AviMainHeader *)MEM_mallocN(sizeof(AviMainHeader), "movieheader");
415 
416  if (GET_FCC(movie->fp) != FCC("AVI ") || GET_FCC(movie->fp) != FCC("LIST") ||
417  !GET_FCC(movie->fp) || GET_FCC(movie->fp) != FCC("hdrl") ||
418  (movie->header->fcc = GET_FCC(movie->fp)) != FCC("avih") ||
419  !(movie->header->size = GET_FCC(movie->fp))) {
420  DEBUG_PRINT("bad initial header info\n");
421  return AVI_ERROR_FORMAT;
422  }
423 
424  movie->header->MicroSecPerFrame = GET_FCC(movie->fp);
425  movie->header->MaxBytesPerSec = GET_FCC(movie->fp);
426  movie->header->PaddingGranularity = GET_FCC(movie->fp);
427  movie->header->Flags = GET_FCC(movie->fp);
428  movie->header->TotalFrames = GET_FCC(movie->fp);
429  movie->header->InitialFrames = GET_FCC(movie->fp);
430  movie->header->Streams = GET_FCC(movie->fp);
431  movie->header->SuggestedBufferSize = GET_FCC(movie->fp);
432  movie->header->Width = GET_FCC(movie->fp);
433  movie->header->Height = GET_FCC(movie->fp);
434  movie->header->Reserved[0] = GET_FCC(movie->fp);
435  movie->header->Reserved[1] = GET_FCC(movie->fp);
436  movie->header->Reserved[2] = GET_FCC(movie->fp);
437  movie->header->Reserved[3] = GET_FCC(movie->fp);
438 
439  BLI_fseek(movie->fp, movie->header->size - 14 * 4, SEEK_CUR);
440 
441  /* Limit number of streams to some reasonable amount to prevent
442  * buffer overflow vulnerabilities. */
443  if (movie->header->Streams < 1 || movie->header->Streams > 65536) {
444  DEBUG_PRINT("Number of streams should be in range 1-65536\n");
445  return AVI_ERROR_FORMAT;
446  }
447 
449  movie->header->Streams, sizeof(AviStreamRec), "moviestreams");
450 
451  for (temp = 0; temp < movie->header->Streams; temp++) {
452 
453  if (GET_FCC(movie->fp) != FCC("LIST") || !GET_FCC(movie->fp) ||
454  GET_FCC(movie->fp) != FCC("strl") ||
455  (movie->streams[temp].sh.fcc = GET_FCC(movie->fp)) != FCC("strh") ||
456  !(movie->streams[temp].sh.size = GET_FCC(movie->fp))) {
457  DEBUG_PRINT("bad stream header information\n");
458  return AVI_ERROR_FORMAT;
459  }
460 
461  movie->streams[temp].sh.Type = GET_FCC(movie->fp);
462  movie->streams[temp].sh.Handler = GET_FCC(movie->fp);
463 
464  fcca = movie->streams[temp].sh.Handler;
465 
466  if (movie->streams[temp].sh.Type == FCC("vids")) {
467  if (fcca == FCC("DIB ") || fcca == FCC("RGB ") || fcca == FCC("rgb ") ||
468  fcca == FCC("RAW ") || fcca == 0) {
469  movie->streams[temp].format = AVI_FORMAT_AVI_RGB;
470  }
471  else if (fcca == FCC("mjpg") || fcca == FCC("MJPG")) {
472  movie->streams[temp].format = AVI_FORMAT_MJPEG;
473  }
474  else {
475  return AVI_ERROR_COMPRESSION;
476  }
477  }
478 
479  movie->streams[temp].sh.Flags = GET_FCC(movie->fp);
480  movie->streams[temp].sh.Priority = GET_TCC(movie->fp);
481  movie->streams[temp].sh.Language = GET_TCC(movie->fp);
482  movie->streams[temp].sh.InitialFrames = GET_FCC(movie->fp);
483  movie->streams[temp].sh.Scale = GET_FCC(movie->fp);
484  movie->streams[temp].sh.Rate = GET_FCC(movie->fp);
485  movie->streams[temp].sh.Start = GET_FCC(movie->fp);
486  movie->streams[temp].sh.Length = GET_FCC(movie->fp);
487  movie->streams[temp].sh.SuggestedBufferSize = GET_FCC(movie->fp);
488  movie->streams[temp].sh.Quality = GET_FCC(movie->fp);
489  movie->streams[temp].sh.SampleSize = GET_FCC(movie->fp);
490  movie->streams[temp].sh.left = GET_TCC(movie->fp);
491  movie->streams[temp].sh.top = GET_TCC(movie->fp);
492  movie->streams[temp].sh.right = GET_TCC(movie->fp);
493  movie->streams[temp].sh.bottom = GET_TCC(movie->fp);
494 
495  BLI_fseek(movie->fp, movie->streams[temp].sh.size - 14 * 4, SEEK_CUR);
496 
497  if (GET_FCC(movie->fp) != FCC("strf")) {
498  DEBUG_PRINT("no stream format information\n");
499  return AVI_ERROR_FORMAT;
500  }
501 
502  movie->streams[temp].sf_size = GET_FCC(movie->fp);
503  if (movie->streams[temp].sh.Type == FCC("vids")) {
504  j = movie->streams[temp].sf_size - (sizeof(AviBitmapInfoHeader) - 8);
505  if (j >= 0) {
507 
508  movie->streams[temp].sf = MEM_mallocN(sizeof(AviBitmapInfoHeader), "streamformat");
509 
510  bi = (AviBitmapInfoHeader *)movie->streams[temp].sf;
511 
512  bi->fcc = FCC("strf");
513  bi->size = movie->streams[temp].sf_size;
514  bi->Size = GET_FCC(movie->fp);
515  bi->Width = GET_FCC(movie->fp);
516  bi->Height = GET_FCC(movie->fp);
517  bi->Planes = GET_TCC(movie->fp);
518  bi->BitCount = GET_TCC(movie->fp);
519  bi->Compression = GET_FCC(movie->fp);
520  bi->SizeImage = GET_FCC(movie->fp);
521  bi->XPelsPerMeter = GET_FCC(movie->fp);
522  bi->YPelsPerMeter = GET_FCC(movie->fp);
523  bi->ClrUsed = GET_FCC(movie->fp);
524  bi->ClrImportant = GET_FCC(movie->fp);
525 
526  fcca = bi->Compression;
527 
528  if (movie->streams[temp].format == AVI_FORMAT_AVI_RGB) {
529  if (fcca == FCC("DIB ") || fcca == FCC("RGB ") || fcca == FCC("rgb ") ||
530  fcca == FCC("RAW ") || fcca == 0) {
531  /* pass */
532  }
533  else if (fcca == FCC("mjpg") || fcca == FCC("MJPG")) {
534  movie->streams[temp].format = AVI_FORMAT_MJPEG;
535  }
536  else {
537  return AVI_ERROR_COMPRESSION;
538  }
539  }
540  }
541  if (j > 0) {
542  BLI_fseek(movie->fp, j, SEEK_CUR);
543  }
544  }
545  else {
546  BLI_fseek(movie->fp, movie->streams[temp].sf_size, SEEK_CUR);
547  }
548 
549  /* Walk to the next LIST */
550  while (GET_FCC(movie->fp) != FCC("LIST")) {
551  temp = GET_FCC(movie->fp);
552  if (temp < 0 || BLI_ftell(movie->fp) > movie->size) {
553  DEBUG_PRINT("incorrect size in header or error in AVI\n");
554  return AVI_ERROR_FORMAT;
555  }
556  BLI_fseek(movie->fp, temp, SEEK_CUR);
557  }
558 
559  BLI_fseek(movie->fp, -4L, SEEK_CUR);
560  }
561 
562  while (1) {
563  temp = GET_FCC(movie->fp);
564  size = GET_FCC(movie->fp);
565 
566  if (size == 0) {
567  break;
568  }
569 
570  if (temp == FCC("LIST")) {
571  if (GET_FCC(movie->fp) == FCC("movi")) {
572  break;
573  }
574 
575  BLI_fseek(movie->fp, size - 4, SEEK_CUR);
576  }
577  else {
578  BLI_fseek(movie->fp, size, SEEK_CUR);
579  }
580  if (BLI_ftell(movie->fp) > movie->size) {
581  DEBUG_PRINT("incorrect size in header or error in AVI\n");
582  return AVI_ERROR_FORMAT;
583  }
584  }
585 
586  movie->movi_offset = BLI_ftell(movie->fp);
587  movie->read_offset = movie->movi_offset;
588 
589  /* Read in the index if the file has one, otherwise create one */
590  if (movie->header->Flags & AVIF_HASINDEX) {
591  BLI_fseek(movie->fp, size - 4, SEEK_CUR);
592 
593  if (GET_FCC(movie->fp) != FCC("idx1")) {
594  DEBUG_PRINT("bad index informatio\n");
595  return AVI_ERROR_FORMAT;
596  }
597 
598  movie->index_entries = GET_FCC(movie->fp) / sizeof(AviIndexEntry);
599  if (movie->index_entries == 0) {
600  DEBUG_PRINT("no index entries\n");
601  return AVI_ERROR_FORMAT;
602  }
603 
604  movie->entries = (AviIndexEntry *)MEM_mallocN(movie->index_entries * sizeof(AviIndexEntry),
605  "movieentries");
606 
607  for (temp = 0; temp < movie->index_entries; temp++) {
608  movie->entries[temp].ChunkId = GET_FCC(movie->fp);
609  movie->entries[temp].Flags = GET_FCC(movie->fp);
610  movie->entries[temp].Offset = GET_FCC(movie->fp);
611  movie->entries[temp].Size = GET_FCC(movie->fp);
612 
613  if (AVI_DEBUG) {
614  printf("Index entry %04d: ChunkId:%s Flags:%d Offset:%d Size:%d\n",
615  temp,
616  fcc_to_char(movie->entries[temp].ChunkId),
617  movie->entries[temp].Flags,
618  movie->entries[temp].Offset,
619  movie->entries[temp].Size);
620  }
621  }
622 
623  /* Some AVI's have offset entries in absolute coordinates
624  * instead of an offset from the movie beginning... this is...
625  * wacky, but we need to handle it. The wacky offset always
626  * starts at movi_offset it seems... so we'll check that.
627  * Note the offset needs an extra 4 bytes for some
628  * undetermined reason */
629 
630  if (movie->entries[0].Offset == movie->movi_offset) {
631  movie->read_offset = 4;
632  }
633  }
634 
635  DEBUG_PRINT("movie successfully opened\n");
636  return AVI_ERROR_NONE;
637 }
638 
639 void *AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream)
640 {
641  int cur_frame = -1, i = 0, rewind = 1;
642  void *buffer;
643 
644  /* Retrieve the record number of the desired frame in the index
645  * If a chunk has Size 0 we need to rewind to previous frame */
646  while (rewind && frame > -1) {
647  i = 0;
648  cur_frame = -1;
649  rewind = 0;
650 
651  while (cur_frame < frame && i < movie->index_entries) {
652  if (fcc_is_data(movie->entries[i].ChunkId) &&
653  fcc_get_stream(movie->entries[i].ChunkId) == stream) {
654  if ((cur_frame == frame - 1) && (movie->entries[i].Size == 0)) {
655  rewind = 1;
656  frame = frame - 1;
657  }
658  else {
659  cur_frame++;
660  }
661  }
662  i++;
663  }
664  }
665 
666  if (cur_frame != frame) {
667  return NULL;
668  }
669 
670  BLI_fseek(movie->fp, movie->read_offset + movie->entries[i - 1].Offset, SEEK_SET);
671 
672  size_t size = GET_FCC(movie->fp);
673  buffer = MEM_mallocN(size, "readbuffer");
674 
675  if (fread(buffer, 1, size, movie->fp) != size) {
676  MEM_freeN(buffer);
677 
678  return NULL;
679  }
680 
681  buffer = avi_format_convert(movie, stream, buffer, movie->streams[stream].format, format, &size);
682 
683  return buffer;
684 }
685 
687 {
688  int i;
689 
690  fclose(movie->fp);
691 
692  for (i = 0; i < movie->header->Streams; i++) {
693  if (movie->streams[i].sf != NULL) {
694  MEM_freeN(movie->streams[i].sf);
695  }
696  }
697 
698  MEM_freeN(movie->header);
699  MEM_freeN(movie->streams);
700 
701  if (movie->entries != NULL) {
702  MEM_freeN(movie->entries);
703  }
704  if (movie->offset_table != NULL) {
705  MEM_freeN(movie->offset_table);
706  }
707 
708  return AVI_ERROR_NONE;
709 }
710 
711 AviError AVI_open_compress(char *name, AviMovie *movie, int streams, ...)
712 {
713  va_list ap;
714  AviList list;
715  AviChunk chunk;
716  int i;
717  int64_t header_pos1, header_pos2;
718  int64_t stream_pos1, stream_pos2;
719  int64_t junk_pos;
720 
721  movie->type = AVI_MOVIE_WRITE;
722  movie->fp = BLI_fopen(name, "wb");
723 
724  movie->index_entries = 0;
725 
726  if (movie->fp == NULL) {
727  return AVI_ERROR_OPEN;
728  }
729 
730  movie->offset_table = (int64_t *)MEM_mallocN((1 + streams * 2) * sizeof(int64_t), "offsettable");
731 
732  for (i = 0; i < 1 + streams * 2; i++) {
733  movie->offset_table[i] = -1L;
734  }
735 
736  movie->entries = NULL;
737 
738  movie->header = (AviMainHeader *)MEM_mallocN(sizeof(AviMainHeader), "movieheader");
739 
740  movie->header->fcc = FCC("avih");
741  movie->header->size = 56;
742  movie->header->MicroSecPerFrame = 66667;
743  movie->header->MaxBytesPerSec = 0;
744  movie->header->PaddingGranularity = 0;
746  movie->header->TotalFrames = 0;
747  movie->header->InitialFrames = 0;
748  movie->header->Streams = streams;
749  movie->header->SuggestedBufferSize = 0;
750  movie->header->Width = 0;
751  movie->header->Height = 0;
752  movie->header->Reserved[0] = 0;
753  movie->header->Reserved[1] = 0;
754  movie->header->Reserved[2] = 0;
755  movie->header->Reserved[3] = 0;
756 
757  /* Limit number of streams to some reasonable amount to prevent
758  * buffer overflow vulnerabilities. */
759  if (movie->header->Streams < 0 || movie->header->Streams > 65536) {
760  DEBUG_PRINT("Number of streams should be in range 0-65536\n");
761  return AVI_ERROR_FORMAT;
762  }
763 
764  movie->streams = (AviStreamRec *)MEM_mallocN(sizeof(AviStreamRec) * movie->header->Streams,
765  "moviestreams");
766 
767  va_start(ap, streams);
768 
769  for (i = 0; i < movie->header->Streams; i++) {
770  movie->streams[i].format = va_arg(ap, AviFormat);
771 
772  movie->streams[i].sh.fcc = FCC("strh");
773  movie->streams[i].sh.size = 56;
774  movie->streams[i].sh.Type = avi_get_format_type(movie->streams[i].format);
775  if (movie->streams[i].sh.Type == 0) {
776  va_end(ap);
777  return AVI_ERROR_FORMAT;
778  }
779 
780  movie->streams[i].sh.Handler = avi_get_format_fcc(movie->streams[i].format);
781  if (movie->streams[i].sh.Handler == 0) {
782  va_end(ap);
783  return AVI_ERROR_FORMAT;
784  }
785 
786  movie->streams[i].sh.Flags = 0;
787  movie->streams[i].sh.Priority = 0;
788  movie->streams[i].sh.Language = 0;
789  movie->streams[i].sh.InitialFrames = 0;
790  movie->streams[i].sh.Scale = 66667;
791  movie->streams[i].sh.Rate = 1000000;
792  movie->streams[i].sh.Start = 0;
793  movie->streams[i].sh.Length = 0;
794  movie->streams[i].sh.SuggestedBufferSize = 0;
795  movie->streams[i].sh.Quality = 10000;
796  movie->streams[i].sh.SampleSize = 0;
797  movie->streams[i].sh.left = 0;
798  movie->streams[i].sh.top = 0;
799  movie->streams[i].sh.right = 0;
800  movie->streams[i].sh.bottom = 0;
801 
802  if (movie->streams[i].sh.Type == FCC("vids")) {
803  movie->streams[i].sf = MEM_mallocN(sizeof(AviBitmapInfoHeader), "moviestreamformatS");
804  movie->streams[i].sf_size = sizeof(AviBitmapInfoHeader);
805 
806  ((AviBitmapInfoHeader *)movie->streams[i].sf)->fcc = FCC("strf");
807  ((AviBitmapInfoHeader *)movie->streams[i].sf)->size = movie->streams[i].sf_size - 8;
808  ((AviBitmapInfoHeader *)movie->streams[i].sf)->Size = movie->streams[i].sf_size - 8;
809  ((AviBitmapInfoHeader *)movie->streams[i].sf)->Width = 0;
810  ((AviBitmapInfoHeader *)movie->streams[i].sf)->Height = 0;
811  ((AviBitmapInfoHeader *)movie->streams[i].sf)->Planes = 1;
812  ((AviBitmapInfoHeader *)movie->streams[i].sf)->BitCount = 24;
813  ((AviBitmapInfoHeader *)movie->streams[i].sf)->Compression = avi_get_format_compression(
814  movie->streams[i].format);
815  ((AviBitmapInfoHeader *)movie->streams[i].sf)->SizeImage = 0;
816  ((AviBitmapInfoHeader *)movie->streams[i].sf)->XPelsPerMeter = 0;
817  ((AviBitmapInfoHeader *)movie->streams[i].sf)->YPelsPerMeter = 0;
818  ((AviBitmapInfoHeader *)movie->streams[i].sf)->ClrUsed = 0;
819  ((AviBitmapInfoHeader *)movie->streams[i].sf)->ClrImportant = 0;
820  }
821  }
822 
823  list.fcc = FCC("RIFF");
824  list.size = 0;
825  list.ids = FCC("AVI ");
826 
827  awrite(movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
828 
829  list.fcc = FCC("LIST");
830  list.size = 0;
831  list.ids = FCC("hdrl");
832 
833  awrite(movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
834 
835  header_pos1 = BLI_ftell(movie->fp);
836 
837  movie->offset_table[0] = BLI_ftell(movie->fp);
838 
839  awrite(movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
840 
841  for (i = 0; i < movie->header->Streams; i++) {
842  list.fcc = FCC("LIST");
843  list.size = 0;
844  list.ids = FCC("strl");
845 
846  awrite(movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
847 
848  stream_pos1 = BLI_ftell(movie->fp);
849 
850  movie->offset_table[1 + i * 2] = BLI_ftell(movie->fp);
851  awrite(movie, &movie->streams[i].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
852 
853  movie->offset_table[1 + i * 2 + 1] = BLI_ftell(movie->fp);
854  awrite(movie, movie->streams[i].sf, 1, movie->streams[i].sf_size, movie->fp, AVI_BITMAPH);
855 
856  stream_pos2 = BLI_ftell(movie->fp);
857 
858  BLI_fseek(movie->fp, stream_pos1 - 8, SEEK_SET);
859 
860  PUT_FCCN((stream_pos2 - stream_pos1 + 4L), movie->fp);
861 
862  BLI_fseek(movie->fp, stream_pos2, SEEK_SET);
863  }
864 
865  junk_pos = BLI_ftell(movie->fp);
866 
867  if (junk_pos < 2024 - 8) {
868  chunk.fcc = FCC("JUNK");
869  chunk.size = 2024 - 8 - (int)junk_pos;
870 
871  awrite(movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
872 
873  for (i = 0; i < chunk.size; i++) {
874  putc(0, movie->fp);
875  }
876  }
877 
878  header_pos2 = BLI_ftell(movie->fp);
879 
880  list.fcc = FCC("LIST");
881  list.size = 0;
882  list.ids = FCC("movi");
883 
884  awrite(movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
885 
886  movie->movi_offset = BLI_ftell(movie->fp) - 8L;
887 
888  BLI_fseek(movie->fp, AVI_HDRL_SOFF, SEEK_SET);
889 
890  PUT_FCCN((header_pos2 - header_pos1 + 4L), movie->fp);
891 
892  va_end(ap);
893 
894  return AVI_ERROR_NONE;
895 }
896 
897 AviError AVI_write_frame(AviMovie *movie, int frame_num, ...)
898 {
899  AviList list;
900  AviChunk chunk;
901  va_list ap;
902  int stream;
903  int64_t rec_off;
905  void *buffer;
906 
907  if (frame_num < 0) {
908  return AVI_ERROR_OPTION;
909  }
910 
911  /* Allocate the new memory for the index entry */
912 
913  if (frame_num >= movie->index_entries) {
914  const size_t entry_size = (movie->header->Streams + 1) * sizeof(AviIndexEntry);
915  movie->entries = (AviIndexEntry *)MEM_recallocN(movie->entries, (frame_num + 1) * entry_size);
916  movie->index_entries = frame_num + 1;
917  }
918 
919  /* Slap a new record entry onto the end of the file */
920 
921  BLI_fseek(movie->fp, 0L, SEEK_END);
922 
923  list.fcc = FCC("LIST");
924  list.size = 0;
925  list.ids = FCC("rec ");
926 
927  awrite(movie, &list, 1, sizeof(AviList), movie->fp, AVI_LIST);
928 
929  rec_off = BLI_ftell(movie->fp) - 8L;
930 
931  /* Write a frame for every stream */
932 
933  va_start(ap, frame_num);
934 
935  for (stream = 0; stream < movie->header->Streams; stream++) {
936  unsigned int tbuf = 0;
937 
938  format = va_arg(ap, AviFormat);
939  buffer = va_arg(ap, void *);
940  size_t size = va_arg(ap, int);
941 
942  /* Convert the buffer into the output format */
944  movie, stream, buffer, format, movie->streams[stream].format, &size);
945 
946  /* Write the header info for this data chunk */
947 
948  BLI_fseek(movie->fp, 0L, SEEK_END);
949 
950  chunk.fcc = avi_get_data_id(format, stream);
951  chunk.size = size;
952 
953  if (size % 4) {
954  chunk.size += 4 - size % 4;
955  }
956 
957  awrite(movie, &chunk, 1, sizeof(AviChunk), movie->fp, AVI_CHUNK);
958 
959  /* Write the index entry for this data chunk */
960 
961  movie->entries[frame_num * (movie->header->Streams + 1) + stream + 1].ChunkId = chunk.fcc;
962  movie->entries[frame_num * (movie->header->Streams + 1) + stream + 1].Flags = AVIIF_KEYFRAME;
963  movie->entries[frame_num * (movie->header->Streams + 1) + stream + 1].Offset =
964  (int)(BLI_ftell(movie->fp) - 12L - movie->movi_offset);
965  movie->entries[frame_num * (movie->header->Streams + 1) + stream + 1].Size = chunk.size;
966 
967  /* Write the chunk */
968  awrite(movie, buffer, 1, size, movie->fp, AVI_RAW);
969  MEM_freeN(buffer);
970 
971  if (size % 4) {
972  awrite(movie, &tbuf, 1, 4 - size % 4, movie->fp, AVI_RAW);
973  }
974 
975  /* Update the stream headers length field */
976  movie->streams[stream].sh.Length++;
977  BLI_fseek(movie->fp, movie->offset_table[1 + stream * 2], SEEK_SET);
978  awrite(movie, &movie->streams[stream].sh, 1, sizeof(AviStreamHeader), movie->fp, AVI_STREAMH);
979  }
980  va_end(ap);
981 
982  /* Record the entry for the new record */
983 
984  BLI_fseek(movie->fp, 0L, SEEK_END);
985 
986  movie->entries[frame_num * (movie->header->Streams + 1)].ChunkId = FCC("rec ");
987  movie->entries[frame_num * (movie->header->Streams + 1)].Flags = AVIIF_LIST;
988  movie->entries[frame_num * (movie->header->Streams + 1)].Offset = (int)(rec_off - 8L -
989  movie->movi_offset);
990  movie->entries[frame_num * (movie->header->Streams + 1)].Size = (int)(BLI_ftell(movie->fp) -
991  (rec_off + 4L));
992 
993  /* Update the record size */
994  BLI_fseek(movie->fp, rec_off, SEEK_SET);
995  PUT_FCCN(movie->entries[frame_num * (movie->header->Streams + 1)].Size, movie->fp);
996 
997  /* Update the main header information in the file */
998  movie->header->TotalFrames++;
999  BLI_fseek(movie->fp, movie->offset_table[0], SEEK_SET);
1000  awrite(movie, movie->header, 1, sizeof(AviMainHeader), movie->fp, AVI_MAINH);
1001 
1002  return AVI_ERROR_NONE;
1003 }
1004 
1006 {
1007  int temp, movi_size, i;
1008 
1009  if (movie->fp == NULL) {
1010  /* none of the allocations below were done if the file failed to open */
1011  return AVI_ERROR_FOUND;
1012  }
1013 
1014  BLI_fseek(movie->fp, 0L, SEEK_END);
1015  movi_size = (int)BLI_ftell(movie->fp);
1016 
1017  PUT_FCC("idx1", movie->fp);
1018  PUT_FCCN((movie->index_entries * (movie->header->Streams + 1) * 16), movie->fp);
1019 
1020  for (temp = 0; temp < movie->index_entries * (movie->header->Streams + 1); temp++) {
1021  awrite(movie, &movie->entries[temp], 1, sizeof(AviIndexEntry), movie->fp, AVI_INDEXE);
1022  }
1023 
1024  temp = (int)BLI_ftell(movie->fp);
1025 
1026  BLI_fseek(movie->fp, AVI_RIFF_SOFF, SEEK_SET);
1027 
1028  PUT_FCCN((temp - 8L), movie->fp);
1029 
1030  BLI_fseek(movie->fp, movie->movi_offset, SEEK_SET);
1031 
1032  PUT_FCCN((movi_size - (movie->movi_offset + 4L)), movie->fp);
1033 
1034  fclose(movie->fp);
1035 
1036  for (i = 0; i < movie->header->Streams; i++) {
1037  if (movie->streams && (movie->streams[i].sf != NULL)) {
1038  MEM_freeN(movie->streams[i].sf);
1039  }
1040  }
1041 
1042  MEM_freeN(movie->header);
1043 
1044  if (movie->entries != NULL) {
1045  MEM_freeN(movie->entries);
1046  }
1047  if (movie->streams != NULL) {
1048  MEM_freeN(movie->streams);
1049  }
1050  if (movie->offset_table != NULL) {
1051  MEM_freeN(movie->offset_table);
1052  }
1053  return AVI_ERROR_NONE;
1054 }
struct _AviBitmapInfoHeader AviBitmapInfoHeader
#define AVIIF_KEYFRAME
Definition: AVI_avi.h:147
#define FCC(ch4)
Definition: AVI_avi.h:231
AviError
Definition: AVI_avi.h:201
@ AVI_ERROR_ALLOC
Definition: AVI_avi.h:208
@ AVI_ERROR_FOUND
Definition: AVI_avi.h:209
@ AVI_ERROR_READING
Definition: AVI_avi.h:205
@ AVI_ERROR_OPTION
Definition: AVI_avi.h:210
@ AVI_ERROR_FORMAT
Definition: AVI_avi.h:207
@ AVI_ERROR_OPEN
Definition: AVI_avi.h:204
@ AVI_ERROR_NONE
Definition: AVI_avi.h:202
@ AVI_ERROR_COMPRESSION
Definition: AVI_avi.h:203
@ AVI_ERROR_WRITING
Definition: AVI_avi.h:206
#define AVIF_MUSTUSEINDEX
Definition: AVI_avi.h:69
#define AVI_MOVIE_WRITE
Definition: AVI_avi.h:183
#define AVIF_HASINDEX
Definition: AVI_avi.h:67
#define AVIIF_LIST
Definition: AVI_avi.h:146
#define AVI_MOVIE_READ
Definition: AVI_avi.h:182
#define AVI_RIFF_SOFF
Definition: AVI_avi.h:225
#define AVI_HDRL_SOFF
Definition: AVI_avi.h:226
AviFormat
Definition: AVI_avi.h:160
@ AVI_FORMAT_AVI_RGB
Definition: AVI_avi.h:166
@ AVI_FORMAT_MJPEG
Definition: AVI_avi.h:168
struct _AviIndexEntry AviIndexEntry
File and directory operations.
int64_t BLI_ftell(FILE *stream) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: storage.c:177
int BLI_fseek(FILE *stream, int64_t offset, int whence)
Definition: storage.c:186
FILE * BLI_fopen(const char *filename, const char *mode) ATTR_WARN_UNUSED_RESULT ATTR_NONNULL()
Definition: fileops.c:1003
#define ELEM(...)
Compatibility-like things for windows.
Read Guarded memory(de)allocation.
#define MEM_recallocN(vmemh, len)
unsigned int GET_FCC(FILE *fp)
Definition: avi.c:62
char * fcc_to_char(unsigned int fcc)
Definition: avi.c:86
AviError AVI_close(AviMovie *movie)
Definition: avi.c:686
AviError AVI_open_compress(char *name, AviMovie *movie, int streams,...)
Definition: avi.c:711
char * tcc_to_char(unsigned int tcc)
Definition: avi.c:96
AviError AVI_close_compress(AviMovie *movie)
Definition: avi.c:1005
static int fcc_get_stream(int fcc)
Definition: avi.c:127
static bool fcc_is_data(int fcc)
Definition: avi.c:139
bool AVI_is_avi(const char *name)
Definition: avi.c:203
void * AVI_read_frame(AviMovie *movie, AviFormat format, int frame, int stream)
Definition: avi.c:639
static int AVI_DEBUG
Definition: avi.c:47
unsigned int GET_TCC(FILE *fp)
Definition: avi.c:74
AviError AVI_print_error(AviError in_error)
Definition: avi.c:158
AviError AVI_write_frame(AviMovie *movie, int frame_num,...)
Definition: avi.c:897
int AVI_get_stream(AviMovie *movie, int avist_type, int stream_num)
Definition: avi.c:106
AviError AVI_open_movie(const char *name, AviMovie *movie)
Definition: avi.c:394
static char DEBUG_FCC[4]
Definition: avi.c:48
#define DEBUG_PRINT(x)
Definition: avi.c:50
int avi_get_format_type(AviFormat format)
Definition: avi_codecs.c:99
int avi_get_format_compression(AviFormat format)
Definition: avi_codecs.c:126
int avi_get_data_id(AviFormat format, int stream)
Definition: avi_codecs.c:82
void * avi_format_convert(AviMovie *movie, int stream, void *buffer, AviFormat from, AviFormat to, size_t *size)
Definition: avi_codecs.c:33
int avi_get_format_fcc(AviFormat format)
Definition: avi_codecs.c:112
void awrite(AviMovie *movie, void *datain, int block, int size, FILE *fp, int type)
Definition: avi_endian.c:149
#define AVI_RAW
Definition: avi_endian.h:28
#define AVI_LIST
Definition: avi_endian.h:30
#define AVI_STREAMH
Definition: avi_endian.h:32
#define AVI_INDEXE
Definition: avi_endian.h:34
#define AVI_MAINH
Definition: avi_endian.h:31
#define AVI_CHUNK
Definition: avi_endian.h:29
#define AVI_BITMAPH
Definition: avi_endian.h:33
#define PUT_FCCN(num, fp)
Definition: avi_intern.h:40
#define PUT_FCC(ch4, fp)
Definition: avi_intern.h:31
static DBVT_INLINE btScalar size(const btDbvtVolume &a)
Definition: btDbvt.cpp:52
__kernel void ccl_constant KernelData ccl_global void ccl_global char ccl_global int ccl_global char ccl_global unsigned int ccl_global float * buffer
format
Definition: logImageCore.h:47
void(* MEM_freeN)(void *vmemh)
Definition: mallocn.c:41
void *(* MEM_calloc_arrayN)(size_t len, size_t size, const char *str)
Definition: mallocn.c:46
void *(* MEM_mallocN)(size_t len, const char *str)
Definition: mallocn.c:47
#define L
static void error(const char *str)
Definition: meshlaplacian.c:65
__int64 int64_t
Definition: stdint.h:92
Definition: msgfmt.c:181
int size
Definition: AVI_avi.h:49
int fcc
Definition: AVI_avi.h:48
int ids
Definition: AVI_avi.h:55
int size
Definition: AVI_avi.h:54
int fcc
Definition: AVI_avi.h:53
int Reserved[4]
Definition: AVI_avi.h:84
int MicroSecPerFrame
Definition: AVI_avi.h:61
int MaxBytesPerSec
Definition: AVI_avi.h:62
int InitialFrames
Definition: AVI_avi.h:79
int SuggestedBufferSize
Definition: AVI_avi.h:81
int TotalFrames
Definition: AVI_avi.h:78
int PaddingGranularity
Definition: AVI_avi.h:63
int64_t read_offset
Definition: AVI_avi.h:193
int64_t * offset_table
Definition: AVI_avi.h:194
int type
Definition: AVI_avi.h:181
int64_t size
Definition: AVI_avi.h:185
int64_t movi_offset
Definition: AVI_avi.h:192
FILE * fp
Definition: AVI_avi.h:179
int index_entries
Definition: AVI_avi.h:190
AviMainHeader * header
Definition: AVI_avi.h:187
AviStreamRec * streams
Definition: AVI_avi.h:188
AviIndexEntry * entries
Definition: AVI_avi.h:189
int SuggestedBufferSize
Definition: AVI_avi.h:108
short Priority
Definition: AVI_avi.h:101
short Language
Definition: AVI_avi.h:102
AviFormat format
Definition: AVI_avi.h:175
AviStreamHeader sh
Definition: AVI_avi.h:172
void * sf
Definition: AVI_avi.h:173