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